Notas de lanzamiento de Django 5.2

2 de abril de 2025

Bienvenido a Django 5.2!

Estas notas de lanzamiento cubren las nuevas características, así como algunas cambios incompatibles con la retrocompatibilidad que debes tener en cuenta al actualizar desde Django 5.1 o versiones anteriores. Hemos comenzado el proceso de desactivación para algunas características <deprecated-features-5.2>.

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

Django 5.2 se designa como una lanzamiento con soporte a largo plazo. Recibirá actualizaciones de seguridad durante al menos tres años después de su lanzamiento. El soporte para el LTS anterior, Django 4.2, terminará en abril de 2026.

Compatibilidad con Python

Django 5.2 admite Python 3.10, 3.11, 3.12, 3.13 y 3.14 (a partir de la versión 5.2.8). Recomendamos y solo oficialmente respaldamos la última versión de cada serie.

¿Qué hay de nuevo en Django 5.2

Importación automática de modelos en el shell

El comando administrativo shell ahora importa automáticamente los modelos de todas las aplicaciones instaladas. Puedes ver detalles adicionales de los objetos importados estableciendo la bandera --verbosity a 2 o más:

$ python -Wall manage.py shell --verbosity=2
6 objects imported automatically, including:

  from django.contrib.admin.models import LogEntry
  from django.contrib.auth.models import Group, Permission, User
  from django.contrib.contenttypes.models import ContentType
  from django.contrib.sessions.models import Session

Este es el resultado de la traducción:

Claves primarias compuestas

La nueva django.db.models.CompositePrimaryKey permite crear tablas con una clave primaria que consiste en múltiples campos.

Para utilizar una clave primaria compuesta, al definir un modelo establezca el atributo pk para ser una CompositePrimaryKey:

from django.db import models


class Release(models.Model):
    pk = models.CompositePrimaryKey("version", "name")
    version = models.IntegerField()
    name = models.CharField(max_length=20)

Consulte Claves primarias compuestas para obtener más detalles.

Sobrescritura simplificada de BoundField

Antes de la versión 5.2, sobrescribir Field.get_bound_field() era la única opción para utilizar un campo vinculado personalizado: BoundField. Django ahora admite especificar las siguientes atributos para personalizar la renderización del formulario:

Para personalizar el BoundField de una clase Form:

from django import forms


class CustomBoundField(forms.BoundField):

    custom_class = "custom"

    def css_classes(self, extra_classes=None):
        result = super().css_classes(extra_classes)
        if self.custom_class not in result:
            result += f" {self.custom_class}"
        return result.strip()


class CustomForm(forms.Form):
    bound_field_class = CustomBoundField

    name = forms.CharField(
        label="Your Name",
        max_length=100,
        required=False,
        widget=forms.TextInput(attrs={"class": "name-input-class"}),
    )
    email = forms.EmailField(label="Your Email")

Al renderizar una instancia de CustomForm, se incluye el siguiente HTML:

<div class="custom">
  <label for="id_name">Your Name:</label>
  <input type="text" name="name" class="name-input-class" maxlength="100" id="id_name">
</div>

<div class="custom">
  <label for="id_email">Your Email:</label>
  <input type="email" name="email" maxlength="320" required="" id="id_email">
</div>

Consulte Customizando BoundField para obtener más detalles sobre esta característica.

Características menores

django.contrib.admin

  • El template admin/base.html ahora tiene un nuevo bloque extrabody para agregar código personalizado antes de la etiqueta de cierre </body>.

  • El valor de un campo URLField se renderiza como enlace.

django.contrib.admindocs

  • Los enlaces a componentes en las documentaciones ahora admiten texto de enlace personalizado, utilizando el formato :role:`texto de enlace <enlace>`. Consulte documentación helpers para obtener más detalles.

  • Las páginas de modelo model pages ahora están restringidas a usuarios con las correspondientes permisos de vista o cambio.

