Примечания к выпуску Django 4.0

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 и ErrorList теперь отображаются с использованием шаблонизатора для улучшения настройки. Смотрите новые render(), get_context() и template_name для Form и formset rendering для 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 удалена.
Вернуться на верх