Notas de lanzamiento de Django 1.10

1 de agosto de 2016

Bienvenido a Django 1.10!

Estas notas de lanzamiento cubren las nuevas características, así como algunas cambios incompatibles con lo anterior que deseas tener en cuenta al actualizar desde Django 1.9 o versiones anteriores. 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-1.10>.

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

Al igual que Django 1.9, Django 1.10 requiere Python 2.7, 3.4 o 3.5. Recomendamos y solo oficialmente apoyamos la última versión de cada serie.

Qué hay de nuevo en Django 1.10

Búsqueda de texto completo para PostgreSQL

Ahora django.contrib.postgres incluye una colección de funciones de base de datos para permitir el uso del motor de búsqueda de texto completo. Puedes buscar a través de múltiples campos en tu base de datos relacional, combinar las búsquedas con otras consultas, utilizar diferentes configuraciones de idioma y ponderaciones, y ordenar los resultados por relevancia.

También ahora incluye soporte para trigramas, utilizando la trigram_similar búsqueda y las expresiones TrigramSimilarity y TrigramDistance.

Medio de acceso a middleware de estilo nuevo

Se introduce un nuevo estilo de middleware para resolver la falta de capas de capa estricto del antiguo estilo de middleware descrito en DEP 0005. Tendrás que adaptar el middleware antiguo y personalizado y cambiar desde la configuración MIDDLEWARE_CLASSES al nuevo parámetro de configuración MIDDLEWARE para aprovechar las mejoras.

Soporte oficial para nombres de usuario Unicode

El modelo de usuarios User en django.contrib.auth originalmente solo aceptaba letras y números ASCII en los nombres de usuario. Aunque no era una elección deliberada, siempre se han aceptado caracteres Unicode cuando se utiliza Python 3.

Ahora el validador de nombre de usuario acepta explícitamente caracteres Unicode por defecto solo en Python 3.

Los modelos de usuarios personalizados pueden utilizar los nuevos ASCIIUsernameValidator o UnicodeUsernameValidator.

Características menores

django.contrib.admin

  • Para sitios que se ejecutan en una subruta, el valor de la URL predeterminada para el enlace «Ver sitio» <django.contrib.admin.AdminSite.site_url> en la parte superior de cada página administrativa ahora apuntará a request.META['SCRIPT_NAME'] si está configurado, en lugar de /.

  • El mensaje de éxito que aparece después de agregar o editar un objeto ahora contiene un enlace a la forma de cambio del objeto.

  • Se eliminan todos los JavaScript inline para que puedas habilitar el encabezado HTTP Content-Security-Policy si lo deseas.

  • El nuevo atributo InlineModelAdmin.classes permite especificar clases en los conjuntos de campos inline. Los inlines con una clase collapse se expandirán inicialmente y su encabezado tendrá un pequeño enlace «mostrar».

  • Si un usuario no tiene la permiso de agregar, el bloque object-tools en la lista de cambios de un modelo ahora se renderizará (sin el botón de agregar). Esto facilita la adición de herramientas personalizadas en este caso.

  • El modelo LogEntry almacena ahora los mensajes de cambio en una estructura JSON para que el mensaje pueda ser traducido dinámicamente utilizando el idioma activo actual. El nuevo método LogEntry.get_change_message() es ahora la forma preferida de obtener el mensaje de cambio.

  • Los objetos seleccionados para campos en ModelAdmin.raw_id_fields tienen ahora un enlace a la forma de cambio del objeto.

  • Se han agregado las opciones «No fecha» y «Tiene fecha» para DateFieldListFilter si el campo es nulo.

  • La biblioteca jQuery incorporada en la administración se ha actualizado desde la versión 2.1.4 a 2.2.3.

django.contrib.auth

  • Se ha agregado soporte para el algoritmo de hash de contraseña Argon2. Se recomienda sobre PBKDF2, aunque no es el valor por defecto ya que requiere una biblioteca adicional.

  • La cuenta de iteraciones predeterminada del hasher de contraseñas PBKDF2 se ha aumentado en un 25%. Este cambio compatible con versiones anteriores no afectará a los usuarios que hayan sobrescrito django.contrib.auth.hashers.PBKDF2PasswordHasher para cambiar el valor por defecto.

  • La vista django.contrib.auth.views.logout() envía encabezados «no-cache» para prevenir un problema donde Safari almacena redirects y impide que un usuario pueda cerrar sesión.

  • Se han agregado el argumento backend opcional a la función django.contrib.auth.login() para permitir su uso sin credenciales.

  • La nueva configuración de ajuste LOGOUT_REDIRECT_URL controla la redirección de la vista django.contrib.auth.views.logout() si la vista no recibe el argumento next_page.

  • El nuevo parámetro redirect_authenticated_user para la vista django.contrib.auth.views.login() permite redirigir a los usuarios autenticados que visiten la página de inicio de sesión.

  • Las nuevas clases AllowAllUsersModelBackend y AllowAllUsersRemoteUserBackend ignoran el valor de User.is_active, mientras que las clases ModelBackend y RemoteUserBackend ahora rechazan a los usuarios inactivos.

