Django 4.0 release notes

December 7, 2021

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

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

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

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

Django 4.0 поддерживает Python 3.8, 3.9 и 3.10. Мы настоятельно рекомендуем и официально поддерживаем только последний выпуск каждой серии.

Серия Django 3.2.x является последней, поддерживающей Python 3.6 и 3.7.

Что нового в Django 4.0

zoneinfo реализация часового пояса по умолчанию

zoneinfo из стандартной библиотеки Python теперь является реализацией часового пояса по умолчанию в Django.

Это следующий шаг в переходе от использования pytz к использованию zoneinfo. В Django 3.2 разрешено использование не``pytz`` часовых поясов. Django 4.0 делает zoneinfo реализацией по умолчанию. Поддержка pytz теперь устарела и будет удалена в Django 5.0.

zoneinfo является частью стандартной библиотеки Python, начиная с Python 3.9. Пакет backports.zoneinfo автоматически устанавливается вместе с Django, если вы используете Python 3.8.

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

Однако, если вы работаете с часовыми поясами, отличными от UTC, и используете API pytz normalize() и localize(), возможно, с настройкой TIME_ZONE, вам придется провести аудит вашего кода, поскольку pytz и zoneinfo не совсем эквивалентны.

Чтобы дать время для такого аудита, переходная настройка USE_DEPRECATED_PYTZ позволяет продолжать использовать pytz во время цикла выпуска 4.x. Эта настройка будет удалена в Django 5.0.

Кроме того, пакет pytz_deprecation_shim, созданный автором zoneinfo, может быть использован для помощи в переходе с pytz. В этом пакете содержатся прокладки, которые помогут вам безопасно удалить pytz, а также подробный migration guide, показывающий, как перейти на новые API zoneinfo.

Использование pytz_deprecation_shim и переходной настройки USE_DEPRECATED_PYTZ рекомендуется, если вам нужен постепенный путь обновления.

Функциональные уникальные ограничения

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

from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import Lower


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

    class Meta:
        constraints = [
            UniqueConstraint(
                Lower('first_name'),
                Lower('last_name').desc(),
                name='first_last_name_unique',
            ),
        ]

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

scrypt хешер пароля

Новый scrypt password hasher является более безопасным и рекомендуется вместо PBKDF2. Однако он не используется по умолчанию, так как требует OpenSSL 1.1+ и больше памяти.

Бэкэнд кэша Redis

Новый бэкенд кэша django.core.cache.backends.redis.RedisCache обеспечивает встроенную поддержку кэширования с помощью Redis. Требуется версия redis-py 3.0.0 или выше. Более подробную информацию см. в разделе documentation on caching with Redis in Django.

Рендеринг форм на основе шаблонов

Forms, Formsets, and ErrorList are now rendered using the template engine to enhance customization. See the new render(), get_context(), and template_name for Form and formset rendering for Formset.

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

django.contrib.admin

  • В шаблоне admin/base.html теперь есть новый блок header, который содержит заголовок сайта администратора.
  • Новый метод ModelAdmin.get_formset_kwargs() позволяет настраивать аргументы ключевых слов, передаваемых в конструктор набора форм.
  • На боковой панели навигации теперь есть панель инструментов быстрого фильтра.
  • Новая контекстная переменная model, которая содержит класс модели для каждой модели, добавляется в метод AdminSite.each_context().
  • Новый атрибут ModelAdmin.search_help_text позволяет задать описательный текст для окна поиска.
  • Атрибут InlineModelAdmin.verbose_name_plural теперь возвращается к InlineModelAdmin.verbose_name + 's'.
  • jQuery обновлен с версии 3.5.1 до 3.6.0.

django.contrib.admindocs

  • Модуль admindocs теперь позволяет использовать эзотерические установки, в которых ROOT_URLCONF не является строкой.
  • В разделе модели admindocs теперь отображаются кэшированные свойства.

