Django 3.2 release notes

April 6, 2021

Добро пожаловать в Django 3.2!

Эти заметки о выпуске охватывают new features, а также некоторые backwards incompatible changes, о которых вы должны знать при переходе с Django 3.1 или более ранней версии. Мы begun the deprecation process for some features.

См. руководство Обновление Django до более новой версии, если вы обновляете существующий проект.

Django 3.2 обозначен как long-term support release. Она будет получать обновления безопасности в течение как минимум трех лет после выпуска. Поддержка предыдущей версии LTS, Django 2.2, закончится в апреле 2022 года.

Совместимость с Python

Django 3.2 supports Python 3.6, 3.7, 3.8, 3.9, and 3.10 (as of 3.2.9). We highly recommend and only officially support the latest release of each series.

Что нового в Django 3.2

Автоматическое обнаружение AppConfig

Большинство подключаемых приложений определяют AppConfig подкласс в apps.py подмодуле. Многие определяют переменную <<<2 >>>, указывающую на этот класс в своем <<<3 >>>.

Когда субмодуль apps.py существует и определяет единственный подкласс AppConfig, Django теперь использует эту конфигурацию автоматически, поэтому вы можете удалить default_app_config.

default_app_config позволил объявлять только путь приложения в INSTALLED_APPS (например, 'django.contrib.admin'), а не путь конфигурации приложения (например, 'django.contrib.admin.apps.AdminConfig'). Он был введен для обратной совместимости с первым стилем, с намерением перевести экосистему на второй, но переход не произошел.

С автоматическим обнаружением AppConfig, default_app_config больше не нужен. Как следствие, он устарел.

Подробную информацию см. в разделе Настройка приложений.

Настройка типа автоматически создаваемых первичных ключей

При определении модели, если ни одно поле в модели не определено с primary_key=True, добавляется неявный первичный ключ. Тип этого неявного первичного ключа теперь можно контролировать с помощью параметра DEFAULT_AUTO_FIELD и атрибута AppConfig.default_auto_field. Больше нет необходимости переопределять первичные ключи во всех моделях.

В соответствии с историческим поведением, значение по умолчанию для DEFAULT_AUTO_FIELD равно AutoField. Начиная с версии 3.2 новые проекты создаются с DEFAULT_AUTO_FIELD, установленным на BigAutoField. Также, новые приложения создаются с AppConfig.default_auto_field, установленным на BigAutoField. В будущем релизе Django значение по умолчанию DEFAULT_AUTO_FIELD будет изменено на BigAutoField.

Чтобы избежать нежелательных миграций в будущем, либо явно установите DEFAULT_AUTO_FIELD в AutoField:

DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

или настроить его для каждого приложения:

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.AutoField'
    name = 'my_app'

или по отдельным моделям:

from django.db import models

class MyModel(models.Model):
    id = models.AutoField(primary_key=True)

В преддверии изменения значения по умолчанию, проверка системы выдаст предупреждение, если у вас нет явной настройки для DEFAULT_AUTO_FIELD.

При изменении значения DEFAULT_AUTO_FIELD в настоящее время не могут быть созданы миграции для первичного ключа существующих автоматически создаваемых сквозных таблиц. Подробнее о миграции таких таблиц см. в документации DEFAULT_AUTO_FIELD.

Функциональные индексы

Новый позиционный аргумент *expressions Index() позволяет создавать функциональные индексы на выражениях и функциях базы данных. Например:

from django.db import models
from django.db.models import F, Index, Value
from django.db.models.functions import Lower, Upper