django.contrib.gis

  • Los lookups de distancia <distance-lookups> ahora aceptan expresiones como el parámetro del valor de distancia.

  • La nueva propiedad GEOSGeometry.unary_union calcula la unión de todos los elementos de esta geometría.

  • Se ha agregado el predicado binario GEOSGeometry.covers().

  • Se han agregado el método GDALBand.statistics() y las propiedades mean y std.

  • Se ha agregado soporte para la clase de agregación MakeLine y la función GeoHash en SpatiaLite.

  • Se ha agregado soporte para las funciones Difference, Intersection, y SymDifference en MySQL.

  • Se ha agregado soporte para instanciar geometrías vacías de GEOS.

  • La nueva propiedad trim y la propiedad precision de WKTWriter permiten controlar la salida de la parte fraccionaria de las coordenadas en WKT.

  • Agregó las propiedades LineString.closed y MultiLineString.closed.

  • La traducción es:

  • La capacidad para replicar los datos de entrada en el método GDALBand.data() se ha agregado. Los datos de banda pueden actualizarse ahora con valores repetidos de manera eficiente.

  • Se han agregado funciones de base de datos: IsValid y MakeValid, así como la búsqueda isvalid, todas para PostGIS. Esto permite filtrar y reparar geometrías inválidas en el lado de la base de datos.

  • Agregada la compatibilidad con rasters para todos los consultas espaciales.

django.contrib.postgres

  • Para conveniencia, HStoreField ahora convierte sus claves y valores a cadenas de texto.

django.contrib.sesiones

  • La orden de comando de administración clearsesiones ahora elimina las sesiones basadas en archivos.

django.contrib.sitios

  • El modelo Sitio ahora admite claves naturales <topics-serialización-claves-naturales>.

django.contrib.archivos_estáticos

  • La etiqueta de plantilla estático utiliza ahora django.contrib.archivos_estáticos si está en INSTALLED_APPS. Esto es especialmente útil para aplicaciones terceras que pueden utilizar ahora siempre {% load static %} (en lugar de {% load staticfiles %} o {% load static from staticfiles %}) y no preocuparse por si el app staticfiles está instalado.

  • Puedes personalizar con más facilidad la opción collectstatic --ignore con una configuración personalizada de AppConfig.

Cache

  • El almacenamiento en caché basado en archivos ahora utiliza el protocolo de serialización más alto.

CSRF

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

  • Para proteger contra ataques BREACH , la mecánica de protección CSRF ahora cambia el valor del token de formulario en cada solicitud (mientras se mantiene un secreto invariante que se puede utilizar para validar los diferentes tokens).

Base de datos

  • La resta de datos temporales se ha unificado en todos los backends.

  • Si el motor de base de datos lo admite, los backends pueden establecer DatabaseFeatures.can_return_ids_from_bulk_insert=True y implementar DatabaseOperations.fetch_returned_insert_ids() para establecer claves primarias en objetos creados utilizando QuerySet.bulk_create().

  • Se han agregado argumentos de palabra clave a los métodos as_sql() de diversas expresiones (Func, When, Case y OrderBy) para permitir que los backends de base de datos los personalicen sin mutar self, lo cual no es seguro cuando se utilizan diferentes motores de base de datos. Consulte los parámetros arg_joiner y **extra_context de la Func.as_sql() para un ejemplo.

Almacenamiento de archivos

Formularios

  • Formulario y widget Media ahora se sirven utilizando django.contrib.staticfiles si está instalado.

  • El tag <input> renderizado por CharField incluye ahora un atributo minlength si el campo tiene una min_length.

  • Los campos de formulario requeridos tienen ahora el atributo HTML required. Establece la nueva propiedad Form.use_required_attribute en False para deshabilitarlo. El atributo required no se incluye en las formas de formsets porque la validación del navegador puede no ser correcta al agregar y eliminar formsets.

Vistas Genericas

  • La clase View ahora se puede importar desde django.views.

Internacionalización

  • La función auxiliar i18n_patterns() ahora se puede utilizar en una URLConf raíz especificada utilizando request.urlconf.

  • Al establecer el nuevo parámetro prefix_default_language para i18n_patterns() en False, puedes permitir acceder al idioma predeterminado sin un prefijo de URL.

  • set_language() ahora devuelve un código de estado 204 (Sin contenido) para solicitudes AJAX cuando no hay un parámetro next en POST o GET.

  • Las vistas basadas en clases JavaScriptCatalog y JSONCatalog sustituyen a las vistas funcionales deprecadas javascript_catalog() y json_catalog(). Las nuevas vistas son casi equivalentes a las antiguas excepto que por defecto las nuevas vistas recopilan todas las cadenas JavaScript en el dominio de traducción djangojs de todas las aplicaciones instaladas en lugar de solo las cadenas JavaScript de LOCALE_PATHS.

Comandos de Gestión

  • call_command() ahora devuelve el valor devuelto desde el método command.handle().

  • La nueva opción check --fail-level permite especificar el nivel de mensaje que causará que la orden ejecutada salga con un estado no cero.

  • La nueva opción makemigrations --check hace que la orden salga con un estado no cero cuando se detecten cambios en modelos sin migraciones.

  • makemigrations ahora muestra el camino a los archivos de migración que genera.

  • La opción shell --interface ahora acepta python para forzar el uso del intérprete Python «puro».

  • La nueva opción shell --command te permite ejecutar una orden como Django y salir, en lugar de abrir la consola interactiva.

  • Se ha agregado una advertencia a dumpdata si se especifica un modelo proxy (lo que resulta en ningún resultado) sin su padre concreto.

  • La nueva atributo BaseCommand.requires_migrations_checks puede ser establecido a True si deseas que tu orden imprima una advertencia, como lo hace runserver, si el conjunto de migraciones en disco no coinciden con las migraciones en la base de datos.

  • Para ayudar con la prueba, call_command() ahora acepta un objeto de orden como primer argumento.

  • La orden shell admite la completación de tabuladores en sistemas que usan libedit, por ejemplo macOS.

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

