Django 3.0 release notes

2 de diciembre de 2019

Bienvenido a Django 3.0!

Estas notas de lanzamiento cubren las nuevas características, así como algunos cambios que no son compatibles con la versión anterior que debes tener en cuenta al actualizar desde Django 2.2 o una versión anterior. Hemos eliminado algunas características que han llegado a su fin de ciclo de deprecación, y hemos comenzado el proceso de deprecación para algunas características <deprecated-features-3.0>.

Consulte la guía Cómo actualizar Django a una versión más reciente si estás actualizando un proyecto existente.

Compatibilidad con Python

Django 3.0 admite Python 3.6, 3.7, 3.8 y 3.9 (a partir de 3.0.11). Muy recomendamos y solo oficialmente apoyamos la última versión de cada serie.

La serie Django 2.2.x es la última que admite Python 3.5.

Soporte de bibliotecas de terceros para versiones antiguas de Django

Después del lanzamiento de Django 3.0, sugerimos a los autores de aplicaciones terceras que abandonen el soporte para todas las versiones de Django anteriores a 2.2. En ese momento, deberías poder ejecutar las pruebas de tu paquete utilizando python -Wd para que las advertencias de deprecación aparezcan. Después de hacer los ajustes de advertencia de deprecación, tu aplicación debe ser compatible con Django 3.0.

What’s new in Django 3.0

Soporte de MariaDB

Django ahora oficialmente admite MariaDB 10.1 y superior. Consulte Notas de MariaDB para obtener más detalles.

Soporte ASGI

Django 3.0 comienza nuestro viaje a hacer que Django sea completamente capaz de ejecutarse de manera asíncrona proporcionando soporte para ejecutar como una aplicación ASGI.

Esto se suma al soporte WSGI existente. Django tiene la intención de admitir ambos en el futuro previsible. Las características asíncronas solo estarán disponibles para aplicaciones que ejecuten bajo ASGI, sin embargo.

En este momento, el soporte asíncrono solo se aplica a la aplicación ASGI externa. Internamente todo sigue siendo sincrónico. El middleware asíncrono, vistas, etc., no están aún admitidos. Sin embargo, puedes utilizar middleware ASGI alrededor de la aplicación de Django, lo que te permite combinar Django con otros frameworks ASGI.

No hay necesidad de cambiar tus aplicaciones a menos que quieras empezar a experimentar con código asíncrono, pero tenemos documentación sobre la depuración con ASGI si quieres aprender más.

Ten en cuenta que como efecto secundario de esta modificación, Django ahora está consciente de los bucles de eventos asíncronos y bloqueará tu código marcado como «inseguro para llamadas asíncronas» - como operaciones ORM - desde un contexto asíncrono. Si estabas utilizando Django desde código asíncrono antes, esto puede desencadenar si lo hacías incorrectamente. Si ves un error SynchronousOnlyOperation, entonces examina de cerca tu código y mueve cualquier operación de base de datos a una subhilo sincrónica.

Restricciones de exclusión en PostgreSQL

La traducción de los textos es la siguiente:

Expresiones de filtro

Las expresiones que devuelven ~django.db.models.BooleanField pueden utilizarse directamente en filtros de QuerySet, sin tener que anotar y luego filtrar contra la anotación.

Enumeraciones para opciones de campos de modelo

Los tipos personalizados de enumeración TextChoices, IntegerChoices y Choices están disponibles como una forma de definir Field.opciones. Los tipos TextChoices y IntegerChoices se proporcionan para campos de texto e integer. La clase Choices permite definir una enumeración compatible con otros tipos de datos concretos. Estos tipos personalizados de enumeración admiten etiquetas legibles por humanos que pueden ser traducidas y accedidas a través de una propiedad en la enumeración o sus miembros. Consulte Tipos de enumeración para obtener más detalles y ejemplos.

Características menores

django.contrib.admin

  • Se ha agregado soporte para la atributo admin_order_field en propiedades en ModelAdmin.list_display.

  • La nueva método ModelAdmin.get_inlines() <django.contrib.admin.ModelAdmin.get_inlines> permite especificar las líneas basadas en la solicitud o instancia de modelo.

  • La biblioteca Select2 se ha actualizado desde la versión 4.0.3 a 4.0.7.

  • jQuery se ha actualizado desde la versión 3.3.1 a 3.4.1.

