Django 2.1 notas de lanzamiento

1 de agosto de 2018

Bienvenido a Django 2.1!

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

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 2.1 admite Python 3.5, 3.6 y 3.7. Django 2.0 es la última versión que admite Python 3.4. Recomendamos y solo oficialmente apoyamos la última versión de cada serie.

¿Qué hay de nuevo en Django 2.1

Permiso de «vista» del modelo

Se agrega un permiso de «vista» al modelo Meta.default_permissions. Las nuevas permisos se crearán automáticamente cuando se ejecute migrate.

Esto permite dar a los usuarios acceso en solo lectura a modelos en la administración. ModelAdmin.has_view_permission() es nuevo. La implementación es compatible con versiones anteriores, ya que no hay necesidad de asignar el permiso de «vista» para permitir a los usuarios que tienen el permiso de «cambio» editar objetos.

Hay un par de consideraciones incompatibles con la versión anterior.

Características menores

django.contrib.admin

django.contrib.auth

django.contrib.gis

django.contrib.sesiones

  • Se ha agregado la SESSION_COOKIE_SAMESITE configuración para establecer la bandera de cookie SameSite en las cookies de sesión.

Cache

CSRF

  • Se ha agregado la CSRF_COOKIE_SAMESITE configuración para establecer la bandera de cookie SameSite en las cookies CSRF.

Formularios

  • El widget para ImageField ahora renderiza con el atributo HTML accept="image/*".

Internacionalización

  • Se ha agregado la get_supported_language_variant() función.

  • Las cadenas no traducidas para variantes de idioma territorial ahora utilizan las traducciones del idioma genérico. Por ejemplo, las cadenas pt_BR no traducidas utilizan traducciones de pt.

Comandos de Gestión

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

  • La clase BaseCommand ahora utiliza un formateador personalizado de ayuda, por lo que las opciones estándar como --verbosity o --settings aparecen al final en la salida de ayuda, dando una posición más prominente a las opciones de comandos subclaseados.

Migraciones

  • Se ha agregado soporte para serialización de objetos partialmethod.

  • Para apoyar entornos congelados, las migraciones pueden cargarse desde archivos .pyc.

Modelos

  • Los modelos ahora pueden utilizar PEP 487 __init_subclass__().

  • Un campo de tipo binario (BinaryField) puede configurarse como editable=True si deseas incluirlo en formularios de modelo.

  • Se han agregado una serie de nuevas funciones para bases de datos de texto: Chr, Left, LPad, LTrim, Ord, Repeat, Replace, Right, RPad, RTrim y Trim.

  • La nueva función TruncWeek truncará a la primera semana de una semana las fechas DateField y DateTimeField.

  • Las expresiones de consulta ahora pueden ser negadas utilizando un signo menos.

  • La propiedad QuerySet.order_by() y distinct(*fields) ahora admiten el uso de transformaciones de campos.

  • BooleanField puede ahora ser null=True. Se recomienda en lugar de NullBooleanField, que probablemente será descontinuado en el futuro.

  • La nueva QuerySet.explain() método muestra el plan de ejecución del servidor de base de datos de la consulta de un conjunto de consultas.

  • QuerySet.raw() ahora admite prefetch_related().

Solicitudes y respuestas

  • Se ha agregado el método HttpRequest.get_full_path_info().

  • Se ha agregado la argumento samesite a HttpResponse.set_cookie() para permitir establecer la bandera de cookie SameSite.

  • El nuevo argumento as_attachment para FileResponse configura el encabezado Content-Disposition para que el navegador pregunte si el usuario quiere descargar el archivo. FileResponse también intenta configurar los encabezados Content-Type y Content-Length donde corresponda.

Plantillas

  • El nuevo json_script filtro imprime de manera segura un objeto Python como JSON, envuelto en una etiqueta <script>, listo para su uso con JavaScript.

Pruebas

  • Se ha agregado soporte de prueba a los redirects 307 y 308 para el cliente de pruebas Client.

  • El cliente de pruebas Client ahora serializa un diccionario de datos de solicitud como JSON si content_type='application/json'. Puedes personalizar el codificador JSON con el parámetro json_encoder del cliente de pruebas.

  • El nuevo método SimpleTestCase.assertWarnsMessage() es una versión más simple de assertWarnsRegex().

Los cambios incompatibles con la versión anterior en 2.1 son los siguientes:

Backend de base de datos API

