7 de diciembre de 2021
Bienvenido a Django 4.0!
Estas notas de lanzamiento cubren las nuevas características, así como algunas cambios incompatibles con lo anterior que querrás tener en cuenta al actualizar desde Django 3.2 o versiones anteriores. Hemos comenzado el proceso de desactivación para algunas características <deprecated-features-4.0>.
Consulte la guía Cómo actualizar Django a una versión más reciente si estás actualizando un proyecto existente.
Django 4.0 admite Python 3.8, 3.9 y 3.10. Recomendamos y solo oficialmente apoyamos la última versión de cada serie.
La serie Django 3.2.x es la última que admite Python 3.6 y 3.7.
zoneinfo¶La biblioteca estándar de Python zoneinfo es ahora la implementación por defecto de zona horaria en Django.
Esto es el siguiente paso en la migración desde el uso de pytz al uso de zoneinfo. Django 3.2 permitió el uso de zonas horarias no pytz. Django 4.0 hace que zoneinfo sea la implementación por defecto. El soporte para pytz ahora está desactivado y se eliminará en Django 5.0.
zoneinfo es parte de la biblioteca estándar de Python desde Python 3.9. El paquete backports.zoneinfo se instala automáticamente junto con Django si estás utilizando Python 3.8.
La traducción de los textos es la siguiente:
Sin embargo, si estás trabajando con zonas horarias no en UTC y utilizando las API normalize() y localize() de pytz, posiblemente junto con la configuración TIME_ZONE, necesitarás auditar tu código, ya que pytz y zoneinfo no son equivalentes en absoluto.
Para dar tiempo a una auditoria de este tipo, la configuración transicional USE_DEPRECATED_PYTZ permite seguir utilizando pytz durante el ciclo de lanzamiento 4.x. Esta configuración se eliminará en Django 5.0.
Además, el paquete pytz_deprecation_shim, creado por el autor de zoneinfo, puede utilizarse para ayudar con la migración desde pytz. Este paquete proporciona shims para ayudarte a eliminar de manera segura pytz y tiene una guía detallada de migración mostrando cómo moverse a las nuevas API de zoneinfo.
Se recomienda utilizar pytz_deprecation_shim y la configuración transicional USE_DEPRECATED_PYTZ si necesitas un camino de actualización gradual.
El nuevo argumento posicional *expressions de UniqueConstraint() permite crear restricciones únicas funcionales en expresiones y funciones de base de datos. Por ejemplo:
from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import Lower
class MyModel(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Meta:
constraints = [
UniqueConstraint(
Lower("first_name"),
Lower("last_name").desc(),
name="first_last_name_unique",
),
]
Las restricciones únicas funcionales se agregan a los modelos utilizando la opción Meta.constraints.
scrypt¶El nuevo hasher de contraseña scrypt es más seguro y recomendado sobre PBKDF2. Sin embargo, no es el predeterminado ya que requiere OpenSSL 1.1+ y más memoria.
El nuevo back-end de caché django.core.cache.backends.redis.RedisCache proporciona soporte integrado para la caché con Redis. Se requiere 3.0.0 o superior de redis-py. Para obtener más detalles, consulte la documentación sobre la caché con Redis en Django.
: class:Forms <django.forms.Form>, Formsets, y ErrorList se renderizan ahora utilizando el motor de plantillas para mejorar la personalización. Consulte los nuevos métodos render(), get_context(), y template_name para Form y la representación de formularios formset para Formset.
django.contrib.admin¶La plantilla admin/base.html ahora tiene un nuevo bloque header que contiene el encabezado del sitio administrativo.
El método ModelAdmin.get_formset_kwargs() permite personalizar los argumentos de palabra clave pasados al constructor de un conjunto de formularios.
La barra lateral de navegación ahora tiene una herramienta de filtro rápido.
Se agrega la variable de contexto model que contiene la clase del modelo para cada modelo a la AdminSite.each_context() método.
El atributo ModelAdmin.search_help_text permite especificar un texto descriptivo para el cuadro de búsqueda.
El atributo InlineModelAdmin.verbose_name_plural ahora se comporta como la concatenación del atributo InlineModelAdmin.verbose_name + 's'.
Los cambios incluyen:
django.contrib.admindocs¶Ahora admindocs permite configuraciones esotéricas donde ROOT_URLCONF no es una cadena.
La sección del modelo de admindocs ahora muestra propiedades cacheadas.
django.contrib.auth¶El recuento por defecto de iteraciones para el hasheador de contraseña PBKDF2 aumenta de 260,000 a 320,000.
El nuevo atributo LoginView.next_page y el método get_default_redirect_url() permiten personalizar la redirección después del inicio de sesión.
django.contrib.gis¶Se agrega soporte para SpatiaLite 5.
La clase GDALRaster ahora permite crear rasters en cualquier sistema de archivos virtual GDAL.
La nueva clase GISModelAdmin permite personalizar el widget utilizado para GeometryField. Se recomienda en lugar de la clase deprecada GeoModelAdmin y OSMGeoAdmin.
django.contrib.postgres¶El backend PostgreSQL ahora admite conectarse mediante un nombre de servicio. Consulte Configuración de conexiones de PostgreSQL para obtener más detalles.
La nueva operación AddConstraintNotValid permite crear restricciones de verificación en PostgreSQL sin verificar que todas las filas existentes satisfagan la nueva restricción.
La traducción de los textos es la siguiente:
The new
ArraySubquery()
expression allows using subqueries to construct lists of values on
PostgreSQL.
El nuevo trigram_word_similar lookup, y las expresiones TrigramWordDistance() y TrigramWordSimilarity() permiten utilizar la similitud de palabras trigramas.
django.contrib.archivos_estáticos¶ManifestStaticFilesStorage ahora reemplaza las rutas a referencias de mapas de fuentes JavaScript con sus contrapartes hashadas.
El nuevo argumento manifest_storage de ManifestFilesMixin y ManifestStaticFilesStorage permite personalizar el almacenamiento del archivo de manifest.
La nueva API asíncrona para django.core.cache.backends.base.BaseCache comienza el proceso de hacer compatibles con asincronía los backends de caché. Las nuevas métodos asíncronos tienen nombres con prefijo a, por ejemplo aadd(), aget(), aset(), aget_or_set(), o adelete_many().
A partir de ahora, se utilizará el prefijo a para las variantes asíncronas de los métodos en general.
La protección CSRF ahora consulta el encabezado Origin, si está presente. Para facilitar esto, se realizan algunas modificaciones en la configuración CSRF_TRUSTED_ORIGINS.
ModelChoiceField ahora incluye el valor proporcionado en el argumento params de un levantado ValidationError para el mensaje de error invalid_choice. Esto permite mensajes de error personalizados utilizar el reemplazo %(value)s.
BaseFormSet ahora renderiza errores no form con una clase adicional de nonform para ayudar a distinguirlos de los errores específicos del formulario.
BaseFormSet ahora permite personalizar el widget utilizado cuando se eliminan formularios a través de la propiedad can_delete estableciendo la propiedad deletion_widget o sobrescribiendo el método get_deletion_widget().
Se ha agregado soporte y traducciones para el idioma malayo.
DeleteView ahora utiliza FormMixin, lo que te permite proporcionar una clase de formulario Form con un checkbox, por ejemplo, para confirmar la eliminación. Además, esto permite a DeleteView funcionar con django.contrib.messages.views.SuccessMessageMixin.
De acuerdo con FormMixin, la eliminación de objetos para solicitudes POST se maneja en form_valid(). La lógica personalizada de eliminación en los manipuladores delete() debe ser movida a form_valid(), o un método auxiliar compartido, según sea necesario.
El alias del motor de base de datos utilizado en una llamada SQL se pasa ahora como contexto adicional junto con cada mensaje al logger django.db.backends.
La orden administrativa runserver ahora admite la opción --skip-checks.
En PostgreSQL, dbshell ahora admite especificar un archivo de contraseña.
La orden administrativa shell ahora respeta sys.__interactivehook__ al inicio. Esto permite cargar la historia del shell entre sesiones interactivas. Como consecuencia, readline ya no se carga si se ejecuta en modo aislado.
La nueva propiedad BaseCommand.suppressed_base_arguments permite suprimir opciones de comando por defecto no soportadas en la salida de ayuda.
Las nuevas opciones startapp --exclude y startproject --exclude permiten excluir directorios del modelo.
El nuevo método QuerySet.contains(obj) devuelve si el conjunto de consultas contiene el objeto dado. Esto intenta realizar la consulta de la manera más simple y rápida posible.
La nueva argumento precision del función de base de datos Round() permite especificar el número de decimales después de redondear.
El método QuerySet.bulk_create() ahora establece la clave primaria en los objetos cuando se utiliza SQLite 3.35+.
La clase DurationField ahora admite multiplicar y dividir por valores escalares en SQLite.
El método QuerySet.bulk_update() ahora devuelve el número de objetos actualizados.
La nueva atributo Expression.empty_result_set_value permite especificar un valor para devolver cuando la función se utiliza sobre un conjunto de resultados vacío.
El argumento skip_locked de QuerySet.select_for_update() ahora está permitido en MariaDB 10.6+.
Las expresiones Lookup pueden usarse ahora directamente en filtros, agregaciones y anotaciones de QuerySet.
El nuevo argumento default para las agregaciones integradas permite especificar un valor a devolver cuando el conjunto de consultas (o agrupación) contiene ninguna entrada, en lugar de None.
La clase SecurityMiddleware ahora agrega la cabecera Cross-Origin Opener Policy con un valor de 'same-origin' para prevenir que los pop-ups de origen cruzado compartan el mismo contexto de navegación. Puedes evitar que se agregue esta cabecera estableciendo la configuración SECURE_CROSS_ORIGIN_OPENER_POLICY en None.
El nuevo argumento stdout para los señales pre_migrate() y post_migrate() permite redirigir la salida a un objeto similar a un flujo. Se debería preferir sobre sys.stdout y print() cuando se emite una salida detallada para permitir su captura adecuada durante las pruebas.
La nueva plantilla de filtro floatformat ahora permite utilizar la sufija u para deshabilitar la localización forzando su uso.
El nuevo argumento serialized_aliases de django.test.utils.setup_databases() determina qué alias de bases de datos deben tener su estado serializado para permitir el uso de la característica de devolución a un estado serializado <test-case-serialized-rollback>.
La opción test --buffer ahora admite pruebas paralelas.
El nuevo argumento logger a DiscoverRunner permite utilizar un logger de Python para la logística.
La nueva método DiscoverRunner.log() proporciona una forma de enviar mensajes que utiliza el DiscoverRunner.logger, o imprime en la consola si no está configurado.
DiscoverRunner ahora puede ejecutar pruebas en un orden aleatorio utilizando la opción test --shuffle.
La opción test --parallel ahora admite el valor auto para ejecutar un proceso de prueba por cada núcleo del procesador.
El método TestCase.captureOnCommitCallbacks() ahora captura las nuevas llamadas a callbacks mientras se ejecutan los callbacks de transaction.on_commit().
Esta es la traducción de los textos:
DatabaseOperations.year_lookup_bounds_for_date_field() y los métodos year_lookup_bounds_for_datetime_field() ahora aceptan el argumento opcional iso_year para poder soportar límites para años con numeración de semana según ISO-8601.
El segundo argumento de los métodos DatabaseSchemaEditor._unique_sql() y _create_unique_sql() ahora es fields en lugar de columns.
django.contrib.gis¶La traducción es:
Soporte para GDAL 2.0 y GEOS 3.5 se ha eliminado.
Soporte upstream para PostgreSQL 9.6 termina en noviembre de 2021. Django 4.0 admite PostgreSQL 10 y versiones superiores.
También se incrementa la versión mínima soportada de psycopg2 desde 2.5.4 a 2.8.4, ya que psycopg2 2.8.4 es la primera versión en apoyar Python 3.8.
Soporte upstream para Oracle 12.2 termina en marzo de 2022 y para Oracle 18c termina en junio de 2021. Django 3.2 seguirá siendo soportado hasta abril de 2024. Django 4.0 oficialmente admite Oracle 19c.
CSRF_TRUSTED_ORIGINS cambia¶Los valores en la configuración CSRF_TRUSTED_ORIGINS deben incluir el esquema (por ejemplo 'http://' o 'https://') en lugar del hostname.
Además, los valores que comenzaban con un punto, ahora también deben incluir una estrella antes del punto. Por ejemplo, cambia '.example.com' a 'https://*.example.com'.
Un sistema de comprobación detecta cualquier cambio requerido.
Como la protección CSRF ahora consulta el encabezado Origin, es posible que debas establecer CSRF_TRUSTED_ORIGINS, especialmente si permites solicitudes de subdominios estableciendo CSRF_COOKIE_DOMAIN (o SESSION_COOKIE_DOMAIN si CSRF_USE_SESSIONS está habilitado) a un valor que comienza con un punto.
SecurityMiddleware ya no establece el encabezado X-XSS-Protection¶La clase SecurityMiddleware ya no establece el encabezado X-XSS-Protection si la configuración SECURE_BROWSER_XSS_FILTER es True. La configuración se elimina.
La mayoría de los navegadores modernos no honran el encabezado HTTP X-XSS-Protection. Puedes utilizar Content-Security-Policy sin permitir scripts 'unsafe-inline' en lugar de eso.
Si deseas soportar navegadores legados y establecer el encabezado, utiliza esta línea en un middleware personalizado:
response.headers.setdefault("X-XSS-Protection", "1; mode=block")
El deteccionador de migraciones ahora utiliza estados de modelos en lugar de clases de modelo. Además, las operaciones de migración para los campos ForeignKey y ManyToManyField ya no especifican atributos que no se pasaron a los campos durante su inicialización.
Como efecto secundario, ejecutar makemigrations puede generar operaciones AlterField vacías para los campos ManyToManyField y ForeignKey en algunos casos.
La clase DeleteView ahora utiliza FormMixin para manejar solicitudes POST. Como consecuencia, cualquier lógica personalizada de eliminación en los manejadores delete() debe ser movida a form_valid(), o un método auxiliar compartido, si es necesario.
Django 4.0 cambió accidentalmente la convención de nombres de tabla y columna en Oracle. Esto causa errores para modelos y campos con nombres más largos que 30 caracteres. Desafortunadamente, es necesario renombrar algunas tablas y columnas de Oracle. Utilice el script de actualización en 33789 para generar declaraciones RENAME para cambiar la convención de nombres.
Se ha eliminado el soporte para cx_Oracle < 7.0.
Para permitir servir un sitio Django en una subruta sin cambiar el valor de STATIC_URL, se elimina la barra diagonal inicial de ese ajuste (ahora 'static/') en el plantilla de proyecto por defecto startproject.
El método de la clase AdminSite para la vista administrativa index ya no está decorado con never_cache cuando se accede directamente, más que a través de la propiedad recomendada AdminSite.urls o el método AdminSite.get_urls().
Las traducciones son:
La función sin documentar django.test.runner.reorder_suite() se renombró a reorder_tests(). Ahora acepta un iterador de pruebas en lugar de un conjunto de pruebas, y devuelve un iterador de pruebas.
Llamar FileSystemStorage.delete() con un name vacío ahora levanta ValueError en lugar de AssertionError.
Llamar EmailMultiAlternatives.attach_alternative() o EmailMessage.attach() con argumentos content o mimetype inválidos ahora levantan ValueError en lugar de AssertionError.
assertHTMLEqual() ya no considera una atributo no booleano sin valor igual a un atributo con el mismo nombre y valor.
Las pruebas que fallan al cargar, por ejemplo debido a errores de sintaxis, ahora siempre coinciden cuando se utiliza test --tag.
La función sin documentar django.contrib.admin.utils.lookup_needs_distinct() se renombró a lookup_spawns_duplicates().
El método sin documentar HttpRequest.get_raw_uri() se eliminó. El método HttpRequest.build_absolute_uri() puede ser una alternativa adecuada.
El argumento object de las métodos no documentadas ModelAdmin.log_addition(), log_change(), y log_deletion() se renombró a obj.
RssFeed, Atom1Feed, y sus subclases ahora emiten elementos sin contenido como etiquetas autocerrantes.
NodeList.render() ya no convierte la salida del método render() para nodos individuales a una cadena. El método Node.render() siempre debe devolver una cadena tal como se documenta.
La propiedad where_class de django.db.models.sql.query.Query y el argumento where_class al método privado get_extra_restriction() de ForeignObject y ForeignObjectRel han sido eliminados. Si es necesario, inicializa en su lugar django.db.models.sql.where.WhereNode.
El argumento filter_clause del método no documentado Query.add_filter() ha sido reemplazado por dos argumentos posicionales filter_lhs y filter_rhs.
La clase CsrfViewMiddleware ahora utiliza request.META['CSRF_COOKIE_NEEDS_UPDATE'] en lugar de request.META['CSRF_COOKIE_USED'], request.csrf_cookie_needs_reset y response.csrf_cookie_set para rastrear si el cookie CSRF debe ser enviado. Este es un API privado no documentado.
La constante no documentada TRANSLATOR_COMMENT_MARK ha sido movida de django.template.base a django.utils.translation.template.
El argumento real_apps del método no documentado django.db.migrations.state.ProjectState.__init__() ahora debe ser un conjunto si se proporciona.
Las clases RadioSelect y CheckboxSelectMultiple de controles ahora se renderizan en etiquetas <div> para que sean anunciadas con mayor concisión por los lectores de pantalla. Si necesita el comportamiento anterior, sobreescriba la plantilla del widget con la plantilla adecuada desde Django 3.2:ref:sobrescribiendo las plantillas de controles integrados <overriding-built-in-widget-templates>.
El filtro de plantilla floatformat ya no depende de la configuración USE_L10N y siempre devuelve salida localizada. Utilice el sufijo u para deshabilitar la localización.
El valor predeterminado de la configuración USE_L10N ha cambiado a True. Consulte la sección de localización anterior para obtener más detalles.
Como parte del migración a zoneinfo, django.utils.timezone.utc ha sido cambiado para ser un alias de datetime.timezone.utc.
La versión mínima soportada de asgiref se incrementa desde 3.3.2 a 3.4.1.
pytz¶Como parte del cambio a zoneinfo, el uso de zonas horarias pytz está obsoleto.
Según esto, los argumentos is_dst de las siguientes también están obsoletas:
Se eliminará el soporte para el uso de pytz en Django 5.0.
Para seguir buenas prácticas, el valor por defecto del parámetro USE_TZ cambiará de False a True, y se habilitará el soporte de zona horaria por defecto en Django 5.0.
Ten en cuenta que el archivo de configuración predeterminado settings.py creado mediante la herramienta django-admin startproject incluye USE_TZ = True desde Django 1.4.
Puedes establecer USE_TZ en False en tus ajustes de proyecto antes de eso para optar fuera.
A fin de seguir buenas prácticas, el valor por defecto del ajuste USE_L10N se cambia desde False a True.
Además, USE_L10N está descontinuado a partir de esta versión. A partir de Django 5.0, por defecto, cualquier fecha o número mostrado por Django será localizado.
El etiqueta {% localize %} y los filtros localizar/ deslocalizar seguirán siendo respetados por Django.
La configuración de prueba SERIALIZE está descontinuada ya que se puede inferir del atributo databases con la opción serialized_rollback habilitada.
El módulo django.utils.baseconv no documentado está descontinuado.
El módulo django.utils.datetime_safe no documentado está descontinuado.
El protocolo de sitio por defecto para los mapas de sitios creados fuera del contexto de una solicitud cambiará desde 'http' a 'https' en Django 5.0.
La argumento extra_tests para DiscoverRunner.build_suite() y DiscoverRunner.run_tests() está descontinuado.
Los textos traducidos son:
Las clases django.contrib.gis.admin.GeoModelAdmin y OSMGeoAdmin están deprecadas. Utiliza en su lugar las clases ModelAdmin y GISModelAdmin.
Dado que la renderización de formularios ahora utiliza el motor de plantillas, el método auxiliar no documentado BaseForm._html_output() está deprecado.
La capacidad de devolver un str desde ErrorList y ErrorDict está deprecada. Se espera que estos métodos devuelvan una SafeString.
Estas características han llegado al final de su ciclo de deprecación y están eliminadas en Django 4.0.
Consulte Características deprecadas en 3.0 para obtener detalles sobre estas modificaciones, incluyendo cómo eliminar el uso de estas características.
django.utils.http.urlquote(), urlquote_plus(), urlunquote(), y urlunquote_plus() están eliminados.
django.utils.encoding.force_text() y smart_text() están eliminadas.
django.utils.translation.ugettext(), ugettext_lazy(), ugettext_noop(), ungettext(), y ungettext_lazy() están eliminados.
django.views.i18n.set_language() no establece el idioma del usuario en request.session (clave _language).
Se requiere que alias=None esté presente en la firma de las subclases de django.db.models.Expression.get_group_by_cols().
Se ha eliminado django.utils.text.unescape_entities().
Se ha eliminado django.utils.http.is_safe_url().
Consulte Características obsoletas en 3.1 para obtener detalles sobre estas modificaciones, incluyendo cómo eliminar el uso de estas características.
Se ha eliminado la configuración PASSWORD_RESET_TIMEOUT_DAYS.
La búsqueda isnull ya no permite utilizar valores no booleanos en el lado derecho.
Se ha eliminado la clase de excepción django.db.models.query_utils.InvalidQuery.
El punto de entrada django-admin.py se ha eliminado.
Se ha eliminado el método HttpRequest.is_ajax().
Los textos traducidos son:
Se elimina el soporte para los tokens de restablecimiento de contraseña pre-Django 3.1 en el sitio administrativo (que utilizan el algoritmo de hash SHA-1).
Se elimina el soporte para el formato de codificación pre-Django 3.1 de las sesiones.
Se elimina el soporte para las firmas django.core.signing.Signer pre-Django 3.1 (codificadas con el algoritmo SHA-1).
Se elimina el soporte para las firmas django.core.signing.dumps() pre-Django 3.1 (codificadas con el algoritmo SHA-1) en django.core.signing.loads().
Se elimina el soporte para las sesiones de usuarios pre-Django 3.1 (que utilizan el algoritmo SHA-1).
El argumento get_response para django.utils.deprecation.MiddlewareMixin.__init__() es obligatorio y no acepta None.
Se elimina el argumento providing_args para django.dispatch.Signal.
El argumento length para django.utils.crypto.get_random_string() es obligatorio.
La cadena de mensajes list para ModelMultipleChoiceField se ha eliminado.
Se ha eliminado el soporte para pasar alias de columnas brutas a QuerySet.order_by().
Se ha eliminado el campo del modelo NullBooleanField, excepto por el soporte en migraciones históricas.
Se ha eliminado django.conf.urls.url().
Se ha eliminado el campo del modelo django.contrib.postgres.fields.JSONField, excepto por el soporte en migraciones históricas.
Se han eliminado django.contrib.postgres.fields.jsonb.KeyTransform y django.contrib.postgres.fields.jsonb.KeyTextTransform.
Se ha eliminado django.contrib.postgres.forms.JSONField.
Se han eliminado las etiquetas de plantilla {% ifequal %} y {% ifnotequal %}.
Se ha eliminado la configuración transitoria DEFAULT_HASHING_ALGORITHM.
may 31, 2026