django.contrib.auth

  • Количество итераций по умолчанию для хешера паролей PBKDF2 увеличено с 260 000 до 320 000.
  • Новый атрибут LoginView.next_page и метод get_default_redirect_url() позволяют настроить перенаправление после входа в систему.

django.contrib.gis

  • Добавлена поддержка SpatiaLite 5.
  • GDALRaster теперь позволяет создавать растры в любой виртуальной файловой системе GDAL.
  • Новый класс GISModelAdmin позволяет настраивать виджет, используемый для GeometryField. Его рекомендуется использовать вместо устаревших GeoModelAdmin и OSMGeoAdmin.

django.contrib.postgres

  • Бэкенд PostgreSQL теперь поддерживает подключение по имени сервиса. Более подробную информацию см. в разделе Настройки подключения к PostgreSQL.
  • Новая операция AddConstraintNotValid позволяет создавать проверочные ограничения в PostgreSQL без проверки того, что все существующие строки удовлетворяют новому ограничению.
  • Новая операция ValidateConstraint позволяет проверять контрольные ограничения, которые были созданы с помощью AddConstraintNotValid на PostgreSQL.
  • Новое выражение ArraySubquery() позволяет использовать подзапросы для построения списков значений в PostgreSQL.
  • Новый поиск trigram_word_similar, а также выражения TrigramWordDistance() и TrigramWordSimilarity() позволяют использовать триграммное сходство слов.

django.contrib.staticfiles

  • ManifestStaticFilesStorage теперь заменяет пути к ссылкам на карту источников JavaScript их хэшированными аналогами.
  • Новый аргумент manifest_storage из ManifestFilesMixin и ManifestStaticFilesStorage позволяет настроить хранение файла манифеста.

Кэш

  • Новый async API для django.core.cache.backends.base.BaseCache начинает процесс обеспечения асинхронной совместимости бэкендов кэша. Все новые методы async имеют имена с префиксом a, например aadd(), aget(), aset(), aget_or_set() или adelete_many().

    В дальнейшем префикс a будет использоваться для асинхронных вариантов методов в целом.

CSRF

  • Защита от CSRF теперь учитывает заголовок Origin, если он присутствует. Для облегчения этого требуется установка some changes к CSRF_TRUSTED_ORIGINS.

Формы

  • ModelChoiceField теперь включает предоставленное значение в аргумент params поднятого ValidationError для сообщения об ошибке invalid_choice. Это позволяет пользовательским сообщениям об ошибках использовать заполнитель %(value)s.
  • BaseFormSet теперь отображает ошибки, не относящиеся к форме, с дополнительным классом nonform, чтобы помочь отличить их от ошибок, специфичных для формы.
  • BaseFormSet теперь позволяет настроить виджет, используемый при удалении форм через can_delete путем установки атрибута deletion_widget или переопределения метода get_deletion_widget().

Интернационализация

  • Добавлена поддержка и переводы для малайского языка.

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

  • DeleteView теперь использует FormMixin, позволяя вам предоставить подкласс Form, например, с флажком для подтверждения удаления. Кроме того, это позволяет DeleteView функционировать с django.contrib.messages.views.SuccessMessageMixin.

    В соответствии с FormMixin, удаление объектов для POST-запросов обрабатывается в form_valid(). Пользовательская логика удаления в обработчиках delete() должна быть перенесена в form_valid(), или в общий вспомогательный метод, по мере необходимости.

Ведение журнала

  • Псевдоним базы данных, используемый в вызове SQL, теперь передается в качестве дополнительного контекста вместе с каждым сообщением в регистратор django.db.backends.

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

  • Команда управления runserver теперь поддерживает опцию --skip-checks.
  • В PostgreSQL, dbshell теперь поддерживает указание файла пароля.
  • Команда shell теперь уважает sys.__interactivehook__ при запуске. Это позволяет загружать историю оболочки между интерактивными сеансами. Как следствие, readline больше не загружается при работе в изолированном режиме.
  • Новый атрибут BaseCommand.suppressed_base_arguments позволяет подавить неподдерживаемые параметры команды по умолчанию в выводе справки.
  • Новые опции startapp --exclude и startproject --exclude позволяют исключить каталоги из шаблона.