Migraciones

  • Se ha agregado el soporte para la serialización de objetos enum.Enum.

  • Se ha agregado el argumento elidable a las operaciones RunSQL y RunPython para permitir que se eliminen cuando se apliquen migraciones combinadas.

  • Se ha agregado el soporte para migraciones no atómicas <non-atomic-migrations>` estableciendo la propiedad atomic en un objeto Migration.

  • Los comandos migrate y makemigrations ahora verifican una historia de migración consistente. Si encuentran algunas dependencias no aplicadas de una migración aplicada, se levanta la excepción InconsistentMigrationHistory.

  • Los señales pre_migrate() y post_migrate() ahora envían su plan de migración y sus aplicaciones.

Modelos

  • Las claves foráneas inversas desde modelos proxy se propagan ahora a su clase concreta. La relación inversa adjunta por un ForeignKey que apunte a un modelo proxy está ahora accesible como descriptor en la clase del modelo proximizado y puede ser referenciada en el filtrado de consultas.

  • El nuevo método Field.rel_db_type() devuelve el tipo de datos de columna de base de datos para campos como ForeignKey y OneToOneField que apunten a otro campo.

  • La propiedad clase arity se ha agregado a la clase Func. Esta propiedad puede usarse para establecer el número de argumentos que acepta la función.

  • Se han agregado los siguientes cambios:

  • Se puede llamar a la función QuerySet.in_bulk() sin argumentos para devolver todos los objetos en el conjunto de consultas.

  • La propiedad related_query_name ahora admite etiquetas de aplicación y clases de interpolación utilizando las cadenas '%(app_label)s' y '%(class)s'.

  • Se permite sobrescribir campos de modelos heredados de clases base abstractas.

  • La función prefetch_related_objects() ahora es una API pública.

  • La función QuerySet.bulk_create() establece la clave primaria en los objetos cuando se utiliza PostgreSQL.

  • Se ha agregado la clase de función de base de datos Cast.

  • Un modelo proxy puede heredar múltiples modelos proxy que comparten una clase padre no abstracta común.

  • Se han agregado funciones de extracción Extract para extraer componentes de fechas y horas como enteros, como el año y la hora.

  • Se han agregado funciones de truncamiento Trunc para truncar una fecha o fecha/hora a un componente significativo. Permiten consultas como ventas por día o ventas por hora.

  • Ahora traduciré los textos manteniendo todas las etiquetas intactas.

  • Las nuevas opciones Meta.base_manager_name y Meta.default_manager_name permiten controlar los _base_manager y _default_manager, respectivamente.

Solicitudes y respuestas

  • Se agregó request.user a la vista de depuración.

  • Se agregaron los métodos readable() y seekable() de la clase HttpResponse para hacer una instancia un objeto similar a un flujo y permitir envolverlo con io.TextIOWrapper.

  • Se agregaron las atributos HttpRequest.content_type y content_params, que se parsean desde el encabezado CONTENT_TYPE.

  • El parser para request.COOKIES se simplificó para coincidir mejor con el comportamiento de los navegadores. request.COOKIES puede contener ahora cookies que son inválidas según RFC 6265 pero pueden ser establecidas mediante document.cookie.

Serialización

  • El django.core.serializers.json.DjangoJSONEncoder ahora sabe cómo serializar cadenas perezosas, típicamente utilizadas para contenido translatable.

Plantillas

  • Se agregó la opción autoescape a la clase DjangoTemplates y a la clase Engine.

  • Se han agregado los operadores de comparación is y is not a la etiqueta if.

  • Se ha permitido a dictsort ordenar una lista de listas por un elemento en una posición especificada.

  • El procesador de contexto debug() contiene consultas para todos los alias de bases de datos en lugar de solo el alias predeterminado.

  • Se ha agregado soporte para rutas relativas a los argumentos de cadena de las etiquetas de plantilla extends y include.

Pruebas

URLs

  • Una adición en django.setup() permite que la resolución de URL que ocurre fuera del ciclo de solicitud/respuesta (por ejemplo, en comandos de administración y scripts independientes) tenga en cuenta FORCE_SCRIPT_NAME cuando está configurado.

Validadores

  • Ahora la clase ~django.core.validators.URLValidator limita el largo de los etiquetas de nombres de dominio a 63 caracteres y el largo total de los nombres de dominio a 253 caracteres por RFC 1034.

  • int_list_validator() ahora acepta un parámetro booleano opcional allow_negative, que por defecto es False, para permitir números negativos.

Cambios no compatibles hacia atrás en 1.10

Advertencia

Además de los cambios descritos en esta sección, asegúrate de revisar la Características eliminadas en 1.10 para las características que han alcanzado el final de su ciclo de deprecación y por lo tanto han sido eliminadas. Si no has actualizado tu código dentro del plazo de deprecación para una característica en particular, su eliminación puede aparecer como un cambio incompatible hacia atrás.

Backend de base de datos API

  • El campo de área AreaField del sistema de información geográfico (GIS) utiliza un tipo numérico subyacente no especificado que, en la práctica, podría ser cualquier tipo numérico de Python. Los valores de decimal.Decimal recuperados desde la base de datos se convierten ahora a float para facilitar su combinación con los valores utilizados por las bibliotecas GIS.

  • Para habilitar la resta temporal debes establecer la bandera de característica del motor de base de datos supports_temporal_subtraction en True y implementar el método DatabaseOperations.subtract_temporals(). Este método debe devolver la consulta SQL y los parámetros necesarios para calcular la diferencia en microsegundos entre los argumentos lhs y rhs en el tipo de dato utilizado para almacenar DurationField.

_meta.get_fields() devuelve campos inversos consistentes para modelos de proxy

Antes de Django 1.10, el método get_fields() devolvía diferentes campos inversos cuando se llamaba en un modelo de proxy comparado con su clase concreta proximada. Esta inconsistencia se corrigió devolviendo la totalidad de los campos que apuntan a una clase concreta o uno de sus modelos de proxy en ambos casos.

Se ha incrementado el max_length de AbstractUser.username a 150

Se incluye una migración para django.contrib.auth.models.User.username. Si tienes un modelo de usuario personalizado que hereda de AbstractUser, necesitarás generar y aplicar una migración de base de datos para tu modelo de usuario.

Consideramos aumentarlo a 254 caracteres para facilitar el uso de direcciones de correo electrónico (que están limitadas a 254 caracteres) como nombres de usuario, pero lo rechazamos debido a una limitación de MySQL. Cuando se utiliza la codificación utf8mb4 (recomendada para un soporte Unicode adecuado), MySQL solo puede crear índices únicos con 191 caracteres por defecto. Por tanto, si necesitas una longitud mayor, por favor usa un modelo de usuario personalizado.

Si deseas preservar la limitación de 30 caracteres para los nombres de usuario, utiliza un formulario personalizado al crear un usuario o cambiar nombres de usuario:

from django.contrib.auth.forms import UserCreationForm


class MyUserCreationForm(UserCreationForm):
    username = forms.CharField(
        max_length=30,
        help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.",
    )

Si deseas mantener esta restricción en el panel de administración, establece UserAdmin.add_form para que utilice este formulario:

from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User


class UserAdmin(BaseUserAdmin):
    add_form = MyUserCreationForm


admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Se ha eliminado el soporte para PostgreSQL 9.1

El soporte oficial de PostgreSQL 9.1 se termina en septiembre de 2016. Como consecuencia, Django 1.10 establece PostgreSQL 9.2 como la versión mínima que oficialmente admite.

La salida de runserver pasa por logging

Los textos traducidos son:

LOGGING = {
    # ...
    "formatters": {
        "django.server": {
            "()": "django.utils.log.ServerFormatter",
            "format": "[%(server_time)s] %(message)s",
        }
    },
    "handlers": {
        "django.server": {
            "level": "INFO",
            "class": "logging.StreamHandler",
            "formatter": "django.server",
        },
    },
    "loggers": {
        "django.server": {
            "handlers": ["django.server"],
            "level": "INFO",
            "propagate": False,
        }
    },
}

Se eliminaron los modelos de prueba auth.CustomUser y auth.ExtensionUser

Dado que se introdujeron las migraciones para las aplicaciones contribuyentes en Django 1.8, las tablas de estos modelos de usuario personalizados de prueba ya no se crean más, lo que los hace inutilizables en un contexto de pruebas.

La inscripción de aplicaciones ya no se auto-población cuando desempaqueta modelos fuera de Django

La inscripción de aplicaciones ya no se auto-población cuando desempaqueta modelos. Esto se agregó en Django 1.7.2 como intento de permitir el desempaquetado de modelos fuera de Django, como en un trabajador RQ, sin llamar a django.setup(), pero crea la posibilidad de un bloqueo. Para adaptar tu código en el caso de RQ, puedes proporcionar tu propio script de trabajador que llama a django.setup().

Se eliminó la comprobación de asignación nula para campos de clave foránea no nulos

En versiones antiguas, asignar None a una ForeignKey o OneToOneField no nulo levantaba un ValueError('Cannot assign None: "model.field" does not allow null values.'). Para consistencia con otros campos de modelo que no tienen una comprobación similar, esta comprobación se elimina.

Se eliminaron los hashers de contraseña débiles de la configuración PASSWORD_HASHERS predeterminada por defecto

Django 0.90 almacenaba contraseñas como MD5 sin sal. Django 0.91 agregó soporte para SHA1 con sal y actualización automática de contraseñas cuando un usuario inicia sesión. Django 1.4 agregó PBKDF2 como el hashador de contraseña predeterminado.

Si tienes un proyecto de Django antiguo con contraseñas codificadas en MD5 o SHA1 (incluso salteadas), ten en cuenta que estas pueden ser fácilmente descifradas con la actualización del hardware. Para hacer que los usuarios de Django reconozcan el uso continuado de hashers débiles, se eliminan los siguientes hashers de la configuración PASSWORD_HASHERS predeterminada:

  • django.contrib.auth.hashers.SHA1PasswordHasher

  • django.contrib.auth.hashers.MD5PasswordHasher

  • django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher

  • django.contrib.auth.hashers.UnsaltedMD5PasswordHasher

  • django.contrib.auth.hashers.CryptPasswordHasher

Consider using a wrapped password hasher to strengthen the hashes in your base de datos. Si eso no es posible, agrega la configuración PASSWORD_HASHERS a tu proyecto y vuelve a agregar cualquier algoritmo de hash que necesites.

Puedes comprobar si tu base de datos tiene alguno de los algoritmos de hash eliminados de esta manera:

from django.contrib.auth import get_user_model

User = get_user_model()

# Unsalted MD5/SHA1:
User.objects.filter(password__startswith="md5$$")
User.objects.filter(password__startswith="sha1$$")
# Salted MD5/SHA1:
User.objects.filter(password__startswith="md5$").exclude(password__startswith="md5$$")
User.objects.filter(password__startswith="sha1$").exclude(password__startswith="sha1$$")
# Crypt hasher:
User.objects.filter(password__startswith="crypt$$")

from django.db.models import CharField
from django.db.models.functions import Length

CharField.register_lookup(Length)
# Unsalted MD5 passwords might not have an 'md5$$' prefix:
User.objects.filter(password__length=32)

Los métodos Field.get_prep_lookup() y Field.get_db_prep_lookup() están eliminados

Si tienes un campo personalizado que implementa cualquiera de estos métodos, regístrate una búsqueda personalizada para él. Por ejemplo:

from django.db.models import Field
from django.db.models.lookups import Exact


class MyField(Field): ...


class MyFieldExact(Exact):
    def get_prep_lookup(self):
        # do_custom_stuff_for_myfield
        ...


MyField.register_lookup(MyFieldExact)

django.contrib.gis

  • Se ha dejado de soportar SpatiaLite < 3.0 y GEOS < 3.3.

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

  • En Oracle/GIS, la función agregada Area ahora devuelve un float en lugar de decimal.Decimal. (Aún está envuelto en una medida de metros cuadrados.)

  • La representación por defecto (GEOSGeometry) del GEOSGeometry (salida WKT) se elimina por defecto. Es decir, en lugar de POINT (23.0000000000000000 5.5000000000000000), obtendrás POINT (23 5.5).

El tamaño máximo del cuerpo de una solicitud y el número de parámetros GET/POST se limita

Dos nuevos ajustes ayudan a mitigar ataques de denegación de servicio mediante solicitudes grandes:

Las aplicaciones que reciben formularios POST grandes pueden necesitar ajustar estos ajustes.

Miscelánea

  • La repr() de un conjunto de consultas (django.db.models.QuerySet) está envuelto en <QuerySet > para desambiguarlo de una lista plana cuando se depura.

  • utils.version.get_version() devuelve versiones de candidato a liberación (PEP 440) compatibles (por ejemplo, “1.10rc1” en lugar de “1.10c1”).

  • Los valores de los tokens CSRF deben ser ahora cadenas de 64 alfanuméricos; se reemplazan automáticamente por cadenas de 64 caracteres los valores de 32 alfanuméricos, tal como lo establecían las versiones antiguas de Django por defecto. Los demás valores son considerados inválidos. Esto solo debería afectar a desarrolladores o usuarios que reemplacen estos tokens.

  • La configuración LOGOUT_URL se ha eliminado ya que Django no la ha utilizado desde antes de la versión 1.0. Si lo utilizas en tu proyecto, puedes agregarlo a las configuraciones de tu proyecto. El valor por defecto era '/accounts/logout/'.

  • Objetos con un método close() como archivos y generadores pasados a HttpResponse se cierran inmediatamente en lugar de cuando el servidor WSGI llama a close() sobre la respuesta.

  • Se ha eliminado la llamada redundante a transaction.atomic() en QuerySet.update_or_create(). Esto puede afectar al recuento de consultas que se prueban con TransactionTestCase.assertNumQueries().

  • La traducción es:

  • cargar datos ahora lanza un Error de Comando en lugar de mostrar una advertencia cuando el archivo de fijación especificado no se encuentra.

  • En lugar de acceder directamente al atributo LogEntry.change_message, es mejor llamar al método LogEntry.get_change_message() que proporcionará el mensaje en el idioma actual.

  • Las vistas de errores por defecto ahora levantan TemplateDoesNotExist si se especifica un nombre de plantilla inexistente.

  • El argumento de palabra clave no utilizado choices del método render() de los widgets Select y SelectMultiple se elimina. El argumento choices del método render_options() también se elimina, haciendo que selected_choices sea el primer argumento.

  • Los textos traducidos son:

  • Los comandos de gestión integrados ahora utilizan el índice de claves en options, por ejemplo, options['verbosity'], en lugar de options.get() y ya no realizan ninguna coerción de tipo. Esto podría ser un problema si estás llamando a comandos utilizando Command.execute() (que bypassa el analizador de argumentos que establece un valor predeterminado) en lugar de call_command(). En lugar de llamar a Command.execute(), pasa la instancia del comando como primer argumento a call_command().

  • ModelBackend y RemoteUserBackend ahora rechazan a los usuarios inactivos. Esto significa que los usuarios inactivos no pueden iniciar sesión y serán desconectados si se les cambia el estado de is_active=True a False. Si necesitas el comportamiento anterior, utiliza el nuevo AllowAllUsersModelBackend o AllowAllUsersRemoteUserBackend en AUTHENTICATION_BACKENDS en lugar.

  • En consideración del cambio anterior, el método de inicio de sesión del cliente de pruebas login() ya no rechaza siempre a los usuarios inactivos sino que delega esta decisión en el backend de autenticación. El método force_login() también delega la decisión al backend de autenticación, por lo que si estás utilizando los backends predeterminados, debes utilizar un usuario activo.

  • django.views.i18n.set_language() puede devolver ahora un código de estado 204 para solicitudes AJAX.

  • La propiedad base_field de RangeField es ahora un tipo de campo, no una instancia de campo. Si has creado una clase personalizada que hereda de RangeField, debes cambiar la propiedad base_field.

  • Las clases de middleware se inician ahora cuando arranca el servidor en lugar de durante la primera solicitud.

  • Si sobreescribes is_authenticated() o is_anonymous() en un modelo de usuario personalizado, debes convertirlos a atributos o propiedades como se describe en la nota de desprecación.

  • Cuando se utiliza la propiedad ModelAdmin.save_as=True, el botón «Guardar como nuevo» ahora redirige a la vista de cambio para el nuevo objeto en lugar de a la lista de modelos. Si necesitas el comportamiento anterior, establece la nueva propiedad ModelAdmin.save_as_continue en False.

  • Los campos de formulario requeridos ahora tienen la atributo HTML required. Establece la propiedad Form.use_required_attribute en False para deshabilitarlo. También puedes agregar el atributo novalidate a <form> si no quieres que se realice la validación del navegador. Para deshabilitar el atributo required en widgets personalizados, sobreescribe el método Widget.use_required_attribute().

  • El WSGI handler ya no elimina el contenido de las respuestas de solicitudes o respuestas con un código de estado de 100-199, 204 o 304. La mayoría de los servidores web implementan ya este comportamiento. Las respuestas recuperadas utilizando el cliente de pruebas de Django siguen teniendo estas «correcciones de respuesta» aplicadas.

  • Model.__init__() ahora recibe django.db.models.DEFERIDO como valor de campos diferidos.

  • La atributo Model._deferred se ha eliminado cuando se utilizan clases dinámicas de modelo con QuerySet.defer() y only() se ha eliminado.

  • Storage.save() ya no reemplaza '\' con '/'`. Este comportamiento se ha movido a :class:`~django.core.files.storage.FileSystemStorage` ya que es un detalle de implementación específico del almacenamiento. Cualquier usuario de Windows con una implementación de almacenamiento personalizada que dependa de este comportamiento deberá implementarlo en el método ``save() de la implementación de almacenamiento personalizada.

  • Los métodos privados de FileField get_directory_name() y get_filename() ya no se llaman (y ahora están desaconsejados) lo que es un cambio incompatible hacia atrás para los usuarios que sobreescriben esos métodos en campos personalizados. Para adaptar tal código, sobrescríba FileField.generate_filename() o Storage.generate_filename() en su lugar. Es posible que puedas utilizar también upload_to.

  • El asunto de los correos electrónicos enviados por AdminEmailHandler ya no se truncan a 989 caracteres. Si contabas con una longitud limitada, trunca el asunto tú mismo.

  • Las expresiones privadas django.db.models.expressions.Date y DateTime se han eliminado. Las nuevas expresiones de función Trunc proporcionan la misma funcionalidad.

  • Los atributos _base_manager y _default_manager se han eliminado de las instancias de modelo. Siguen siendo accesibles en la clase del modelo.

  • Acceder a un campo eliminado en una instancia de modelo, por ejemplo después de del obj.field, recarga el valor del campo en lugar de levantar AttributeError.

  • Si sobrescribes AbstractBaseUser y sobreescribes clean(), asegúrate de que llame a super(). AbstractBaseUser.normalize_username() se llama en un nuevo método AbstractBaseUser.clean().

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

  • Si está instalado django.contrib.staticfiles, el etiqueta de plantilla static utiliza el almacenamiento staticfiles para construir la URL en lugar de simplemente unir el valor con STATIC_ROOT. La nueva aproximación codifica la URL, lo que podría ser incompatibilidad hacia atrás en casos como incluir un fragmento en una ruta, por ejemplo {% static 'img.svg#fragment' %}, ya que el # se codifica como %23. Para adaptarse, mueve el fragmento fuera de la etiqueta de plantilla: {% static 'img.svg' %}#fragment.

  • Cuando USE_L10N es True, ahora se aplica la localización para los filtros date y time cuando no se especifica una cadena de formato. Se utilizan en su lugar los especificadores DATE_FORMAT y TIME_FORMAT del locale activo en lugar de las configuraciones con el mismo nombre.