Esta es la traducción de los textos:

  • Para cumplir con PEP 249, las excepciones donde una base de datos no admite un determinado feature se cambian desde NotImplementedError a django.db.NotSupportedError.

  • Se renombró la bandera de característica de base de datos allow_sliced_subqueries a allow_sliced_subqueries_with_in.

  • DatabaseOperations.distinct_sql() ahora requiere un argumento adicional params y devuelve una tupla de SQL y parámetros en lugar de una cadena de SQL.

  • DatabaseFeatures.introspected_boolean_field_type se cambió de método a propiedad.

django.contrib.gis

  • Se eliminó el soporte para SpatiaLite 4.0.

Se eliminó el soporte para MySQL 5.5

El final del apoyo upstream para MySQL 5.5 es diciembre de 2018. Django 2.1 admite MySQL 5.6 y superior.

Se eliminó el soporte para PostgreSQL 9.3

El final del apoyo upstream para PostgreSQL 9.3 es septiembre de 2018. Django 2.1 admite PostgreSQL 9.4 y superior.

Removed BCryptPasswordHasher del ajuste de configuración por defecto PASSWORD_HASHERS

Si utilizaste bcrypt con Django 1.4 o 1.5 (antes de que se agregara BCryptSHA256PasswordHasher en Django 1.6), es posible que tengas algunas contraseñas que usen el hashador BCryptPasswordHasher.

Puedes comprobar si es así de la siguiente manera:

from django.contrib.auth import get_user_model

User = get_user_model()
User.objects.filter(password__startswith="bcrypt$$")

Si deseas continuar permitiendo que esas contraseñas se utilicen, deberás definir el ajuste de configuración PASSWORD_HASHERS (si no lo has hecho ya) e incluir 'django.contrib.auth.hashers.BCryptPasswordHasher'.

Movido la variable de contexto del widget wrap_label

Para solucionar la falta de <label> al utilizar RadioSelect y CheckboxSelectMultiple con MultiWidget, la variable de contexto wrap_label ahora aparece como un atributo de cada opción. Por ejemplo, en una plantilla personalizada input_option.html, cambia {% if wrap_label %} a {% if widget.wrap_label %}.

Cookies SameSite

Los cookies utilizados para django.contrib.sessions, django.contrib.messages y la protección CSRF de Django ahora establecen el flag SameSite en Lax por defecto. Los navegadores que respeten este flag no enviarán estos cookies en solicitudes cross-origin. Si dependes del comportamiento antiguo, establece los ajustes de configuración SESSION_COOKIE_SAMESITE y/o CSRF_COOKIE_SAMESITE en None.

Consideraciones para la nueva permiso «view» del modelo

Las formas personalizadas de administración deben tener en cuenta el caso de solo lectura

Con la nueva «permiso de vista», las formas administrativas personalizadas existentes pueden generar errores cuando un usuario no tiene el permiso de cambio porque la forma puede acceder a campos inexistentes. Soluciona esto sobrescribiendo ModelAdmin.get_form() y comprobando si el usuario tiene los «permisos de cambio» y devolviendo la forma por defecto si no es así:

class MyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if not self.has_change_permission(request, obj):
            return super().get_form(request, obj, **kwargs)
        return CustomForm

La nueva permiso de vista predeterminado podría permitir acceso no deseado a las vistas administrativas

Si tienes un permiso personalizado con el nombre codificado en la forma view_<modelname>, la nueva gestión del permiso de vista en la administración permitirá el acceso de vista a las páginas de lista y detalles para esos modelos. Si esto no es deseado, debes cambiar el nombre codificado de tu permiso personalizado.