django.contrib.auth

  • El nuevo atributo reset_url_token en PasswordResetConfirmView permite especificar un parámetro de token que se muestra como componente de las URLs de restablecimiento de contraseña.

  • Se han agregado la clase BaseBackend para facilitar la personalización de los backends de autenticación.

  • Se ha agregado el método get_user_permissions() para reflejar el método existente get_group_permissions().

  • Se ha agregado la atributo autocomplete HTML a los widgets de campos de usuario, correo electrónico y contraseña en django.contrib.auth.forms para una mejor interacción con los administradores de contraseñas del navegador.

  • El comando createsuperuser ahora utiliza las variables de entorno para la contraseña y los campos requeridos cuando no se proporciona el argumento correspondiente en modo no interactivo.

  • La propiedad REQUIRED_FIELDS ahora admite relaciones muchos a muchos con ManyToManyField.

  • El nuevo método UserManager.with_perm() devuelve los usuarios que tienen la permiso especificado.

  • Se ha aumentado el recuento de iteraciones por defecto para el algoritmo de hash de contraseña PBKDF2 de 150,000 a 180,000.

django.contrib.gis

  • Se han permitido las funciones de búsqueda espacial MySQL para operar con geometrías reales. El soporte anterior estaba limitado a cajas de enfoque.

  • Se ha agregado la función GeometryDistance, que está disponible en PostGIS.

  • Se ha agregado el soporte para la unidad furlong en Distance.

  • La traducción de los textos es la siguiente:

  • La clase GeoIP2 ahora acepta pathlib.Path path.

django.contrib.postgres

django.contrib.sesiones

django.contrib.syndication

Cache

Almacenamiento de archivos

  • El nuevo método Storage.get_alternative_name() permite personalizar el algoritmo para generar nombres de archivo si ya existe un archivo con el nombre subido original.

Formularios

Internacionalización

Registro de eventos

  • El nuevo parámetro reporter_class de AdminEmailHandler permite proporcionar una subclase de django.views.debug.ExceptionReporter para personalizar el texto del seguimiento enviado al sitio ADMINS cuando DEBUG es False.

Comandos de Gestión

  • La nueva opción compilemessages --ignore permite ignorar directorios específicos al buscar archivos .po para compilar.

  • showmigrations --list ahora muestra las fechas de aplicación cuando --verbosity es 2 y superior.

  • En PostgreSQL, dbshell ahora admite certificados TLS del lado del cliente.

  • inspectdb ahora introspecta OneToOneField cuando una clave foránea tiene una restricción de clave única o primaria.

  • La nueva opción --skip-checks omite la ejecución de comprobaciones del sistema antes de ejecutar el comando.

  • Las opciones startapp --template y startproject --template ahora admiten plantillas almacenadas en archivos XZ (.tar.xz, .txz) y LZMA (.tar.lzma, .tlz).

Modelos

  • Se han agregado funciones de base de datos hash: MD5, SHA1, SHA224, SHA256, SHA384 y SHA512.

  • Se han agregado la función de base de datos Sign.

  • La nueva parámetro is_dst del las funciones de base de datos Trunc determina el tratamiento de los datetimes inexistentes y ambiguos.

  • connection.queries ahora muestra las sentencias COPY TO en PostgreSQL.

  • FilePathField ahora acepta una función llamable para path.

  • Se ha permitido la tabla intermedia simétrica para las relaciones de muchos a muchos ManyToManyField.

  • Los atributos name de CheckConstraint, UniqueConstraint y Index ahora admiten la interpolación del etiqueta de aplicación y clase utilizando los lugares de sustitución '%(app_label)s' y '%(class)s'.

  • La nueva atributo Field.descriptor_class permite a los campos de modelo personalizar el comportamiento get y set sobreescribiendo sus descriptores.

  • Avg y Sum ahora admiten la argumento distinct.

  • Se ha agregado SmallAutoField, que actúa mucho como un AutoField excepto que solo permite valores bajo cierto (dependiente de la base de datos) límite. Los valores desde 1 a 32767 son seguros en todas las bases de datos admitidas por Django.

  • AutoField, BigAutoField y SmallAutoField ahora heredan de IntegerField, BigIntegerField y SmallIntegerField respectivamente. Los controles de sistema y validadores se heredan también correctamente.

  • FileField.upload_to ahora admite pathlib.Path.

  • CheckConstraint está ahora soportado en MySQL 8.0.16+.

  • La nueva allows_group_by_selected_pks_on_model() método de django.db.backends.base.BaseDatabaseFeatures permite la optimización de las cláusulas GROUP BY para que requieran solo los clave primarias seleccionadas de los modelos. Por defecto, está soportado sólo para modelos administrados en PostgreSQL.

    Para habilitar la optimización de cláusulas GROUP BY con clave primaria única para modelos no administrados, debes heredar la base del motor de bases de datos PostgreSQL, sobrescribiendo la clase de características allows_group_by_selected_pks_on_model() como requieras. Consulta Herencia de los motores de bases de datos integrados para un ejemplo.