Características deprecadas en 1.10

Asignación directa a una clave foránea inversa o relación muchos-a-muchos

En lugar de asignar objetos relacionados mediante asignación directa:

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list

Utilice el método set() agregado en Django 1.9:

>>> e.related_set.set([obj1, obj2, obj3])

Esto evita la confusión sobre una asignación que resulte en un ahorro implícito.

API de almacenamiento no-tenazón

Los métodos antiguos, no-tenazón, accessed_time(), created_time() y modified_time() están deprecados en favor de los nuevos métodos get_*_time().

Los terceros deben implementar los nuevos métodos y marcar los antiguos como obsoletos. Hasta que no lo hagan, los nuevos métodos get_*_time() en la clase base Storage convierten las fechas de tiempo de los métodos antiguos según sea necesario y emiten un aviso de deprecación al hacerlo.

Los terceros pueden mantener los métodos antiguos siempre que deseen apoyar versiones anteriores de Django.

django.contrib.gis

  • Los métodos get_srid() y set_srid() de GEOSGeometry están obsoletos a favor de la propiedad srid.

  • Los métodos get_x(), set_x(), get_y(), set_y(), get_z() y set_z() de Point están obsoletos a favor de las propiedades x, y y z.

  • Los métodos get_coords() y set_coords() de Point están obsoletos a favor de la propiedad tuple.

  • La propiedad cascaded_union de MultiPolygon está obsoleta a favor de la propiedad unary_union.

  • La función django.contrib.gis.utils.precision_wkt() está obsoleta a favor de WKTWriter.