Модели

  • Новый метод QuerySet.contains(obj) возвращает, содержит ли кверисет заданный объект. При этом делается попытка выполнить запрос наиболее простым и быстрым способом.
  • Новый аргумент precision функции базы данных Round() позволяет указать количество десятичных знаков после округления.
  • QuerySet.bulk_create() теперь устанавливает первичный ключ для объектов при использовании SQLite 3.35+.
  • DurationField теперь поддерживает умножение и деление на скалярные значения в SQLite.
  • QuerySet.bulk_update() теперь возвращает количество обновленных объектов.
  • Новый атрибут Expression.empty_result_set_value позволяет указать значение, возвращаемое при использовании функции над пустым набором результатов.
  • Аргумент skip_locked в QuerySet.select_for_update() теперь разрешен в MariaDB 10.6+.
  • Выражения Lookup теперь можно использовать в аннотациях QuerySet, агрегатах и непосредственно в фильтрах.
  • Новый аргумент default для встроенных агрегатов позволяет указать значение, которое будет возвращено, когда кверисет (или группировка) не содержит записей, вместо None.

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

  • SecurityMiddleware теперь добавляет заголовок Cross-Origin Opener Policy со значением 'same-origin', чтобы предотвратить совместное использование контекста просмотра кросс-оригинальных всплывающих окон. Вы можете предотвратить добавление этого заголовка, установив для параметра SECURE_CROSS_ORIGIN_OPENER_POLICY значение None.

Сигналы

  • Новый аргумент stdout для сигналов pre_migrate() и post_migrate() позволяет перенаправить вывод на потокоподобный объект. Его следует предпочесть sys.stdout и print() при выдаче подробного вывода, чтобы обеспечить надлежащий захват при тестировании.

Шаблоны

  • Фильтр шаблонов floatformat теперь позволяет использовать суффикс u для принудительного отключения локализации.

Тесты

  • Новый аргумент serialized_aliases в django.test.utils.setup_databases() определяет, какие тестовые базы данных псевдонимов DATABASES должны иметь сериализованное состояние, чтобы можно было использовать функцию serialized_rollback.
  • Бегунок тестирования Django теперь поддерживает опцию --buffer при параллельных тестах.
  • Новый аргумент logger в DiscoverRunner позволяет использовать для протоколирования Python logger.
  • Новый метод DiscoverRunner.log() предоставляет способ регистрации сообщений, который использует DiscoverRunner.logger, или печатает на консоль, если не установлен.
  • Бегунок тестирования Django теперь поддерживает опцию --shuffle для выполнения тестов в случайном порядке.
  • Опция test --parallel теперь поддерживает значение auto для запуска одного процесса тестирования для каждого ядра процессора.
  • TestCase.captureOnCommitCallbacks() теперь перехватывает новые обратные вызовы, добавленные во время выполнения обратных вызовов transaction.on_commit().

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

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

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

  • Методы DatabaseOperations.year_lookup_bounds_for_date_field() и year_lookup_bounds_for_datetime_field() теперь принимают необязательный аргумент iso_year, чтобы поддерживать границы для лет с нумерацией недель ISO-8601.
  • Вторым аргументом методов DatabaseSchemaEditor._unique_sql() и _create_unique_sql() теперь является fields вместо columns.

django.contrib.gis

  • Удалена поддержка PostGIS 2.3.
  • Удалена поддержка GDAL 2.0 и GEOS 3.5.

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

Поддержка PostgreSQL 9.6 заканчивается в ноябре 2021 года. Django 4.0 поддерживает PostgreSQL 10 и выше.

Также минимальная поддерживаемая версия psycopg2 увеличена с 2.5.4 до 2.8.4, поскольку psycopg2 2.8.4 является первым релизом, поддерживающим Python 3.8.

Прекращена поддержка Oracle 12.2 и 18c