Solicitudes y respuestas

  • Se permite a HttpResponse ser inicializado con contenido de memoryview.

  • Para su uso en, por ejemplo, plantillas Django, HttpRequest.headers ahora admite consultas utilizando guiones bajos (por ejemplo user_agent) en lugar de guiones.

Seguridad

Pruebas

  • El nuevo argumento de prueba Client raise_request_exception permite controlar si las excepciones levantadas durante la solicitud también deben ser levantadas en la prueba. El valor predeterminado es True para compatibilidad hacia atrás. Si es False y ocurre una excepción, el cliente de pruebas devolverá una respuesta 500 con el atributo exc_info, un tupla que proporciona información sobre la excepción que ocurrió.

  • Pruebas y casos de prueba para ejecutar pueden ser seleccionadas por patrón de nombre de prueba utilizando la nueva opción test -k.

  • Comparación de HTML, tal como se utiliza en assertHTMLEqual(), ahora considera que el texto, las referencias a caracteres y las referencias a entidades que se refieren al mismo carácter son equivalentes.

  • DiscoverRunner puede generar ahora un depurador en cada error o falla utilizando la opción test --pdb.

Cambios no compatibles hacia atrás en 3.0

Model.save() cuando se proporciona un valor por defecto para la clave primaria

Model.save() ya no intenta encontrar una fila cuando se guarda una instancia nueva de Model y se proporciona un valor por defecto para la clave primaria, y siempre realiza una consulta INSERT única. En versiones antiguas de Django, Model.save() realizaba una consulta INSERT o UPDATE según si existía la fila.

Llama a Model.save() mientras se proporciona un valor de clave primaria por defecto equivalente a pasar force_insert=True al método save() del modelo. Los intentos de utilizar una nueva instancia de Model para actualizar una fila existente darán como resultado un error de integridad IntegrityError.

Para actualizar un modelo existente para un valor de clave primaria específico, utilice el método update_or_create() o QuerySet.filter(pk=…).update(…) en su lugar. Por ejemplo:

>>> MyModel.objects.update_or_create(pk=existing_pk, defaults={"name": "new name"})
>>> MyModel.objects.filter(pk=existing_pk).update(name="new name")

Backend de base de datos API

Esta es la traducción de los textos:

  • La segunda argumento de DatabaseIntrospection.get_geometry_type() es ahora la descripción de fila en lugar del nombre de columna.

  • DatabaseIntrospection.get_field_type() puede dejar de devolver tuplas.

  • Si la base de datos puede crear claves foráneas en el mismo statement SQL que agrega un campo, agregue SchemaEditor.sql_create_column_inline_fk con el SQL apropiado; de lo contrario, establezca DatabaseFeatures.can_create_inline_fk = False.

  • DatabaseFeatures.can_return_id_from_insert y can_return_ids_from_bulk_insert se renombran a can_return_columns_from_insert y can_return_rows_from_bulk_insert.

  • Las funciones de la base de datos ahora manejan formatos datetime.timezone cuando se crean utilizando instancias de datetime.timedelta (por ejemplo, timezone(timedelta(hours=5)), que produciría 'UTC+05:00'). Los backends tercerizados deben manejar este formato cuando preparen DateTimeField en datetime_cast_date_sql(), datetime_extract_sql(), etc.

  • Se agregan entradas para AutoField, BigAutoField y SmallAutoField a DatabaseOperations.integer_field_ranges para apoyar los validadores de rango de números enteros en estos tipos de campo. Los backends tercerizados pueden necesitar personalizar las entradas predeterminadas.

  • DatabaseOperations.fetch_returned_insert_id() se reemplaza por fetch_returned_insert_columns(), que devuelve una lista de valores devueltos por el statement INSERT RETURNING, en lugar de un valor único.

  • DatabaseOperations.return_insert_id() se reemplaza por return_insert_columns(), que acepta un argumento fields, que es un iterable de campos a ser devueltos después del insert. Normalmente, esto solo es la clave primaria auto-generada.