Campo del modelo CommaSeparatedIntegerField

CommaSeparatedIntegerField está obsoleto a favor de CharField con el validador validate_comma_separated_integer_list():

from django.core.validators import validate_comma_separated_integer_list
from django.db import models


class MyModel(models.Model):
    numbers = models.CharField(..., validators=[validate_comma_separated_integer_list])

Si estás utilizando Oracle, CharField utiliza un tipo de campo de base de datos diferente (NVARCHAR2) que CommaSeparatedIntegerField (VARCHAR2). Dependiendo de tus configuraciones de la base de datos, esto podría implicar un código de caracteres y una longitud en bytes diferentes para el mismo contenido. Si los valores almacenados son más largos que la limitación de 4000 bytes de NVARCHAR2, debes utilizar TextField (NCLOB) en su lugar. En este caso, si tienes alguna consulta que agrupe por el campo (por ejemplo, anotando el modelo con una agregación o utilizando distinct()), necesitarás cambiarlas (a diferir el campo).

Consulta de búsqueda __search

La búsqueda search, que solo admite MySQL y tiene una funcionalidad extremadamente limitada, está descontinuada. Reemplázala con una búsqueda personalizada:

from django.db import models


class Search(models.Lookup):
    lookup_name = "search"

    def as_mysql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return "MATCH (%s) AGAINST (%s IN BOOLEAN MODE)" % (lhs, rhs), params