django.contrib.auth

  • La cuenta de iteraciones por defecto para el hasheador de contraseña PBKDF2 se incrementa desde 870,000 hasta 1,000,000.

  • Se proporcionan los siguientes nuevos métodos asíncronos, utilizando un prefijo a:

    • UserManager.acreate_user()

    • UserManager.crear_superuser()

    • BaseUserManager.obtener_por_clave_natural()

    • User.obtener_permisos_del_usuario()

    • User.obtener_todos_los_permisos()

    • User.obtener_permisos_de_grupo()

    • User.tiene_permiso()

    • User.tiene_permisos()

    • User.tiene_módulo_permitido()

    • ModelBackend.autenticar()

    • ModelBackend.obtener_permisos_del_usuario()

    • ModelBackend.obtenga_permisos_de_grupo()

    • ModelBackend.obtenga_todos_los_permisos()

    • ModelBackend.tiene_permiso()

    • ModelBackend.tiene_módulo_permisos()

    • RemoteUserBackend.autenticar()

    • RemoteUserBackend.configura_usuario()

  • Los backends de autenticación pueden proporcionar ahora implementaciones asíncronas, que se utilizan cuando se llaman funciones de autenticación asíncronas (por ejemplo autenticar()) para reducir el cambio de contexto lo que mejora el rendimiento. Consulte añadir una interfaz asíncrona para obtener más detalles.

  • Las clases de validadores de contraseña ahora tienen un nuevo método obtener_mensaje_de_error(), que se puede sobrescribir en subclases para personalizar los mensajes de error.

django.contrib.gis

  • GDAL ahora admite geometrías curvas CurvePolygon, CompoundCurve, CircularString, MultiSurface y MultiCurve a través de la nueva propiedad OGRGeometry.tiene_curva, y los métodos OGRGeometry.obtenga_geometría_lineal() y OGRGeometry.obtenga_geometría_curva().

  • Se admiten ahora las consultas de lookup coveredby y covers en MySQL.

django.contrib.syndication

  • Los textos traducidos son:

Base de datos

  • Las conexiones a MySQL ahora utilizan por defecto el conjunto de caracteres utf8mb4, en lugar de utf8, que es un alias del conjunto de caracteres obsoleto utf8mb3.

  • Los backends Oracle admiten ahora pools de conexión, estableciendo "pool" en la parte de configuración de opciones de base de datos.

Decoradores

Correo electrónico

Información sobre errores

Formularios

  • El nuevo widget de formulario ColorInput es para ingresar un color en formato hexadecimal rrggbb y se renderiza como <input type="color" ...>. Algunos navegadores admiten una interfaz visual de selector de colores para este tipo de entrada.

  • El nuevo widget de formulario SearchInput es para ingresar consultas de búsqueda y se renderiza como <input type="search" ...>.

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

  • Se ha agregado el argumento field_id para ErrorList, lo que permite agregar un atributo HTML id en la plantilla de errores. Consulte ErrorList.field_id para obtener más detalles.

  • Se ha agregado una propiedad aria_describedby a BoundField para facilitar el uso de este atributo HTML en las plantillas.

  • Para mejorar la accesibilidad para usuarios con lectores de pantalla, se utiliza aria-describedby para asociar campos de formulario con sus mensajes de error. Consulte cómo se muestran los errores del formulario para obtener más detalles.

  • El nuevo objeto de activo Script está disponible para agregar atributos HTML personalizados a JavaScript en el media de formularios. Consulte las rutas como objetos para obtener más detalles.

Comandos de Gestión

  • Se muestra una nueva advertencia cuando se ejecuta runserver, indicando que no es adecuado para producción. Esta advertencia puede suprimirse estableciendo la variable de entorno DJANGO_RUNSERVER_HIDE_WARNING en "true".

  • Las órdenes makemigrations y migrate tienen un nuevo atributo Command.autodetector para subclases que deseen sobrescribirlo para utilizar una clase de detección personalizada.

  • El método nuevo BaseCommand.get_check_kwargs() se puede sobreescribir en comandos personalizados para controlar la ejecución de las verificaciones del sistema, por ejemplo, para optarse a las verificaciones dependientes de la base de datos.

Migraciones

  • La operación nueva AlterConstraint es una operación sin efecto que altera las restricciones sin borrar ni recrearlas en la base de datos.