django.contrib.admin

  • Los mensajes de cambio en el historial de modelos de Admin ahora prefieren etiquetas de campo más legibles en lugar de nombres de campo.

django.contrib.gis

  • Se elimina el soporte para PostGIS 2.1.

  • Se elimina el soporte para SpatiaLite 4.1 y 4.2.

  • Supporto para GDAL 1.11 y GEOS 3.4 se ha eliminado.

Se ha dejado de apoyar a PostgreSQL 9.4

El soporte upstream para PostgreSQL 9.4 finaliza en diciembre del 2019. Django 3.0 admite PostgreSQL 9.5 y versiones superiores.

Se ha dejado de apoyar a Oracle 12.1

El soporte upstream para Oracle 12.1 finaliza en julio del 2021. Django 2.2 seguirá siendo compatible hasta abril del 2022. Django 3.0 admite oficialmente Oracle 12.2 y 18c.

Se han eliminado las API de compatibilidad privadas con Python 2

Aunque el soporte para Python 2 se eliminó en Django 2.0, algunas APIs privadas no se eliminaron de Django para que las aplicaciones terceras pudieran seguir utilizandolas hasta la finalización del ciclo de vida de Python 2.

Dado que esperamos que las aplicaciones eliminen la compatibilidad con Python 2 cuando agreguen soporte a Django 3.0, estamos eliminando estas API en este momento.

  • django.test.utils.str_prefix() - Las cadenas no tienen prefijos “u” en Python 3.

  • django.test.utils.patch_logger() - Utiliza unittest.TestCase.assertLogs() en su lugar.

  • django.utils.lru_cache.lru_cache() - Alias de functools.lru_cache().

  • django.utils.decorators.available_attrs() - Esta función devuelve functools.WRAPPER_ASSIGNMENTS.

  • django.utils.decorators.ContextDecorator - Alias de contextlib.ContextDecorator.

  • django.utils._os.abspathu() - Alias de os.path.abspath().

  • django.utils._os.upath() y npath() - Estas funciones no hacen nada en Python 3.

  • django.utils.six - Elimina el uso de esta biblioteca vendida o cambia a six.

  • django.utils.encoding.python_2_unicode_compatible() - Alias de six.python_2_unicode_compatible().

  • django.utils.functional.curry() - Utiliza functools.partial() o functools.partialmethod. Consulta 5b1c389603a353625ae1603ba345147356336afb.

  • django.utils.safestring.SafeBytes - No utilizada desde Django 2.0.

Valor por defecto nuevo para la configuración FILE_UPLOAD_PERMISSIONS

Los textos traducidos son:

Ahora FILE_UPLOAD_PERMISSIONS tiene como valor por defecto 0o644 para evitar esta inconsistencia.

Nuevos valores por defecto para configuraciones de seguridad

Para hacer que los proyectos Django sean más seguros por defecto, algunas configuraciones de seguridad tienen ahora valores por defecto más seguros:

Consulte la sección Qué hay de nuevo de seguridad anterior para obtener más detalles sobre estos cambios.