models.CharField.register_lookup(Search)
models.TextField.register_lookup(Search)

Usando User.is_authenticated() y User.is_anonymous() como métodos

Los métodos is_authenticated() y is_anonymous() de las clases AbstractBaseUser y AnonymousUser ahora son propiedades. Aún funcionarán como métodos hasta Django 2.0, pero todo el uso en Django utiliza acceso a atributos.

Ejemplo: si utilizas AuthenticationMiddleware y deseas saber si el usuario está actualmente conectado, utilizarías:

if request.user.is_authenticated:
    ...  # Do something for logged-in users.
else:
    ...  # Do something for anonymous users.

en lugar de request.user.is_authenticated().

Esta es la traducción de los textos:

if request.user.is_authenticated:
    return sensitive_information

Si sobreescribes estos métodos en un modelo de usuario personalizado, debes cambiarlos a propiedades o atributos.

Django utiliza un objeto CallableBool para permitir que estas atributos funcionen como propiedad y método. Por lo tanto, hasta que termine el período de deprecación, no se puede comparar estas propiedades utilizando el operador is. Es decir, lo siguiente no funcionará:

if request.user.is_authenticated is True:
    ...

La «escape» mitad de django.utils.safestring

La función mark_for_escaping() y las clases que utiliza: EscapeData, EscapeBytes, EscapeText, EscapeString y EscapeUnicode están deprecadas.