Modelos

  • La cláusula SELECT generada al utilizar QuerySet.values() y QuerySet.values_list() ahora coincide con el orden especificado de las expresiones referenciadas. Anteriormente, el orden se basaba en una serie de reglas contraintuitivas que hacían que la combinación de consultas a través de métodos como QuerySet.union() fuera impredecible.

  • Se han agregado funcionalidades de validación para las restricciones de modelo que utilizan un GeneratedField.

  • La nueva atributo Expression.set_returning especifica que la expresión contiene una función devolviendo conjuntos, lo que implica la evaluación de subconsultas. Esto es necesario para muchas funciones devolviendo conjuntos de Postgres.

  • Ya no se requiere establecer CharField.max_length en SQLite, ya que admite columnas VARCHAR ilimitadas.

  • La función QuerySet.explain() ahora admite las opciones memory y serialize en PostgreSQL 17+.

  • La nueva función de base de datos JSONArray acepta una lista de nombres de campos o expresiones y devuelve un array JSON que contiene esos valores.

  • El nuevo atributo Expression.allows_composite_expressions especifica que la expresión permite expresiones compuestas, por ejemplo, para apoyar claves primarias compuestas <cpk-and-database-functions>.

Solicitudes y respuestas

Serialización

  • Cada formato de serialización ahora define una clase Deserializer, en lugar de una función, para mejorar la extensibilidad al definir un formato de serialización personalizado: Formatos de serialización personalizados.

Plantillas

  • El nuevo decorador simple_block_tag() permite crear etiquetas de bloque simples, que pueden aceptar y utilizar una sección del template.

Pruebas

  • Las pila de frames de las afirmaciones personalizadas de Django ahora están ocultas. Esto hace que los fallos de prueba sean más fáciles de leer y permite test --pdb entrar directamente en el método de prueba fallido.

  • Los datos cargados desde fixtures y habilitados con serialized_rollback=True ahora están disponibles durante TransactionTestCase.setUpClass().

URLs

  • reverse() y reverse_lazy() ahora aceptan los argumentos de palabra clave query y fragment, lo que permite agregar una cadena de consulta y/o identificador de fragmento en la URL generada, respectivamente.

Utilidades

  • SafeString ahora devuelve NotImplemented en __add__ para valores del lado derecho no de tipo string. Esto se alinea con el comportamiento de agregación de str y permite utilizar __radd__ si está disponible.

  • format_html_join() ahora admite tomar un iterable de mapas, pasando sus contenidos como argumentos de palabra clave a format_html().

Cambios incompatibles con versiones anteriores en 5.2

Backend de base de datos API

Esta es la traducción de los textos:

  • El nuevo método Model._is_pk_set() permite comprobar si la clave primaria de una instancia de Model está definida.

  • BaseDatabaseOperations.adapt_decimalfield_value() ahora es un no-op, simplemente devolviendo el valor dado.

django.contrib.gis

  • Los textos traducidos son:

  • Se ha eliminado el soporte para GDAL 3.0.

Se ha dejado de apoyar PostgreSQL 13

El soporte upstream para PostgreSQL 13 finaliza en noviembre del 2025. Django 5.2 admite PostgreSQL 14 y versiones superiores.

Se ha cambiado el conjunto de caracteres por defecto de la conexión a MySQL.

Las conexiones a MySQL ahora utilizan por defecto el conjunto de caracteres utf8mb4, en lugar del utf8, que es un alias para el conjunto de caracteres obsoleto utf8mb3. Puede especificar utf8mb3 en la parte OPTIONS de la configuración DATABASES si es necesario para bases de datos legadas.

Miscelánea

Características obsoletas en 5.2

Miscelánea

  • El argumento all para la función find() del módulo django.contrib.staticfiles.finders está obsoleto a favor del argumento find_all.

  • Los fallbacks a request.user y request.auser() cuando user es None en las funciones login() de django.contrib.auth y alogin(), respectivamente, están obsoletos.

  • El argumento de palabra clave ordering de las funciones agregadas específicas de PostgreSQL ArrayAgg, JSONBAgg y StringAgg del módulo django.contrib.postgres.aggregates está obsoleto a favor del argumento order_by.

  • El soporte para subclases de RemoteUserMiddleware que sobrescriben process_request() sin sobrescribir aprocess_request() está obsoleto.