Miscelánea

  • La versión mínima soportada de mysqlclient se incrementa desde 1.3.3 hasta 1.3.7.

  • Se elimina el soporte para SQLite < 3.7.15.

  • El formato de fecha del directorio Expires de Set-Cookie se cambia para seguir RFC 7231 Section 7.1.1.1 en lugar del estándar de cookies de Netscape. Los guiones presentes en fechas como Tue, 25-Dec-2018 22:26:13 GMT se eliminan. Este cambio debería ser meramente cosmético excepto quizás para navegadores anticuados que no parseen el nuevo formato.

  • Ahora allowed_hosts es un argumento requerido de la API privada django.utils.http.is_safe_url().

  • El atributo multiple renderizado por el widget SelectMultiple ahora utiliza la sintaxis booleana HTML5 en lugar de XHTML’s multiple="multiple".

  • Los widgets de formularios ya no incluyen una barra de cierre en elementos en blanco, p. ej. <br>. Esto es incompatible con XHTML, aunque algunos widgets ya utilizaban aspectos del HTML5 como atributos booleanos.

  • El valor de las opciones vacías de SelectDateWidget se cambia de 0 a una cadena vacía, lo que principalmente puede requerir algunas ajustes en los tests que comparan HTML.

  • User.has_usable_password() y la función is_password_usable() ya no devuelven False si el password es None o una cadena vacía, o si el password utiliza un algoritmo de hash que no está en la configuración PASSWORD_HASHERS. Este comportamiento no documentado era una regresión en Django 1.6 y impedía a los usuarios con tales contraseñas solicitar un reseteo de contraseña. Verifique su código para confirmar que su uso de estas APIs no depende del antiguo comportamiento.

  • Dado que las migraciones ahora se cargan desde archivos .pyc, es posible que deba eliminarlos si estás trabajando en un entorno mixto Python 2 y Python 3.

  • Usar None como valor de búsqueda para el campo JSONField de django.contrib.postgres.fields ahora coincide con los objetos que tienen la clave especificada y un valor nulo, en lugar de coincidir con los objetos que no tienen la clave.

  • La clase CSS del administrador field-box se renombró a fieldBox para evitar conflictos con el nombre dado a los campos de modelo llamados «box».

  • Dado que las plantillas actions.html, change_list_results.html, date_hierarchy.html, pagination.html, prepopulated_fields_js.html, search_form.html y submit_line.html del administrador ahora pueden ser sobrescritas por aplicación o por modelo, es posible que deba renombrar las plantillas existentes con esos nombres escritos para un propósito diferente.

  • QuerySet.raw() ahora almacena sus resultados en caché como los conjuntos de consultas regulares. Utilice iterator() si no quiere caching.

  • El método allow_relation() del router de la base de datos se llama en más casos. Los routers escritos incorrectamente pueden necesitar ser actualizados según sea necesario.

  • Las traducciones ya no se desactivan antes de ejecutar comandos de gestión. Si su comando personalizado requiere que las traducciones estén desactivadas (por ejemplo, para insertar contenido sin traducir en la base de datos), utilice el nuevo decorador @no_translations.

  • Los comandos de gestión ya no permiten las formas abreviadas de los argumentos --settings y --pythonpath.

  • La constante privada django.db.models.sql.constants.QUERY_TERMS se ha eliminado. Los métodos get_lookup() y get_lookups() de la API de registro de consultas pueden ser alternativas adecuadas. En comparación con la constante QUERY_TERMS, permiten que su código también tenga en cuenta cualquier consulta personalizada registrada.

  • La compatibilidad con py-bcrypt se ha eliminado ya que no está mantenido. Utiliza en su lugar bcrypt.

Características deprecadas en 2.1.

Miscelánea

  • La función GIS ForceRHR está deprecada a favor de la nueva función ForcePolygonCW.

  • django.utils.http.cookie_date() está deprecada a favor de http_date(), que sigue el formato del último RFC.

  • {% load staticfiles %} y {% load admin_static %} están deprecados a favor de {% load static %}, que funciona igual.

  • django.contrib.staticfiles.templatetags.static() está deprecado a favor de django.templatetags.static.static().

  • Se eliminarán los métodos InlineModelAdmin.has_add_permission() que no aceptan obj como el segundo argumento posicional en Django 3.0.

Características eliminadas en 2.1

Estas características han llegado al final de su ciclo de deprecación y se eliminan en Django 2.1. Consulte Características obsoletas en 1.11 para obtener detalles, incluyendo cómo eliminar el uso de estas características.

  • contrib.auth.views.login(), logout(), password_change(), password_change_done(), password_reset(), password_reset_done(), password_reset_confirm(), y password_reset_complete() se han eliminado.

  • El extra_context parámetro de contrib.auth.views.logout_then_login() se ha eliminado.

  • Se ha eliminado django.test.runner.setup_databases().

  • Se ha eliminado django.utils.translation.string_concat().

  • django.core.cache.backends.memcached.PyLibMCCache ya no admite la pasada de configuraciones de comportamiento de pylibmc como atributos de nivel superior de OPTIONS.

  • Se ha eliminado el parámetro host de django.utils.http.is_safe_url().

  • La silenciación de excepciones lanzadas al renderizar la plantilla de etiqueta {% include %} se ha eliminado.

  • Se ha eliminado DatabaseIntrospection.get_indexes().

  • El método authenticate() de los backends de autenticación requiere request como primer argumento posicional.

  • Se ha eliminado el decorador django.db.models.permalink().

  • La configuración USE_ETAGS se ha eliminado. CommonMiddleware y django.utils.cache.patch_response_headers() ya no establecen ETags.

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

  • Se ha eliminado el soporte para banderas inline en grupos de expresiones regulares ((?i), (?L), (?m), (?s) y (?u)) en url().

  • Se ha eliminado el soporte para métodos Widget.render() sin la argumento renderer.