Como resultado, el comportamiento «perezoso» del filtro escape (donde siempre se aplicaría como último filtro independientemente de dónde en la cadena de filtros apareciera) está deprecado. El filtro cambiará para aplicar inmediatamente conditional_escape() en Django 2.0.

Miscelánea

  • La opción makemigrations --exit está descontinuada en favor de la opción makemigrations --check.

  • django.utils.functional.allow_lazy() está descontinuado en favor del nuevo función keep_lazy() que se puede utilizar con un decorador más natural.

  • La opción shell --plain está descontinuada en favor de -i python o --interface python.

  • La importación desde el módulo django.core.urlresolvers está descontinuada en favor de su nueva ubicación, django.urls.

  • El método del contexto de plantilla Context.has_key() está descontinuado en favor de in.

  • La atributo privado virtual_fields de Model._meta está descontinuado en favor de private_fields.

  • Los argumentos de palabra clave privados virtual_only en Field.contribute_to_class() y virtual en Model._meta.add_field() están descontinuados en favor de private_only y private, respectivamente.

  • Los textos traducidos son:

  • En la herencia múltiple de tablas, la promoción implícita de un OneToOneField a un parent_link está desaconsejada. Añade parent_link=True a tales campos.

  • La API privada Widget._format_value() se hace pública y se renombra a format_value(). El nombre antiguo seguirá funcionando durante un período de desaceleración.

  • Los métodos privados del campo FileField get_directory_name() y get_filename() están desaconsejados en favor de realizar esta tarea en Storage.generate_filename().

  • Las middleware antiguas que utilizan settings.MIDDLEWARE_CLASSES están desaconsejadas. Adapta middleware antiguo y personalizado y utiliza la nueva configuración de MIDDLEWARE.

Características eliminadas en 1.10