Поддержка Oracle 12.2 заканчивается в марте 2022 года, а Oracle 18c - в июне 2021 года. Django 3.2 будет поддерживаться до апреля 2024 года. Django 4.0 официально поддерживает Oracle 19c.

CSRF_TRUSTED_ORIGINS изменения

Изменение формата

Значения в параметре CSRF_TRUSTED_ORIGINS должны включать схему (например, 'http://' или 'https://'), а не только имя хоста.

Кроме того, значения, начинающиеся с точки, теперь должны содержать звездочку перед точкой. Например, измените '.example.com' на 'https://*.example.com'.

Проверка системы обнаруживает все необходимые изменения.

Настройка может потребоваться

Поскольку защита от CSRF теперь использует заголовок Origin, вам может понадобиться установить CSRF_TRUSTED_ORIGINS, особенно если вы разрешаете запросы с поддоменов, установив CSRF_COOKIE_DOMAIN (или SESSION_COOKIE_DOMAIN, если включено CSRF_USE_SESSIONS) на значение, начинающееся с точки.

SecurityMiddleware больше не устанавливает заголовок X-XSS-Protection

SecurityMiddleware больше не устанавливает заголовок X-XSS-Protection, если параметром SECURE_BROWSER_XSS_FILTER является True. Настройка удаляется.

Большинство современных браузеров не соблюдают HTTP-заголовок X-XSS-Protection. Вместо этого вы можете использовать Content-Security-Policy без разрешения 'unsafe-inline' скриптов.

Если вы хотите поддерживать устаревшие браузеры и установить заголовок, используйте эту строку в пользовательском промежуточном ПО:

response.headers.setdefault('X-XSS-Protection', '1; mode=block')

Изменения в автодетекторе миграции

Автоопределитель миграций теперь использует состояния модели вместо классов модели. Также операции миграции для полей ForeignKey и ManyToManyField больше не указывают атрибуты, которые не были переданы полям при инициализации.

В качестве побочного эффекта, выполнение makemigrations в некоторых случаях может генерировать безоперационные операции AlterField для полей ManyToManyField и ForeignKey.

DeleteView изменения

DeleteView теперь использует FormMixin для обработки POST-запросов. Как следствие, любая пользовательская логика удаления в обработчиках delete() должна быть перенесена в form_valid(), или в общий вспомогательный метод, если это необходимо.

Изменения схемы именования таблиц и столбцов в Oracle

Django 4.0 непреднамеренно изменил схему именования таблиц и столбцов в Oracle. Это вызывает ошибки для моделей и полей с именами длиннее 30 символов. К сожалению, требуется переименование некоторых таблиц и столбцов Oracle. Используйте скрипт обновления в 33789 для генерации операторов RENAME для изменения схемы именования.