Miscelánea

  • Ahora ContentType.__str__() incluye el etiqueta de aplicación del modelo para desambiguar modelos con el mismo nombre en diferentes aplicaciones.

  • Dado que acceder al idioma en la sesión en lugar de en el cookie está deprecado, LocaleMiddleware ya no busca el idioma del usuario en la sesión y django.contrib.auth.logout() ya no conserva el idioma de la sesión después de cerrar sesión.

  • django.utils.html.escape() ahora utiliza html.escape() para escapar HTML. Esto convierte ' a &#x27; en lugar del código decimal equivalente anterior &#39;.

  • The django-admin test -k option now works as the unittest -k option rather que como un atajo para --keepdb.

  • Se ha eliminado el soporte para pywatchman < 1.2.0.

  • urlencode() ahora codifica los valores iterables tal y como lo hacen cuando doseq=False, en lugar de iterarlos, lo que lo pone en línea con la función estándar urllib.parse.urlencode().

  • El filtro de plantilla intword ahora traduce 1.0 como una frase singular y todos los demás valores numéricos como plurales. Esto puede ser incorrecto para algunos idiomas.

  • Asignar un valor a la propiedad “_id” de un modelo ForeignKey o OneToOneField ahora desactiva el campo correspondiente. Acceder al campo después resultará en una consulta.

  • patch_vary_headers() ahora maneja un asterisco '*' según la especificación RFC 7231 Section 7.1.4, es decir, si una lista de nombres de campos de encabezado contiene un asterisco, entonces el encabezado Vary consistirá en un solo asterisco '*'.

  • En MySQL 8.0.16+, PositiveIntegerField y PositiveSmallIntegerField ahora incluyen una restricción de verificación para prevenir valores negativos en la base de datos.

  • Se ha agregado alias=None a la firma de Expression.get_group_by_cols().

  • RegexPattern, utilizado por re_path(), ya no devuelve argumentos clave con valores None para pasar a la vista para los grupos nombrados opcionales que faltan.

Características deprecadas en 3.0

django.utils.encoding.force_text() y smart_text()

Las alias smart_text() y force_text() (desde Django 2.0) de smart_str() y force_str() están descontinuadas. Ignora esta descontinuación si tu código soporta Python 2, ya que el comportamiento de smart_str() y force_str() es diferente allí.

Miscelánea

  • django.utils.http.urlquote(), urlquote_plus(), urlunquote(), y urlunquote_plus() están descontinuados en favor de las funciones a las que son alias: urllib.parse.quote(), quote_plus(), unquote(), y unquote_plus().

  • django.utils.translation.ugettext(), ugettext_lazy(), ugettext_noop(), ungettext(), y ungettext_lazy() están descontinuados en favor de las funciones a las que son alias: django.utils.translation.gettext(), gettext_lazy(), gettext_noop(), ngettext(), y ngettext_lazy().

  • Para limitar la creación de sesiones y favorecer algunas estrategias de caché, django.views.i18n.set_language() dejará de establecer el idioma del usuario en la sesión en Django 4.0. Desde Django 2.1, el idioma se almacena siempre en el cookie LANGUAGE_COOKIE_NAME.

  • django.utils.text.unescape_entities() está descontinuado en favor de html.unescape(). Ten en cuenta que a diferencia de unescape_entities(), html.unescape() evalúa las cadenas lazy inmediatamente.

  • Para evitar posibles confusiones sobre el alcance efectivo, la utilidad interna privada is_safe_url() se renombró a url_has_allowed_host_and_scheme(). Que una URL tenga un host y esquema permitidos no implica en general que sea «segura». Puede estar aún mal citada, por ejemplo. Asegúrate de utilizar también iri_to_uri() en el componente de ruta de las URLs no confiables.

Características eliminadas en 3.0

Estas características han alcanzado el final de su ciclo de descontinuación y se eliminan en Django 3.0.

Consulta Características obsoletas en 2.0 para obtener detalles sobre estas modificaciones, incluyendo cómo eliminar el uso de estas características.

  • El módulo django.db.backends.postgresql_psycopg2 se ha eliminado.

  • Se ha eliminado la función render_to_response() de django.shortcuts.

  • La configuración DEFAULT_CONTENT_TYPE se ha eliminado.

  • Se ha eliminado el método xreadlines() de HttpRequest.

  • Se ha eliminado el soporte para el argumento context de Field.from_db_value() y Expression.convert_value().

  • Se ha eliminado el argumento field_name de QuerySet.earliest() y latest().

Consulte la sección Características deprecadas en 2.1. para obtener detalles sobre estas modificaciones, incluyendo cómo eliminar el uso de estas características.

  • La función GIS ForceRHR se ha eliminado.

  • Se ha eliminado la función cookie_date() de django.utils.http.

  • Las bibliotecas de etiquetas de plantilla staticfiles y admin_static se han eliminado.

  • django.contrib.staticfiles.templatetags.staticfiles.static() se ha eliminado.