Estas características han llegado al final de su ciclo de desaceleración y se eliminan en Django 1.10. Consulta características desaconsejadas-1.8 para obtener detalles, incluyendo cómo eliminar el uso de estas características.

  • El soporte para llamar directamente a un SQLCompiler como alias para llamar su método quote_name_unless_alias se elimina.

  • Los marcadores de plantilla cycle y firstof se eliminan del biblioteca de marcadores de plantilla future.

  • django.conf.urls.patterns() está eliminado.

  • El soporte para el argumento prefix en django.conf.urls.i18n.i18n_patterns() se ha eliminado.

  • Se ha eliminado la propiedad urls de SimpleTestCase.

  • Ahora se lanza una excepción cuando se utiliza un recuento incorrecto de valores desempaquetados en el tag de plantilla for, en lugar de fallar silenciosamente.

  • Se ha eliminado la capacidad de utilizar reverse() URLs utilizando un camino de Python punto a punto.

  • Se ha eliminado la capacidad de usar un camino de Python punto a punto para las configuraciones LOGIN_URL y LOGIN_REDIRECT_URL.

  • Se ha eliminado el soporte para optparse en comandos de gestión personalizados.

  • La clase django.core.management.NoArgsCommand se ha eliminado.

  • El módulo django.core.context_processors se ha eliminado.

  • El módulo django.db.models.sql.aggregates se ha eliminado.

  • El módulo django.contrib.gis.db.models.sql.aggregates se ha eliminado.

  • Los métodos y propiedades de django.db.sql.query.Query que se eliminan:

    • Propiedades: aggregates y aggregate_select

    • Métodos: add_aggregate, set_aggregate_mask y append_aggregate_mask.

  • Se elimina django.template.resolve_variable.

  • Las siguientes APIs privadas se eliminan de django.db.models.options.Options (Model._meta):

    • get_field_by_name()

    • get_all_field_names()

    • get_fields_with_model()

    • get_concrete_fields_with_model()

    • get_m2m_with_model()

    • get_all_related_objects()

    • get_all_related_objects_with_model()

    • get_all_related_many_to_many_objects()

    • get_all_related_m2m_objects_with_model()

  • La argumento error_message de django.forms.RegexField se ha eliminado.

  • El filtro unordered_list ya no admite listas antiguas.

  • Se ha eliminado el soporte para las cadenas view como argumentos a url().

  • La compatibilidad retrocompatible con la shim para renombrar django.forms.Form._has_changed() a has_changed() se ha eliminado.

  • El filtro de plantilla removetags se ha eliminado.

  • Las funciones remove_tags() y strip_entities() en django.utils.html se han eliminado.

  • El is_admin_site argumento a django.contrib.auth.views.password_reset() se ha eliminado.

  • django.db.models.field.subclassing.SubfieldBase se ha eliminado.

  • django.utils.checksums se ha eliminado.

  • La atributo original_content_type_id en django.contrib.admin.helpers.InlineAdminForm se ha eliminado.

  • El shim de compatibilidad hacia atrás para permitir que FormMixin.get_form() esté definido con ningún valor por defecto para su argumento form_class se ha eliminado.

  • Las siguientes configuraciones se han eliminado, y debes actualizar a la TEMPLATES configuración:

    • ALLOWED_INCLUDE_ROOTS

    • TEMPLATE_CONTEXT_PROCESSORS

    • TEMPLATE_DEBUG

    • TEMPLATE_DIRS

    • Los textos traducidos son:

    • CADENA_DE_STRINGIFICACIÓN_INVALIDA_DE_TEMPLATES

  • La compatibilidad hacia atrás con el alias django.template.loader.BaseLoader se ha eliminado.

  • Los objetos de plantilla Django devueltos por get_template() y select_template() ya no aceptan un Context en su método render() .

  • APIs de respuesta de plantilla imponen el uso de objetos de plantillas dependientes del backend y de tipo dict en lugar de Context y Template respectivamente.

  • El parámetro current_app para las siguientes funciones y clases se ha eliminado:

    • django.shortcuts.render()

    • django.template.Context()

    • django.template.RequestContext()

    • django.template.response.TemplateResponse()

  • Los textos traducidos son:

    • django.shortcuts.render()

    • django.shortcuts.render_to_response()

    • django.template.loader.render_to_string()

  • El parámetro dirs para las siguientes funciones se elimina:

    • django.template.loader.get_template()

    • django.template.loader.select_template()

    • django.shortcuts.render()

    • django.shortcuts.render_to_response()

  • La verificación de sesión está habilitada independientemente de si 'django.contrib.auth.middleware.SessionAuthenticationMiddleware' esté en MIDDLEWARE_CLASSES o no. SessionAuthenticationMiddleware ya no tiene ningún propósito y se puede eliminar de MIDDLEWARE_CLASSES. Se mantiene como stub hasta Django 2.0 por cortesía para los usuarios que no lean esta nota.

  • La propiedad privada django.db.models.Field.related se elimina.

  • La opción --list del comando de gestión migrate se elimina.

  • El marcador de plantilla ssi se elimina.

  • Los textos traducidos son:

  • Se han eliminado las compatibilidades con retroceso para permitir que Storage.get_available_name() y Storage.save() se definan sin un argumento max_length.

  • Se ha eliminado el soporte para la sintaxis legada %(<foo>)s en ModelFormMixin.success_url.

  • Los métodos agregados de GeoQuerySet collect(), extent(), extent3d(), make_line() y unionagg() se han eliminado.

  • Se ha eliminado la capacidad de especificar ContentType.name al crear una instancia de tipo de contenido.

  • Se ha eliminado el soporte para la antigua firma de allow_migrate.

  • Se ha eliminado el soporte para la sintaxis de {% cycle %} que utiliza argumentos separados por comas.

  • La advertencia que Signer emitía cuando se le daba un separador inválido ahora es un ValueError.