class MyModel(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    height = models.IntegerField()
    weight = models.IntegerField()

    class Meta:
        indexes = [
            Index(
                Lower('first_name'),
                Upper('last_name').desc(),
                name='first_last_name_idx',
            ),
            Index(
                F('height') / (F('weight') + Value(5)),
                name='calc_idx',
            ),
        ]

Функциональные индексы добавляются к моделям с помощью опции Meta.indexes.

pymemcache поддержка

Новый django.core.cache.backends.memcached.PyMemcacheCache кэш-бэкенд позволяет использовать библиотеку pymemcache для memcached. Требуется версия pymemcache 3.4.0 или выше. Для более подробной информации см. раздел documentation on caching in Django.

Новые декораторы для сайта администратора

Новый декоратор display() позволяет легко добавлять опции к пользовательским функциям отображения, которые могут использоваться с list_display или readonly_fields.

Аналогично, новый декоратор action() позволяет легко добавлять опции к функциям действия, которые могут быть использованы с actions.

Преимущество использования декоратора @display заключается в том, что теперь можно использовать декоратор @property, когда необходимо указать атрибуты пользовательского метода. До этого необходимо было использовать функцию property() после присвоения методу необходимых атрибутов.

Преимущество использования декораторов заключается в том, что эти опции более доступны для обнаружения, поскольку они могут быть предложены утилитами завершения в редакторах кода. Они являются лишь удобством и по-прежнему устанавливают те же атрибуты для функций под капотом.

Незначительные особенности

django.contrib.admin

  • ModelAdmin.search_fields теперь позволяет выполнять поиск по цитируемым фразам с пробелами.

  • Связанные поля, доступные только для чтения, теперь отображаются как ссылки с возможностью навигации, если целевые модели зарегистрированы в администраторе.

  • Админка теперь поддерживает тематическое оформление и включает темную тему, которая включается в соответствии с настройками браузера. Более подробную информацию смотрите в Поддержка программирования.

  • ModelAdmin.autocomplete_fields теперь уважает ForeignKey.to_field и ForeignKey.limit_choices_to при поиске связанной модели.

  • Теперь администратор устанавливает последнее представление, которое перенаправляет неаутентифицированных пользователей на страницу входа в систему, независимо от того, является ли URL-адрес действительным. Это защищает от потенциальной проблемы конфиденциальности перечисления моделей.

    Хотя это не рекомендуется, вы можете установить новое значение AdminSite.final_catch_all_view на False, чтобы отключить всеобъемлющее представление.

django.contrib.auth

  • Количество итераций по умолчанию для хешера паролей PBKDF2 увеличено с 216 000 до 260 000.

  • Вариант по умолчанию для хешера паролей Argon2 изменен на Argon2id. memory_cost и parallelism увеличены до 102,400 и 8 соответственно, чтобы соответствовать argon2-cffi по умолчанию.

    Увеличение memory_cost увеличивает требуемую память с 512 КБ до 100 МБ. Это все еще довольно консервативно, но может привести к проблемам в средах с ограниченным объемом памяти. В этом случае существующий хэшер можно подклассифицировать, чтобы переопределить значения по умолчанию.

  • Энтропия соли по умолчанию для хешеров паролей Argon2, MD5, PBKDF2, SHA-1 увеличена с 71 до 128 бит.

django.contrib.contenttypes

django.contrib.gis

django.contrib.postgres

  • Новый атрибут ExclusionConstraint.include позволяет создавать охватывающие ограничения исключения на PostgreSQL 12+.
  • Новый атрибут ExclusionConstraint.opclasses позволяет устанавливать классы операторов PostgreSQL.
  • Новый атрибут JSONBAgg.ordering определяет порядок следования агрегированных элементов.
  • Новый атрибут JSONBAgg.distinct определяет, будут ли агрегированные значения различаться.
  • Операция CreateExtension теперь проверяет, что расширение уже существует в базе данных, и пропускает миграцию, если это так.
  • Новые операции CreateCollation и RemoveCollation позволяют создавать и сбрасывать колляции в PostgreSQL. Более подробную информацию см. в разделе Управление коллациями с помощью миграций.
  • Поиск для ArrayField теперь позволяет использовать (не вложенные) массивы, содержащие выражения в качестве правых сторон.
  • Новое выражение OpClass() позволяет создавать функциональные индексы на выражениях с пользовательским классом оператора. Более подробную информацию смотрите в Функциональные индексы.

django.contrib.sitemaps

  • Новые атрибуты Sitemap alternates, languages и x_default позволяют генерировать альтернативные карты сайта для локализованных версий ваших страниц.

django.contrib.syndication

  • Новый хук item_comments позволяет указывать URL комментариев для каждого элемента фида.

Бэкенды баз данных

  • Сторонние бэкенды баз данных теперь могут пропускать или отмечать как ожидаемые отказы тесты в тестовом наборе Django, используя новые атрибуты DatabaseFeatures.django_test_skips и django_test_expected_failures.

Декораторы

  • Новый декоратор no_append_slash() позволяет исключить отдельные представления из нормализации URL APPEND_SLASH.

Отчеты об ошибках

Загрузка файлов

Формы

Общие представления

  • Атрибуты week_format WeekMixin и WeekArchiveView теперь поддерживают формат недели '%V' ISO 8601.

Команды управления

  • loaddata теперь поддерживает фиксы, хранящиеся в XZ архивах (.xz) и LZMA архивах (.lzma).
  • dumpdata теперь может сжимать данные в форматах bz2, gz, lzma или xz.
  • makemigrations теперь можно вызывать без активного соединения с базой данных. В этом случае проверка на наличие последовательной истории миграции пропускается.
  • BaseCommand.requires_system_checks теперь поддерживает указание списка тегов. Системные проверки, зарегистрированные в выбранных тегах, будут проверены на наличие ошибок перед выполнением команды. В предыдущих версиях выполнялись либо все, либо ни одна из системных проверок.
  • Обновлена поддержка цветного вывода терминала в Windows. Различные современные терминальные среды определяются автоматически, и улучшены опции для включения поддержки в других случаях. Более подробную информацию смотрите в Синтаксическая раскраска.

Миграции

  • Новое свойство Operation.migration_name_fragment позволяет указать фрагмент имени файла, который будет использоваться для названия миграции, содержащей только эту операцию.
  • Миграции теперь поддерживают сериализацию чистых и конкретных объектов path из экземпляров pathlib, и os.PathLike.

Модели

  • Новый параметр no_key для QuerySet.select_for_update(), поддерживаемый в PostgreSQL, позволяет приобретать более слабые блокировки, которые не блокируют создание строк, ссылающихся на заблокированные строки через внешний ключ.
  • Выражение When() теперь позволяет использовать аргумент condition с lookups.
  • Новые атрибуты Index.include и UniqueConstraint.include позволяют создавать покрывающие индексы и покрывающие уникальные ограничения на PostgreSQL 11+.
  • Новый атрибут UniqueConstraint.opclasses позволяет устанавливать классы операторов PostgreSQL.
  • Метод QuerySet.update() теперь уважает условие order_by() в MySQL и MariaDB.
  • FilteredRelation() теперь поддерживает вложенные отношения.
  • Аргумент of QuerySet.select_for_update() теперь разрешен в MySQL 8.0.1+.
  • Value() выражение теперь автоматически разрешает свой output_field в соответствующий Field подкласс на основе типа предоставленного value для :py<bool, : py<bytes, :py<float, :py<int, str, datetime.date, datetime.datetime, datetime.time, datetime.timedelta, decimal.Decimal, и uuid.UUID экземпляров. Как следствие, разрешение output_field для функций базы данных и комбинированных выражений теперь может завершиться со смешанными типами при использовании Value(). В таких случаях необходимо явно задать output_field.
  • Новый метод QuerySet.alias() позволяет создавать многократно используемые псевдонимы для выражений, которые не нужно выбирать, но используются для фильтрации, упорядочивания или как часть сложных выражений.
  • Новая функция Collate позволяет фильтровать и упорядочивать по заданным коллациям базы данных.
  • Аргумент field_name в QuerySet.in_bulk() теперь принимает разные поля, если в QuerySet.distinct() указано только одно поле.
  • Новый параметр tzinfo функций баз данных TruncDate и TruncTime позволяет усекать даты в определенном часовом поясе.
  • Новый аргумент db_collation для CharField и TextField позволяет установить коллизию базы данных для поля.
  • Добавлена функция базы данных Random.
  • Агрегационные функции, F(), OuterRef() и другие выражения теперь позволяют использовать преобразования. Подробности смотрите в Выражения могут ссылаться на преобразования.
  • Новый аргумент durable для atomic() гарантирует, что изменения, сделанные в атомарном блоке, будут зафиксированы, если блок завершится без ошибок. Вложенный атомарный блок, помеченный как долговечный, вызовет предупреждение RuntimeError.
  • Добавлена функция базы данных JSONObject.

Пагинация

  • Новый метод django.core.paginator.Paginator.get_elided_page_range() позволяет генерировать диапазон страниц с некоторыми значениями, исключенными из списка. Если имеется большое количество страниц, это может быть полезно для генерации разумного количества ссылок на страницы в шаблоне.

Запросы и ответы

  • Заголовки ответов теперь хранятся в виде HttpResponse.headers. Это можно использовать вместо оригинального диктоподобного интерфейса объектов HttpResponse. Оба интерфейса будут поддерживаться и в дальнейшем. Подробности смотрите в Настройка полей заголовка.
  • Новый параметр headers для HttpResponse, SimpleTemplateResponse и TemplateResponse позволяет установить ответ headers при инстанцировании.

Безопасность

  • Параметр SECRET_KEY теперь проверяется на действительное значение при первом доступе, а не при первой загрузке настроек. Это позволяет выполнять команды управления, которые не зависят от SECRET_KEY, без необходимости предоставлять значение. Как следствие этого, вызов configure() без предоставления действительного SECRET_KEY, а затем обращение к settings.SECRET_KEY теперь вызовет исключение ImproperlyConfigured.

  • Новые методы Signer.sign_object() и Signer.unsign_object() позволяют подписывать сложные структуры данных. Более подробную информацию см. в Защита сложных структур данных.

    Кроме того, signing.dumps() и loads() становятся сокращениями для TimestampSigner.sign_object() и unsign_object().

Сериализация

  • Новый сериализатор JSONL позволяет использовать формат JSON Lines с dumpdata и loaddata. Это может быть полезно при заполнении больших баз данных, поскольку данные загружаются в память построчно, а не все сразу.

Сигналы

Шаблоны

  • Фильтр шаблонов floatformat теперь позволяет использовать суффикс g для принудительной группировки по THOUSAND_SEPARATOR для активной локали.
  • Шаблоны, кэшированные с помощью Cached template loaders, теперь корректно перезагружаются при разработке.

Тесты

  • Объекты, назначенные атрибутам класса в TestCase.setUpTestData(), теперь изолированы для каждого метода тестирования. Такие объекты теперь необходимы для поддержки создания глубоких копий с помощью :py<<1 >>>. Присвоение объектов, которые не поддерживают copy.deepcopy(), устарело и будет удалено в Django 4.1.
  • DiscoverRunner теперь включает faulthandler по умолчанию. Это можно отключить с помощью опции test --no-faulthandler.
  • DiscoverRunner и команда управления test теперь могут отслеживать время, включая установку базы данных и общее время работы. Это можно включить с помощью опции test --timing.
  • Client теперь сохраняет строку запроса при следовании 307 и 308 редиректам.
  • Новый метод TestCase.captureOnCommitCallbacks() фиксирует функции обратного вызова, переданные в transaction.on_commit(), в виде списка. Это позволяет тестировать такие обратные вызовы без использования более медленного метода TransactionTestCase.
  • TransactionTestCase.assertQuerysetEqual() теперь поддерживает прямое сравнение с другим набором запросов, а не ограничивается сравнением со списком строковых представлений объектов при использовании значения по умолчанию для аргумента transform.

Утилиты

  • Новый параметр depth функций django.utils.timesince.timesince() и django.utils.timesince.timeuntil() позволяет указать количество смежных единиц времени для возврата.

Валидаторы

  • Встроенные валидаторы теперь включают предоставленное значение в аргумент params поднятого ValidationError. Это позволяет в пользовательских сообщениях об ошибках использовать заполнитель %(value)s.
  • Оператор равенства ValidationError теперь игнорирует упорядочивание messages и params.

Изменения в версии 3.2, несовместимые с обратными изменениями

API бэкенда базы данных

В этом разделе описаны изменения, которые могут потребоваться в бэкендах баз данных сторонних производителей.

  • Новое свойство DatabaseFeatures.introspected_field_types заменяет эти функции:
    • can_introspect_autofield
    • can_introspect_big_integer_field
    • can_introspect_binary_field
    • can_introspect_decimal_field
    • can_introspect_duration_field
    • can_introspect_ip_address_field
    • can_introspect_positive_integer_field
    • can_introspect_small_integer_field
    • can_introspect_time_field
    • introspected_big_auto_field_type
    • introspected_small_auto_field_type
    • introspected_boolean_field_type
  • Чтобы включить поддержку покрывающих индексов (Index.include) и покрывающих уникальных ограничений (UniqueConstraint.include), установите DatabaseFeatures.supports_covering_indexes на True.
  • Бэкенды баз данных сторонних производителей должны реализовать поддержку коллаций баз данных столбцов на CharFields и TextFields или установить DatabaseFeatures.supports_collation_on_charfield и DatabaseFeatures.supports_collation_on_textfield на False. Если недетерминированные колляции не поддерживаются, установите supports_non_deterministic_collations в False.
  • DatabaseOperations.random_function_sql() удаляется в пользу новой функции базы данных Random.
  • DatabaseOperations.date_trunc_sql() и DatabaseOperations.time_trunc_sql() теперь принимают необязательный аргумент tzname для усечения в определенном часовом поясе.
  • DatabaseClient.runshell() теперь из метода DatabaseClient.settings_to_cmd_args_env() получает аргументы и необязательный словарь с переменными окружения для базового клиента командной строки. Сторонние бэкенды баз данных должны реализовать DatabaseClient.settings_to_cmd_args_env() или переопределить DatabaseClient.runshell().
  • Бэкенды баз данных сторонних производителей должны реализовать поддержку функциональных индексов (Index.expressions) или установить DatabaseFeatures.supports_expression_indexes в False. Если COLLATE не является частью оператора CREATE INDEX, установите DatabaseFeatures.collate_as_index_expression в True.

django.contrib.admin

  • Ссылки пагинации в админке теперь 1-индексируются вместо 0-индексируемых, т.е. строка запроса для первой страницы ?p=1 вместо ?p=0.
  • Новое представление «catch-all» для администраторов будет нарушать шаблоны URL, направленные после URL-адресов администраторов и соответствующие префиксу URL-адреса администратора. Вы можете либо скорректировать порядок URL, либо, если необходимо, установить AdminSite.final_catch_all_view на False, отключив представление catch-all. Более подробную информацию смотрите в Что нового в Django 3.2.
  • Минифицированные файлы JavaScript больше не включаются в админку. Если вам требуется минификация этих файлов, воспользуйтесь сторонним приложением или внешним инструментом сборки. Минифицированные вендорные файлы JavaScript, упакованные с администратором (например, jquery.min.js), по-прежнему включены.
  • ModelAdmin.prepopulated_fields больше не удаляет английские стоп-слова, такие как 'a' или 'an'.

django.contrib.gis

  • Удалена поддержка PostGIS 2.2.
  • Бэкэнд Oracle теперь клонирует полигоны (и коллекции геометрии, содержащие полигоны) перед их переориентацией и сохранением в базе данных. Они больше не мутируют на месте. Вы можете заметить это, если используете полигоны после сохранения модели.

Прекращена поддержка PostgreSQL 9.5

Поддержка PostgreSQL 9.5 заканчивается в феврале 2021 года. Django 3.2 поддерживает PostgreSQL 9.6 и выше.

Прекращена поддержка MySQL 5.6

Окончание поддержки MySQL 5.6 приходится на апрель 2021 года. Django 3.2 поддерживает MySQL 5.7 и выше.

Разное

  • Django теперь поддерживает не``pytz`` часовые пояса, например, модуль zoneinfo в Python 3.9+ и его бэкпорт.

  • Недокументированный метод SpatiaLiteOperations.proj4_version() переименован в proj_version().

  • slugify() теперь удаляет ведущие и последующие тире и знаки подчеркивания.

  • Фильтры шаблонов intcomma и intword больше не зависят от настройки USE_L10N.

  • Удалена поддержка argon2-cffi < 19.1.0.

  • Ключи кэша больше не включают язык, когда интернационализация отключена (USE_I18N = False) и локализация включена (USE_L10N = True). После обновления до Django 3.2 в таких конфигурациях первый запрос к любому ранее кэшированному значению будет пропуском кэша.

  • ForeignKey.validate() теперь использует _base_manager, а не _default_manager для проверки существования связанных экземпляров.

  • Когда приложение определяет подкласс AppConfig в подмодуле apps.py, Django теперь использует эту конфигурацию автоматически, даже если она не включена с помощью default_app_config. Установите default = False в подклассе AppConfig, если вам нужно предотвратить такое поведение. Смотрите Что нового в Django 3.2 для более подробной информации.

  • Инстанцирование абстрактной модели теперь вызывает TypeError.

  • Аргументы ключевых слов в setup_databases() теперь только для ключевых слов.

  • Недокументированная функция django.utils.http.limited_parse_qsl() удалена. Вместо нее используйте urllib.parse.parse_qsl().

  • django.test.utils.TestContextDecorator теперь использует :py<addCleanup(), чтобы очистка, зарегистрированная в методе setUp(), вызывалась перед TestContextDecorator.disable().

  • SessionMiddleware теперь вызывает исключение SessionInterrupted вместо SuspiciousOperation, когда сессия уничтожается в параллельном запросе.

  • Оператор равенства django.db.models.Field теперь правильно различает наследуемые экземпляры полей в разных моделях. Кроме того, теперь определен порядок следования таких полей.

  • Недокументированная функция django.core.files.locks.lock() теперь возвращает False, если файл не может быть заблокирован, вместо того, чтобы возвращать BlockingIOError.

  • Механизм сброса пароля теперь аннулирует токены при изменении электронной почты пользователя.

  • Команда makemessages больше не обрабатывает недействительные локали, указанные с помощью опции makemessages --locale, если они содержат дефисы ('-').

  • Поле формы django.contrib.auth.forms.ReadOnlyPasswordHashField теперь по умолчанию disabled. Поэтому UserChangeForm.clean_password() больше не требуется для возврата начального значения.

  • Операции кэширования cache.get_many(), get_or_set(), has_key(), incr(), decr(), incr_version() и decr_version() теперь корректно обрабатывают None, хранящиеся в кэше, так же, как и любое другое значение, вместо того, чтобы вести себя так, как будто ключ не существует.

    Из-за ограничения python-memcached, предыдущее поведение сохраняется для устаревшего бэкенда MemcachedCache.

  • Минимальная поддерживаемая версия SQLite увеличена с 3.8.3 до 3.9.0.

  • CookieStorage теперь хранит сообщения в формате, соответствующем RFC 6265. Поддержка cookies, использующих старый формат, сохраняется до выхода Django 4.1.

  • The minimum supported version of asgiref is increased from 3.2.10 to 3.3.2.

Функции, устаревшие в версии 3.2

Разное

  • Назначение объектов, которые не поддерживают создание глубоких копий с помощью :py<<0 >>>, атрибутам класса в <<<1 >>> является устаревшим.
  • Использование булевого значения в BaseCommand.requires_system_checks устарело. Используйте '__all__' вместо True, и [] (пустой список) вместо False.
  • Аргумент whitelist и атрибут domain_whitelist в EmailValidator устарели. Используйте allowlist вместо whitelist, и domain_allowlist вместо domain_whitelist. Возможно, вам придется переименовать whitelist в существующих миграциях.
  • Переменная конфигурации приложения default_app_config устарела из-за автоматического обнаружения AppConfig. См. раздел Что нового в Django 3.2 для более подробной информации.
  • Автоматический вызов repr() на кверисете в TransactionTestCase.assertQuerysetEqual(), когда сравниваются строковые значения, является устаревшим. Если вам нужно прежнее поведение, явно установите transform в repr.
  • Бэкенд django.core.cache.backends.memcached.MemcachedCache устарел, так как python-memcached имеет некоторые проблемы и, похоже, не поддерживается. Вместо этого используйте django.core.cache.backends.memcached.PyMemcacheCache или django.core.cache.backends.memcached.PyLibMCCache.
  • Формат сообщений, используемый django.contrib.messages.storage.cookie.CookieStorage, отличается от формата, генерируемого старыми версиями Django. Поддержка старого формата сохраняется до версии Django 4.1.
Вернуться на верх