Разное

  • Удалена поддержка cx_Oracle < 7.0.
  • Чтобы позволить обслуживать сайт Django на подпути без изменения значения STATIC_URL, в шаблоне по умолчанию 'static/' из этого параметра (теперь startproject) удалена ведущая косая черта.
  • Метод AdminSite для представления администратора index больше не украшается never_cache при прямом обращении, а не через рекомендуемое свойство AdminSite.urls или метод AdminSite.get_urls().
  • Неподдерживаемые операции над нарезанным кверисетом теперь вызывают ошибку TypeError вместо AssertionError.
  • Недокументированная функция django.test.runner.reorder_suite() переименована в reorder_tests(). Теперь она принимает итератор тестов, а не набор тестов, и возвращает итератор тестов.
  • Вызов FileSystemStorage.delete() с пустым name теперь повышает ValueError вместо AssertionError.
  • Вызов EmailMultiAlternatives.attach_alternative() или EmailMessage.attach() с недопустимыми аргументами content или mimetype теперь вызывает ValueError вместо AssertionError.
  • assertHTMLEqual() больше не считает небулевый атрибут без значения равным атрибуту с тем же именем и значением.
  • Тесты, которые не загружаются, например, из-за синтаксических ошибок, теперь всегда совпадают при использовании test --tag.
  • Недокументированная функция django.contrib.admin.utils.lookup_needs_distinct() переименована в lookup_spawns_duplicates().
  • Недокументированный метод HttpRequest.get_raw_uri() удален. Метод HttpRequest.build_absolute_uri() может быть подходящей альтернативой.
  • Аргумент object недокументированных методов ModelAdmin.log_addition(), log_change() и log_deletion() переименован в obj.
  • RssFeed, Atom1Feed и их подклассы теперь выдают элементы без содержимого как самозакрывающиеся теги.
  • NodeList.render() больше не приводит вывод метода render() для отдельных узлов к строке. Node.render() всегда должен возвращать строку, как это задокументировано.
  • Свойство where_class у django.db.models.sql.query.Query и аргумент where_class у метода private get_extra_restriction() у ForeignObject и ForeignObjectRel удаляются. Если необходимо, инициализируйте django.db.models.sql.where.WhereNode вместо этого.
  • Аргумент filter_clause недокументированного метода Query.add_filter() заменен двумя позиционными аргументами filter_lhs и filter_rhs.
  • CsrfViewMiddleware теперь использует request.META['CSRF_COOKIE_NEEDS_UPDATE'] вместо request.META['CSRF_COOKIE_USED'], request.csrf_cookie_needs_reset и response.csrf_cookie_set для отслеживания необходимости отправки CSRF cookie. Это недокументированный, частный API.
  • Недокументированная константа TRANSLATOR_COMMENT_MARK перенесена из django.template.base в django.utils.translation.template.
  • Аргумент real_apps недокументированного метода django.db.migrations.state.ProjectState.__init__() теперь должен быть множеством, если он указан.
  • Виджеты RadioSelect и CheckboxSelectMultiple теперь отображаются в тегах <div>, поэтому они более лаконично объявляются программами чтения с экрана. Если вам нужно прежнее поведение, override the widget template с соответствующим шаблоном из Django 3.2.
  • Фильтр шаблонов floatformat больше не зависит от настройки USE_L10N и всегда возвращает локализованный вывод. Для отключения локализации используйте суффикс u.
  • Значение по умолчанию параметра USE_L10N изменяется на True. Более подробную информацию см. в разделе Localization section выше.
  • Как часть move to zoneinfo, django.utils.timezone.utc изменяется на псевдоним datetime.timezone.utc.
  • Минимальная поддерживаемая версия asgiref увеличена с 3.3.2 до 3.4.1.

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

Использование часовых поясов pytz

В рамках move to zoneinfo использование часовых поясов pytz устарело.

Соответственно, аргументы is_dst для следующих аргументов также устарели:

Поддержка использования pytz будет удалена в Django 5.0.

Поддержка часовых поясов

Чтобы следовать хорошей практике, в Django 5.0 значение параметра USE_TZ по умолчанию изменится с False на True, а поддержка часовых поясов будет включена по умолчанию.

Обратите внимание, что файл settings.py, создаваемый по умолчанию django-admin startproject, включает USE_TZ = True начиная с Django 1.4.

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

Локализация

Для того чтобы следовать хорошей практике, значение по умолчанию параметра USE_L10N изменено с False на True.

Более того, USE_L10N устарело с этого релиза. Начиная с Django 5.0, по умолчанию, любая дата или число, отображаемые Django, будут локализованы.

Тег {% localize %} и фильтры localize/ unlocalize будут по-прежнему соблюдаться Django.

