Примечания к выпуску Django 4.2¶
3 апреля 2023 г.
Добро пожаловать в Джанго 4.2!
Эти примечания к выпуску охватывают новые функции, а также некоторые обратно несовместимые изменения, о которых вам следует знать при обновлении с Django 4.1 или более ранней версии. Мы начали процесс прекращения поддержки некоторых функций.
См. руководство Обновление Django до новой версии, если вы обновляете существующий проект.
Django 4.2 обозначен как выпуск с долгосрочной поддержкой. Он будет получать обновления безопасности в течение как минимум трех лет после выпуска. Поддержка предыдущей LTS, Django 3.2, закончится в апреле 2024 года.
Совместимость версий Python¶
Django 4.2 поддерживает Python 3.8, 3.9, 3.10, 3.11 и 3.12 (начиная с версии 4.2.8). Мы настоятельно рекомендуем и официально поддерживаем только последнюю версию каждой серии.
Что нового в Джанго 4.2¶
Поддержка Псикопг 3¶
Django теперь поддерживает psycopg версии 3.1.8 или выше. Чтобы обновить код, установите библиотеку psycopg, вам не нужно менять ENGINE, поскольку django.db.backends.postgresql поддерживает обе библиотеки.
Поддержка psycopg2, скорее всего, будет прекращена и прекращена в какой-то момент в будущем.
Имейте в виду, что в psycopg 3 внесены некоторые критические изменения по сравнению с psycopg2. Как следствие, вам может потребоваться внести некоторые изменения, чтобы учесть отличия от psycopg2.
Комментарии к столбцам и таблицам¶
Новые параметры Field.db_comment и Meta.db_table_comment позволяют создавать комментарии к столбцам и таблицам соответственно. Например:
from django.db import models
class Question(models.Model):
text = models.TextField(db_comment="Poll question")
pub_date = models.DateTimeField(
db_comment="Date and time when the question was published",
)
class Meta:
db_table_comment = "Poll questions"
class Answer(models.Model):
question = models.ForeignKey(
Question,
on_delete=models.CASCADE,
db_comment="Reference to a question",
)
answer = models.TextField(db_comment="Question answer")
class Meta:
db_table_comment = "Question answers"
Кроме того, новая операция AlterModelTableComment позволяет изменять комментарии к таблице, определенные в Meta.db_table_comment.
Устранение последствий атаки BREACH¶
GZipMiddleware теперь включает средства защиты от атаки BREACH. Он добавит до 100 случайных байтов к ответам gzip, чтобы усложнить атаки BREACH. Подробнее о методе смягчения последствий читайте в статье «Исцеление нарушения (HTB)»_.
Хранение файлов в памяти¶
Новый класс django.core.files.storage.InMemoryStorage предоставляет непостоянное хранилище, полезное для ускорения тестов за счет предотвращения доступа к диску.
Пользовательские файловые хранилища¶
Новый параметр STORAGES позволяет настроить несколько пользовательских хранилищ файлов. Он также управляет механизмами хранения для управления файлами (ключ "default") и статическими файлами (ключ "staticfiles").
Старые настройки DEFAULT_FILE_STORAGE и STATICFILES_STORAGE устарели с этого выпуска.
Минорные изменения¶
django.contrib.admin¶
Светлую или темную цветовую тему администратора теперь можно переключать в пользовательском интерфейсе, а также настроить в соответствии с системными настройками.
Стек шрифтов администратора теперь отдает предпочтение шрифтам системного пользовательского интерфейса и больше не требует загрузки шрифтов. Кроме того, доступны переменные CSS, позволяющие более легко переопределить семейства шрифтов по умолчанию.
Шаблон admin/delete_confirmation.html теперь имеет несколько дополнительных блоков и скриптовых ловушек для упрощения настройки.
Выбранные параметры виджетов
filter_horizontalиfilter_verticalтеперь можно фильтровать.В шаблоне
admin/base.htmlтеперь есть новый блокnav-breadcrumbs, который содержит навигационный ориентир и блокbreadcrumbs.ModelAdmin.list_editableтеперь использует атомарные транзакции при внесении изменений.jQuery обновлен с версии 3.6.0 до 3.6.4.
django.contrib.auth¶
Число итераций по умолчанию для хэшера паролей PBKDF2 увеличено с 390 000 до 600 000.
UserCreationFormтеперь сохраняет поля формы «многие ко многим» для пользовательской модели пользователя.Новый
BaseUserCreationFormтеперь является рекомендуемым базовым классом для настройки формы создания пользователя.
django.contrib.gis¶
Сериализатор GeoJSON теперь выводит ключ
idдля сериализованных объектов, который по умолчанию равен первичному ключу объектов.Класс
GDALRasterтеперь поддерживаетpathlib.Path.Класс
GeoIP2теперь поддерживает файлы.mmdb, загруженные с DB-IP.Виджет шаблона OpenLayers больше не включает встроенный CSS (который также удаляет прежний блок «map_css»), чтобы лучше соответствовать строгой Политике безопасности контента.
OpenLayersWidgetтеперь основан на OpenLayers 7.2.2 (ранее 4.6.5).Новый поиск
isemptyи выражениеIsEmpty()позволяют фильтровать пустые геометрии в PostGIS.Новые функции
FromWKB()иFromWKT()позволяют создавать геометрии из общеизвестных двоичных (WKB) и общеизвестных текстовых (WKT) представлений.
django.contrib.postgres¶
Новый поиск
trigram_strict_word_similar, а такжеTrigramStrictWordSimilarity()иTrigramStrictWordDistance() Выраженияпозволяют использовать строгое сходство слов триграммы.Поиск
arrayfield.overlapтеперь поддерживаетQuerySet.values()иvalues_list()в качестве правой части.
django.contrib.sitemaps¶
Новый метод
Sitemap.get_languages_for_item()позволяет настроить список языков, для которых отображается элемент.
django.contrib.staticfiles¶
ManifestStaticFilesStorageтеперь имеет экспериментальную поддержку замены путей к модулям JavaScript в операторахimportиexportих хешированными аналогами. Если вы хотите попробовать, создайте подкласс ManifestStaticFilesStorage и установите для атрибута support_js_module_import_aggregation значение True.Новый атрибут
ManifestStaticFilesStorage.manifest_hashобеспечивает хэш всех файлов в манифесте и изменяется при каждом изменении одного из файлов.
Серверные базы данных¶
Новая опция
"assume_role"теперь поддерживается вOPTIONSв PostgreSQL, что позволяет указать роль сеанса.Новая опция
"server_side_binding"теперь поддерживается вOPTIONSв PostgreSQL сpsycopg3.1.8+, что позволяет использовать курсоры привязки на стороне сервера.
Отчеты об ошибках¶
На странице отладки теперь отображаются примечания к исключениям и детализированные местоположения ошибок в Python 3.11+.
Файлы cookie сеанса теперь рассматриваются как учетные данные и поэтому скрываются и заменяются звездочками («******») в отчетах об ошибках.
Формы¶
ModelFormтеперь принимает новуюMetaопциюformfield_callbackдля настройки полей формы.modelform_factory()теперь учитывает атрибут formfield_callbackMetaформы.
Интернационализация¶
Добавлена поддержка и переводы на центрально-курдский (сорани) язык.
Ведение журнала¶
Регистратор django.db.backends теперь регистрирует запросы управления транзакциями (
BEGIN,COMMITиROLLBACK) на уровнеDEBUG.
Команды управления¶
makemessagesкоманда теперь поддерживает локали с частными вложенными тегами, такими какnl_NL-x-informal.Новая опция
makemigrations --updateобъединяет изменения модели с последней миграцией и оптимизирует полученные операции.
Миграции¶
Миграции теперь поддерживают сериализацию объектов enum.Flag.
Модели¶
QuerySetтеперь широко поддерживает фильтрацию по оконным функциям, за исключением дизъюнктивного поиска фильтров по оконным функциям при выполнении агрегирования.prefetch_lated()теперь поддерживает объектыPrefetchс нарезанными наборами запросов.Регистрация поисков в экземплярах
Fieldтеперь поддерживается.Новый аргумент
robustдляon_commit()позволяет выполнять действия, которые могут завершиться неудачей после успешного подтверждения транзакции базы данных.Новое выражение
KT()представляет текстовое значение ключа, индекса или преобразования путиJSONField.Nowтеперь поддерживает точность до микросекунд в MySQL и точность до миллисекунд в SQLite.F()выражения, выводящиеBooleanField, теперь можно инвертировать с помощью~F()(оператор инверсии).Modelтеперь предоставляет асинхронные версии некоторых методов, использующих базу данных, с использованием префиксаa:adelete(),arefresh_from_db()иasave().Связанные менеджеры теперь предоставляют асинхронные версии методов, которые изменяют набор связанных объектов, используя префикс
a:aadd(),aclear(),aremove()иaset().CharField.max_lengthбольше не требуется устанавливать в PostgreSQL, который поддерживает неограниченное количество столбцовVARCHAR.
Запросы и ответы¶
StreamingHttpResponseтеперь поддерживает асинхронные итераторы, когда Django обслуживается через ASGI.
Тесты¶
Опция
test --debug-sqlтеперь форматирует SQL-запросы с помощьюsqlparse.Классы
RequestFactory,AsyncRequestFactory,ClientиAsyncClientтеперь поддерживают параметрheaders, который принимает словарь имен и значений заголовков. Это обеспечивает более естественный синтаксис объявления заголовков.# Before: self.client.get("/home/", HTTP_ACCEPT_LANGUAGE="fr") await self.async_client.get("/home/", ACCEPT_LANGUAGE="fr") # After: self.client.get("/home/", headers={"accept-language": "fr"}) await self.async_client.get("/home/", headers={"accept-language": "fr"})
Утилиты¶
Новый параметр encoder для функции
django.utils.html.json_script()позволяет настраивать класс кодировщика JSON.Частная внутренняя копия
urllib.parse.urlsplit()теперь удаляет'\r','\n'и'\t'(см. CVE 2022-0391 и bpo-43882). Это сделано для защиты проектов, которые могут неправильно использовать внутреннюю функциюurl_has_allowed_host_and_scheme()вместо использования одной из документированных функций для обработки перенаправления URL-адресов. Функции Django не были затронуты.Новая функция
django.utils.http.content_disposition_header()возвращает значение HTTP-заголовкаContent-Disposition, как указано в RFC 6266.
Валидаторы¶
Список общих паролей, используемых
CommonPasswordValidator, обновляется до самой последней версии.
Изменения обратной несовместимости в версии 4.2¶
Серверный API базы данных¶
В этом разделе описаны изменения, которые могут потребоваться в сторонних базах данных.
DatabaseFeatures.allows_group_by_pkудален, поскольку он остался только для размещения расширения MySQL, которое было заменено правильным обнаружением функциональных зависимостей в MySQL 5.7.15. Обратите внимание, что DatabaseFeatures.allows_group_by_selected_pks по-прежнему поддерживается и должен быть включен, если ваш сервер поддерживает обнаружение функциональных зависимостей в предложениях GROUP BY, как указано в стандарте SQL:1999.inspectdbтеперь используетdisplay_sizeизDatabaseIntrospection.get_table_description()вместоinternal_sizeдляCharField.
Прекращена поддержка MariaDB 10.3.¶
Вышестоящая поддержка MariaDB 10.3 заканчивается в мае 2023 года. Django 4.2 поддерживает MariaDB 10.4 и выше.
Прекращена поддержка MySQL 5.7.¶
Поддержка MySQL 5.7 заканчивается в октябре 2023 года. Django 4.2 поддерживает MySQL 8 и выше.
Прекращена поддержка PostgreSQL 11.¶
Поддержка исходной версии PostgreSQL 11 заканчивается в ноябре 2023 года. Django 4.2 поддерживает PostgreSQL 12 и выше.
Теперь может потребоваться установка update_fields в Model.save().¶
Чтобы избежать обновления ненужных столбцов, QuerySet.update_or_create() теперь передает update_fields в вызовы Model.save(). Как следствие, любые поля, измененные в пользовательских методах save(), должны быть добавлены к аргументу ключевого слова update_fields перед вызовом super(). Дополнительную информацию см. в разделе Переопределение методов модели.
Прекращена поддержка необработанных агрегаций в MySQL.¶
MySQL 8+ допускает функциональные зависимости от столбцов GROUP BY, поэтому обходной путь, существовавший до Django 4.2, с группировкой по первичным ключам основной таблицы, удален. Как следствие, использование агрегатов RawSQL() больше не поддерживается в MySQL, поскольку нет способа определить, необходимы ли такие агрегаты или действительны ли они в предложении GROUP BY. Вместо этого используйте Функции агрегации.
Разнообразный¶
Недокументированная функция django.http.multipartparser.parse_header() удалена. Вместо этого используйте django.utils.http.parse_header_parameters().
{%blocktranslate asvar … %}результат теперь помечен как безопасный для целей вывода (HTML).HTML-атрибут
autofocusв поле поиска администратора удален, так как он может сбивать с толку программы чтения с экрана.Опция
makemigrations --checkбольше не создает отсутствующие файлы миграции.Аргумент
aliasдляExpression.get_group_by_cols()удален.Минимальная поддерживаемая версия sqlparse увеличена с 0.2.2 до 0.3.1.
Недокументированный параметр
negatedвыраженияExistsудален.Аргумент is_summary недокументированного метода Query.add_annotation() удален.
Минимальная поддерживаемая версия SQLite увеличена с 3.9.0 до 3.21.0.
Минимальная поддерживаемая версия asgiref увеличена с 3.5.2 до 3.6.0.
UserCreationFormтеперь отклоняет имена пользователей, которые отличаются только по регистру. Если вам нужно предыдущее поведение, используйте вместо негоBaseUserCreationForm.Минимальная поддерживаемая версия mysqlclient увеличена с 1.4.0 до 1.4.3.
Минимальная поддерживаемая версия argon2-cffi увеличена с 19.1.0 до 19.2.0.
Минимальная поддерживаемая версия Pillow увеличена с 6.2.0 до 6.2.1.
Минимальная поддерживаемая версия jinja2 увеличена с 2.9.2 до 2.11.0.
Минимальная поддерживаемая версия redis-py увеличена с 3.0.0 до 3.4.0.
Созданные вручную объекты
WSGIRequestдолжны быть предоставлены в виде файлового объекта дляwsgi.input. Раньше поведение Django было более мягким, чем ожидалось, как указано в спецификации WSGI.Поддержка
PROJ< 5 удалена.EmailBackendтеперь проверяетимя хостаисертификаты. Если вам нужно предыдущее поведение, которое является менее ограничительным и не рекомендуется, создайте подкласс EmailBackend и переопределите свойство ssl_context.
Функции, устаревшие в версии 4.2¶
Опция index_together устарела в пользу indexes¶
Опция Meta.index_together устарела в пользу опции indexes.
Миграцию существующего index_together следует рассматривать как миграцию. Например:
class Author(models.Model):
rank = models.IntegerField()
name = models.CharField(max_length=30)
class Meta:
index_together = [["rank", "name"]]
Должно стать:
class Author(models.Model):
rank = models.IntegerField()
name = models.CharField(max_length=30)
class Meta:
indexes = [models.Index(fields=["rank", "name"])]
Запуск команды makemigrations создаст миграцию, содержащую операцию RenameIndex, которая переименует существующий индекс. Затем рассмотрите возможность сокращения миграций, чтобы удалить index_together из исторических миграций.
Операция миграции AlterIndexTogether теперь официально поддерживается только для файлов миграции до Django 4.2. По соображениям обратной совместимости он по-прежнему является частью общедоступного API, и его прекращение поддержки или удаление не планируется, но его не следует использовать для новых миграций. Вместо этого используйте операции AddIndex и RemoveIndex.
Передача закодированных строковых литералов JSON в JSONField устарела.¶
JSONField и связанные с ним поисковые запросы и агрегаты, используемые для передачи строковых литералов в кодировке JSON, что вызывало неоднозначность в отношении того, были ли строковые литералы уже закодированы с точки зрения серверной части базы данных.
В течение периода прекращения поддержки будут предприняты попытки декодирования строковых литералов в формате JSON, и в случае успеха будет выдано предупреждение, указывающее на передачу незакодированных форм.
Код, который использовался для передачи строковых литералов в кодировке JSON:
Document.objects.bulk_create(
Document(data=Value("null")),
Document(data=Value("[]")),
Document(data=Value('"foo-bar"')),
)
Document.objects.annotate(
JSONBAgg("field", default=Value("[]")),
)
Должно стать:
Document.objects.bulk_create(
Document(data=Value(None, JSONField())),
Document(data=[]),
Document(data="foo-bar"),
)
Document.objects.annotate(
JSONBAgg("field", default=[]),
)
В Django 5.1+ строковые литералы будут неявно интерпретироваться как строковые литералы JSON.
Разнообразный¶
Метод BaseUserManager.make_random_password() устарел. См. рецепты и лучшие практики для использования модуля Python
secretsдля генерации паролей.Фильтр шаблона length_is устарел в пользу
lengthи оператора==в теге{% if %}. Например{% if value|length == 4 %}…{% endif %} {% if value|length == 4 %}True{% else %}False{% endif %}
вместо:
{% if value|length_is:4 %}…{% endif %} {{ value|length_is:4 }}
django.contrib.auth.hashers.SHA1PasswordHasher,django.contrib.auth.hashers.UnsaltedSHA1PasswordHasherиdjango.contrib.auth.hashers.UnsaltedMD5PasswordHasherустарели.django.contrib.postgres.fields.CICharFieldустарел в пользуCharField(db_collation="…")с недетерминированными параметрами сортировки, нечувствительными к регистру.django.contrib.postgres.fields.CIEmailFieldустарел в пользуEmailField(db_collation="…")с недетерминированной сортировкой без учета регистра.django.contrib.postgres.fields.CITextFieldустарел в пользуTextField(db_collation="…")с недетерминированными параметрами сортировки, нечувствительными к регистру.Миксин django.contrib.postgres.fields.CIText устарел.
Атрибуты
map_heightиmap_widthвBaseGeometryWidgetустарели, вместо этого используйте CSS для определения размера виджетов карты.SimpleTestCase.assertFormsetError()устарел в пользуassertFormSetError().TransactionTestCase.assertQuerysetEqual()устарел в пользуassertQuerySetEqual().Передача позиционных аргументов в
SignerиTimestampSignerустарела в пользу аргументов, содержащих только ключевые слова.Параметр
DEFAULT_FILE_STORAGEустарел в пользуSTORAGES["default"].Параметр
STATICFILES_STORAGEустарел в пользуSTORAGES["staticfiles"].Функция django.core.files.storage.get_storage_class() устарела.