Разное

  • Настройка теста SERIALIZE устарела, поскольку она может быть выведена из databases при включенной опции serialized_rollback.
  • Недокументированный модуль django.utils.baseconv является устаревшим.
  • Недокументированный модуль django.utils.datetime_safe является устаревшим.
  • В Django 5.0 протокол по умолчанию для карт сайта, построенных вне контекста запроса, изменится с 'http' на 'https'.
  • Аргумент extra_tests для DiscoverRunner.build_suite() и DiscoverRunner.run_tests() устарел.
  • Агрегаты ArrayAgg, JSONBAgg и StringAgg будут возвращать None при отсутствии строк вместо [], [] и '' соответственно в Django 5.0. Если вам нужно предыдущее поведение, явно установите default в Value([]), Value('[]') или Value('').
  • Классы django.contrib.gis.admin.GeoModelAdmin и OSMGeoAdmin устарели. Вместо них используйте ModelAdmin и GISModelAdmin.
  • Поскольку рендеринг формы теперь использует шаблонизатор, недокументированный вспомогательный метод BaseForm._html_output() устарел.
  • Возможность возвращать str из ErrorList и ErrorDict устарела. Ожидается, что эти методы будут возвращать SafeString.

Функции, удаленные в версии 4.0

Эти функции достигли конца своего цикла устаревания и будут удалены в Django 4.0.

Подробнее об этих изменениях, в том числе о том, как удалить использование этих функций, смотрите Функции, устаревшие в версии 3.0.

  • django.utils.http.urlquote(), urlquote_plus(), urlunquote() и urlunquote_plus() удаляются.
  • django.utils.encoding.force_text() и smart_text() удаляются.
  • django.utils.translation.ugettext(), ugettext_lazy(), ugettext_noop(), ungettext() и ungettext_lazy() удаляются.
  • django.views.i18n.set_language() не устанавливает язык пользователя в request.session (клавиша _language).
  • alias=None требуется в сигнатуре подклассов django.db.models.Expression.get_group_by_cols().
  • django.utils.text.unescape_entities() удаляется.
  • django.utils.http.is_safe_url() удаляется.

Подробнее об этих изменениях, в том числе о том, как удалить использование этих функций, смотрите Функции, устаревшие в версии 3.1.

  • Настройка PASSWORD_RESET_TIMEOUT_DAYS удаляется.
  • Поиск isnull больше не позволяет использовать в качестве правой части небулевые значения.
  • Класс исключений django.db.models.query_utils.InvalidQuery удален.
  • Точка входа django-admin.py удаляется.
  • Метод HttpRequest.is_ajax() удален.
  • Удалена поддержка формата кодировки значений cookies, существовавшего до версии Django 3.1 и использовавшегося django.contrib.messages.storage.cookie.CookieStorage.
  • Удалена поддержка токенов для сброса пароля в админке до версии Django 3.1 (которые используют алгоритм хэширования SHA-1).
  • Удалена поддержка формата кодировки сессий, существовавшего до версии Django 3.1.
  • Удалена поддержка подписей django.core.signing.Signer, существовавших до версии Django 3.1 (закодированных с помощью алгоритма SHA-1).
  • Убрана поддержка подписей django.core.signing.dumps(), существовавших до версии Django 3.1 (закодированных алгоритмом SHA-1) в django.core.signing.loads().
  • Удалена поддержка пользовательских сессий, существовавших до версии Django 3.1 (которые используют алгоритм SHA-1).
  • Аргумент get_response для django.utils.deprecation.MiddlewareMixin.__init__() является обязательным и не принимает None.
  • Аргумент providing_args для django.dispatch.Signal удаляется.
  • Аргумент length для django.utils.crypto.get_random_string() является обязательным.
  • Сообщение list для ModelMultipleChoiceField удалено.
  • Поддержка передачи необработанных псевдонимов столбцов в QuerySet.order_by() удалена.
  • Поле модели NullBooleanField удалено, за исключением поддержки в исторических миграциях.
  • django.conf.urls.url() удаляется.
  • Поле модели django.contrib.postgres.fields.JSONField удалено, за исключением поддержки в исторических миграциях.
  • django.contrib.postgres.fields.jsonb.KeyTransform и django.contrib.postgres.fields.jsonb.KeyTextTransform удаляются.
  • django.contrib.postgres.forms.JSONField удаляется.
  • Теги шаблонов {% ifequal %} и {% ifnotequal %} удалены.
  • Переходная настройка DEFAULT_HASHING_ALGORITHM удалена.
Вернуться на верх