Django 4.1 release notes¶
August 3, 2022
Добро пожаловать в Django 4.1!
Эти заметки о выпуске охватывают new features, а также некоторые backwards incompatible changes, о которых вы должны знать при переходе с Django 4.0 или более ранней версии. Мы begun the deprecation process for some features.
См. руководство How to upgrade Django to a newer version, если вы обновляете существующий проект.
Совместимость с Python¶
Django 4.1 supports Python 3.8, 3.9, 3.10, and 3.11 (as of 4.1.3). We highly recommend and only officially support the latest release of each series.
Что нового в Django 4.1¶
Асинхронные обработчики для представлений на основе классов¶
Подклассы представления теперь могут определять асинхронные обработчики HTTP-методов:
import asyncio
from django.http import HttpResponse
from django.views import View
class AsyncView(View):
async def get(self, request, *args, **kwargs):
# Perform view logic using await.
await asyncio.sleep(1)
return HttpResponse("Hello async world!")
Более подробную информацию см. в разделе Asynchronous class-based views.
Асинхронный интерфейс ORM¶
QuerySet
теперь предоставляет асинхронный интерфейс для всех операций доступа к данным. Они называются так же, как и существующие синхронные операции, но с префиксом a
, например acreate()
, aget()
и так далее.
Новый интерфейс позволяет писать асинхронный код без необходимости оборачивать операции ORM в sync_to_async()
:
async for author in Author.objects.filter(name__startswith="A"):
book = await author.books.afirst()
Обратите внимание, что на данном этапе базовые операции с базой данных остаются синхронными, при этом продолжается работа по внедрению асинхронной поддержки в компилятор SQL и интеграции драйверов асинхронных баз данных. Новый асинхронный интерфейс queryset в настоящее время инкапсулирует необходимые операции sync_to_async()
для вас, и позволит вашему коду использовать преимущества развития асинхронной поддержки ORM по мере его развития.
Подробности и ограничения см. в разделе Асинхронные запросы.
Валидация ограничений¶
Ограничения Check
, unique
и exclusion
, определенные в опции Meta.constraints
, теперь проверяются во время model validation.
Доступность рендеринга формы¶
Чтобы помочь пользователям с программами чтения с экрана и другими вспомогательными технологиями, в этом выпуске доступны новые шаблоны форм на основе <div>
. Они обеспечивают более доступную навигацию, чем старые шаблоны, и способны правильно группировать связанные элементы управления, такие как радиосписки, в наборы полей.
Новые шаблоны рекомендованы и станут стилем рендеринга формы по умолчанию при выводе формы, как {{ form }}
в шаблоне, начиная с Django 5.0.
Чтобы облегчить принятие нового стиля вывода, шаблоны форм и наборов форм по умолчанию теперь настраиваются на уровне проекта с помощью параметра FORM_RENDERER
.
Подробную информацию см. в разделе the Forms section (below).
CSRF_COOKIE_MASKED
установка¶
Новый переходный параметр CSRF_COOKIE_MASKED
позволяет указать, нужно ли маскировать CSRF-куки.
CsrfViewMiddleware
больше не маскирует CSRF cookie, как это делает CSRF token в DOM. Если вы обновляете несколько экземпляров одного и того же проекта до Django 4.1, вам следует установить CSRF_COOKIE_MASKED
на True
во время перехода, чтобы обеспечить совместимость со старыми версиями Django. После завершения перехода на 4.1 вы можете перестать переопределять CSRF_COOKIE_MASKED
.
This setting is deprecated as of this release and will be removed in Django 5.0.
Незначительные особенности¶
django.contrib.admin
¶
- Админ dark mode CSS variables теперь применяется в отдельной таблице стилей и блоке шаблона.
- ModelAdmin Фильтры списка, предоставляющие пользовательские подклассы
FieldListFilter
, теперь могут управлять разделителем значений строки запроса при фильтрации нескольких значений с помощью поиска__in
. - Администратор
history view
теперь постранично. - В обертках связанных виджетов теперь есть ссылка на форму изменения объекта.
- Метод
AdminSite.get_app_list()
теперь позволяет изменить порядок приложений и моделей на индексной странице администратора.
django.contrib.auth
¶
- Число итераций по умолчанию для хешера паролей PBKDF2 увеличено с 320 000 до 390 000.
- Метод
RemoteUserBackend.configure_user()
теперь позволяет синхронизировать атрибуты пользователя с атрибутами в удаленной системе, такой как каталог LDAP.
django.contrib.gis
¶
- Новый метод
GEOSGeometry.make_valid()
позволяет преобразовывать недопустимые геометрии в допустимые. - Новый аргумент
clone
дляGEOSGeometry.normalize()
позволяет создать нормализованный клон геометрии.
django.contrib.postgres
¶
- Новая агрегатная функция
BitXor()
возвращаетint
побитовогоXOR
всех не нулевых входных значений. SpGistIndex
теперь поддерживает покрывающие индексы на PostgreSQL 14+.ExclusionConstraint
теперь поддерживает охватывающие ограничения исключения с использованием индексов SP-GiST на PostgreSQL 14+.- Новый атрибут
default_bounds
вDateTimeRangeField
иDecimalRangeField
позволяет задавать границы для списков и кортежей. ExclusionConstraint
now allows specifying operator classes with theOpClass()
expression.
django.contrib.sitemaps
¶
- Шаблон индекса карты сайта по умолчанию
<sitemapindex>
теперь включает метку времени<lastmod>
там, где она доступна, с помощью нового методаget_latest_lastmod()
. Пользовательские шаблоны индекса sitemap должны быть обновлены для корректировки context variables.
django.contrib.staticfiles
¶
ManifestStaticFilesStorage
теперь заменяет пути к ссылкам на карту источников CSS их хэшированными аналогами.
Database backends¶
- Бэкенды баз данных сторонних производителей теперь могут указывать минимально необходимую версию базы данных с помощью атрибута
DatabaseFeatures.minimum_database_version
, который представляет собой кортеж (например,(10, 0)
означает «10.0»). Если указана минимальная версия, бэкенды должны также реализоватьDatabaseWrapper.get_database_version()
, который возвращает кортеж текущей версии базы данных. Метод бэкендаDatabaseWrapper.init_connection_state()
должен вызватьsuper()
для того, чтобы проверка была выполнена.
Формы¶
Шаблон по умолчанию, используемый для отображения форм при приведении к строке, например, в шаблонах в виде
{{ form }}
, теперь настраивается на уровне проекта путем установкиform_template_name
на класс, предусмотренный дляFORM_RENDERER
.Form.template_name
теперь является свойством, отсылающим к рендереру, но может быть переопределено строковым значением для указания имени шаблона per-form class.Аналогично, шаблон по умолчанию, используемый для рендеринга наборов форм, может быть указан через соответствующий атрибут рендеринга
formset_template_name
.Новый шаблон формы
div.html
, ссылающийся на атрибутForm.template_name_div
, и соответствующий методForm.as_div()
выводят формы, используя элементы HTML<div>
.Этот новый стиль вывода рекомендуется использовать вместо существующих стилей
as_table()
,as_p()
иas_ul()
, так как в шаблоне реализованы<fieldset>
и<legend>
для группировки связанных входов и более удобной навигации для пользователей программ чтения с экрана.Вывод на основе div станет стилем рендеринга по умолчанию, начиная с Django 5.0.
Для плавного перехода на новый стиль вывода
<div>
доступны два класса рендереров переходных форм:django.forms.renderers.DjangoDivFormRenderer
иdjango.forms.renderers.Jinja2DivFormRenderer
, для бэкендов шаблонов Django и Jinja2 соответственно.Вы можете применить один из них через настройку
FORM_RENDERER
. Например:FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
Как только стиль вывода
<div>
станет стилем по умолчанию, начиная с Django 5.0, эти переходные рендереры будут устаревшими и будут удалены в Django 6.0. ОбъявлениеFORM_RENDERER
может быть удалено в это время.Если новый стиль вывода
<div>
не подходит для вашего проекта, вам следует определить подкласс рендерера, указавform_template_name
иformset_template_name
для требуемого стиля, и установитьFORM_RENDERER
соответственно.Например, для стиля вывода
<p>
, используемогоas_p()
, вы определите рендерер формы, устанавливающийform_template_name
в"django/forms/p.html"
иformset_template_name
в"django/forms/formsets/p.html"
.Новый
legend_tag()
позволяет выводить метки полей в тегах<legend>
через новый аргументtag
вlabel_tag()
.Новый аргумент
edit_only
дляmodelformset_factory()
иinlineformset_factory()
позволяет предотвратить создание новых объектов.T
Новые атрибуты
BoundField.use_fieldset
иWidget.use_fieldset
помогают определить виджеты, в которых входы должны быть сгруппированы в<fieldset>
с<legend>
.Аргумент error_messages для
BaseFormSet
теперь позволяет настраивать сообщения об ошибках для недопустимого количества форм, передавая ключи'too_few_forms'
и'too_many_forms'
.IntegerField
,FloatField
иDecimalField
теперь опционально принимают аргументstep_size
. Он используется для установки HTML-атрибутаstep
и проверяется при отправке формы.
Интернационализация¶
- Функция
i18n_patterns()
теперь поддерживает языки со скриптами и регионами.
Команды управления¶
makemigrations --no-input
теперь записывает в журнал ответы по умолчанию и причины, по которым миграции не могут быть созданы.- Новая опция
makemigrations --scriptable
перенаправляет вывод журнала и подсказки ввода вstderr
, записывая вstdout
только пути сгенерированных файлов миграции. - Новая опция
migrate --prune
позволяет удалять несуществующие миграции из таблицыdjango_migrations
. - Файлы Python, созданные
startproject
,startapp
,optimizemigration
,makemigrations
иsquashmigrations
, теперь форматируются с помощью командыblack
, если она присутствует на вашемPATH
. - Новая команда
optimizemigration
позволяет оптимизировать операции для миграции.
Миграции¶
- Новая операция
RenameIndex
позволяет переименовывать индексы, определенные в опцияхMeta.indexes
илиindex_together
. - Автоопределитель миграций теперь генерирует операции
RenameIndex
вместоRemoveIndex
иAddIndex
при переименовании индексов, определенных вMeta.indexes
. - Автоопределитель миграций теперь генерирует операции
RenameIndex
вместоAlterIndexTogether
иAddIndex
при перемещении индексов, определенных вMeta.index_together
, вMeta.indexes
.
Модели¶
- Аргумент
order_by
выраженияWindow
теперь принимает строковые ссылки на поля и преобразования. - Новая настройка
CONN_HEALTH_CHECKS
позволяет включить проверку здоровья для persistent database connections, чтобы уменьшить количество неудачных запросов, например, после перезапуска сервера базы данных. QuerySet.bulk_create()
теперь поддерживает обновление полей, когда при вставке строки не соблюдаются ограничения уникальности. Это поддерживается на MariaDB, MySQL, PostgreSQL и SQLite 3.24+.QuerySet.iterator()
теперь поддерживает предварительную выборку связанных объектов, если указан аргументchunk_size
. В старых версиях предварительная выборка не выполнялась.- <<<Объекты
Q
и наборы запросов теперь можно объединять, используя^
в качестве оператора исключающего или (XOR
).XOR
поддерживается в MariaDB и MySQL. Для баз данных, не поддерживающихXOR
, запрос будет преобразован в эквивалент с помощьюAND
,OR
иNOT
. - Новый атрибут Field.non_db_attrs позволяет настраивать атрибуты полей, которые не влияют на определение столбца.
- В PostgreSQL столбцы
AutoField
,BigAutoField
иSmallAutoField
теперь создаются как столбцы идентичности, а не как последовательные столбцы с последовательностями.
Запросы и ответы¶
HttpResponse.set_cookie()
теперь поддерживает объектыtimedelta
для аргументаmax_age
.
Безопасность¶
- Новая настройка
SECRET_KEY_FALLBACKS
позволяет предоставить список значений для поворота секретного ключа. - Настройка
SECURE_PROXY_SSL_HEADER
теперь поддерживает список протоколов в значении заголовка, разделенный запятыми.
Шаблоны¶
- Атрибут HTML
<script>
элементаid
больше не требуется при обертывании фильтра шаблонаjson_script
. - Теперь
cached template loader
включается в разработке, когдаDEBUG
являетсяTrue
, аOPTIONS['loaders']
не указан. Вы можете указатьOPTIONS['loaders']
, чтобы отменить это, если необходимо.
Тесты¶
DiscoverRunner
теперь поддерживает параллельный запуск тестов на macOS, Windows и любых других системах, где по умолчанию используется метод запускаmultiprocessing
spawn
.- Вложенный атомарный блок, помеченный как долговечный в
django.test.TestCase
, теперь вызываетRuntimeError
, как и вне тестов. SimpleTestCase.assertFormError()
andassertFormsetError()
now support passing a form/formset object directly.
URLs¶
- Новый атрибут
ResolverMatch.captured_kwargs
хранит захваченные аргументы ключевых слов, как они были разобраны из URL. - Новый атрибут
ResolverMatch.extra_kwargs
хранит дополнительные аргументы ключевого слова, переданные функции представления.
Утилиты¶
SimpleLazyObject
теперь поддерживает операции сложения.mark_safe()
теперь сохраняет ленивые объекты.
Валидаторы¶
- Новый
StepValueValidator
проверяет, является ли значение целым кратным заданного размера шага. Этот новый валидатор используется для нового аргументаstep_size
, добавляемого в поля формы, представляющие числовые значения.
Изменения в 4.1, несовместимые с обратными изменениями¶
API бэкенда базы данных¶
В этом разделе описаны изменения, которые могут потребоваться в бэкендах баз данных сторонних производителей.
BaseDatabaseFeatures.has_case_insensitive_like
изменено сTrue
наFalse
, чтобы отразить поведение большинства баз данных.DatabaseIntrospection.get_key_columns()
удаляется. Вместо этого используйтеDatabaseIntrospection.get_relations()
.- Метод
DatabaseOperations.ignore_conflicts_suffix_sql()
заменяется наDatabaseOperations.on_conflict_suffix_sql()
, который принимает аргументыfields
,on_conflict
,update_fields
иunique_fields
. - Аргумент
ignore_conflicts
методаDatabaseOperations.insert_statement()
заменяется наon_conflict
, который принимаетdjango.db.models.constants.OnConflict
. DatabaseOperations._convert_field_to_tz()
заменяется наDatabaseOperations._convert_sql_to_tz()
, который принимает аргументыsql
,params
иtzname
.- Несколько методов даты и времени на
DatabaseOperations
теперь принимают аргументыsql
иparams
вместоfield_name
и возвращают кортеж, содержащий некоторый SQL и параметры, которые должны быть интерполированы в этот SQL. Измененные методы имеют новые сигнатуры:DatabaseOperations.date_extract_sql(lookup_type, sql, params)
DatabaseOperations.datetime_extract_sql(lookup_type, sql, params, tzname)
DatabaseOperations.time_extract_sql(lookup_type, sql, params)
DatabaseOperations.date_trunc_sql(lookup_type, sql, params, tzname=None)
DatabaseOperations.datetime_trunc_sql(self, lookup_type, sql, params, tzname)
DatabaseOperations.time_trunc_sql(lookup_type, sql, params, tzname=None)
DatabaseOperations.datetime_cast_date_sql(sql, params, tzname)
DatabaseOperations.datetime_cast_time_sql(sql, params, tzname)
django.contrib.gis
¶
- Удалена поддержка GDAL 2.1.
- Удалена поддержка PostGIS 2.4.
Dropped support for PostgreSQL 10¶
Upstream support for PostgreSQL 10 ends in November 2022. Django 4.1 supports PostgreSQL 11 and higher.
Прекращена поддержка MariaDB 10.2¶
Поддержка MariaDB 10.2 заканчивается в мае 2022 года. Django 4.1 поддерживает MariaDB 10.3 и выше.
Поиск изменений в списке изменений администратора, охватывающий изменения многозначных отношений¶
Поиск в списке изменений администратора с использованием нескольких поисковых запросов теперь выполняется в одном вызове filter()
, а не в последовательных вызовах filter()
.
Для многозначных отношений это означает, что строки из связанной модели должны соответствовать всем терминам, а не любому из них. Например, если search_fields
установлен на ['child__name', 'child__age']
, а пользователь ищет 'Jamal 17'
, строки о родителях будут возвращены только в том случае, если есть связь с каким-то 17-летним ребенком по имени Джамал, вместо того, чтобы возвращать родителям, у которых просто есть младший или старший ребенок по имени Джамал в дополнение к какому-то другому 17-летнему.
См. тему Охватывающие многозначные отношения для более подробного обсуждения этого различия. В Django 4.0 и более ранних версиях get_search_results()
следовал второму примеру запроса, но это недокументированное поведение приводило к запросам с избыточными соединениями.
Обратное изменение внешних ключей для несохраненных экземпляров модели¶
Чтобы унифицировать поведение с отношениями «многие ко многим» для несохраненных экземпляров модели, обратный внешний ключ теперь поднимает ValueError
при вызове related managers
для несохраненных объектов.
Разное¶
- Related managers for
ForeignKey
,ManyToManyField
, andGenericRelation
are now cached on theModel
instance to which they belong. This change was reverted in Django 4.1.2. - Бегунок тестирования Django теперь возвращает ненулевой код ошибки при неожиданных успехах тестов, помеченных
unittest.expectedFailure()
. CsrfViewMiddleware
больше не маскирует CSRF cookie, как это делает CSRF токен в DOM.CsrfViewMiddleware
теперь используетrequest.META['CSRF_COOKIE']
для хранения незамаскированного CSRF-секрета, а не замаскированной версии. Это недокументированный, частный API.- Атрибуты
ModelAdmin.actions
иinlines
теперь по умолчанию используют пустой кортеж, а не пустой список, чтобы предотвратить непреднамеренную мутацию. - Атрибут
type="text/css"
больше не включается в теги<link>
для CSS form media. - События JavaScript
formset:added
иformset:removed
теперь являются событиями чистого JavaScript и не зависят от jQuery. Более подробно об этом изменении смотрите События встроенной формы. - Аргумент
exc_info
недокументированной функцииdjango.utils.log.log_response()
заменяется наexception
. - Аргумент
size
недокументированной функцииdjango.views.static.was_modified_since()
удален. - В пользовательском интерфейсе выхода из системы администратора теперь используются запросы
POST
. - Недокументированное свойство
InlineAdminFormSet.non_form_errors
заменено методомnon_form_errors()
. Это соответствуетBaseFormSet
. - Согласно above, загрузчик кэшированных шаблонов теперь включен в разработке. Вы можете указать
OPTIONS['loaders']
, чтобы отменить это, если необходимо. - Недокументированный миксин
django.contrib.auth.views.SuccessURLAllowedHostsMixin
заменен наRedirectURLMixin
. - Подклассы
BaseConstraint
должны реализовать методvalidate()
, чтобы эти ограничения можно было использовать для проверки. - Недокументированные
URLResolver._is_callback()
,URLResolver._callback_strs
иURLPattern.lookup_str()
перемещены вdjango.contrib.admindocs.utils
. - Метод
Model.full_clean()
теперь преобразует значениеexclude
вset
. Также предпочтительнее передавать значениеexclude
в видеset
методамModel.clean_fields()
,Model.full_clean()
,Model.validate_unique()
иModel.validate_constraints()
. - Минимальная поддерживаемая версия
asgiref
увеличена с 3.4.1 до 3.5.2. - Комбинированные выражения больше не используют опасное для ошибок поведение угадывания
output_field
при совпадении типов аргументов. Как следствие, разрешениеoutput_field
для функций базы данных и комбинированных выражений теперь может привести к сбою при смешанных типах. В таких случаях необходимо явно задатьoutput_field
.
Функции, устаревшие в версии 4.1¶
Выход из системы через GET¶
Выход из системы через GET
запросы к built-in logout view
устарел. Вместо этого используйте запросы POST
.
Если вы хотите сохранить удобство использования HTML-ссылки, вы можете использовать форму, которая будет выглядеть как ссылка:
<form id="logout-form" method="post" action="{% url 'admin:logout' %}">
{% csrf_token %}
<button type="submit">{% translate "Log out" %}</button>
</form>
#logout-form {
display: inline;
}
#logout-form button {
background: none;
border: none;
cursor: pointer;
padding: 0;
text-decoration: underline;
}
Разное¶
Контекст для шаблонов индексов sitemap, представляющий собой плоский список URL-адресов, устарел. Пользовательские шаблоны индекса sitemap должны быть обновлены для настроенного context variables, ожидая список объектов с
location
и необязательными атрибутамиlastmod
.Переходная установка
CSRF_COOKIE_MASKED
устарела.Аргумент
name
вdjango.utils.functional.cached_property()
является устаревшим, так как начиная с Python 3.6 в нем нет необходимости.Аргумент
opclasses
вdjango.contrib.postgres.constraints.ExclusionConstraint
устарел в пользу использованияOpClass()
вExclusionConstraint.expressions
. Чтобы использовать его, вам нужно добавить'django.contrib.postgres'
в вашINSTALLED_APPS
.После внесения этого изменения
makemigrations
создаст новую миграцию с двумя операциями:RemoveConstraint
иAddConstraint
. Поскольку это изменение не влияет на схему базы данных, операциюSeparateDatabaseAndState
можно использовать только для обновления состояния миграции без выполнения какого-либо SQL. Переместите сгенерированные операции в аргументstate_operations
вSeparateDatabaseAndState
. Например:class Migration(migrations.Migration): ... operations = [ migrations.SeparateDatabaseAndState( database_operations=[], state_operations=[ migrations.RemoveConstraint( ... ), migrations.AddConstraint( ... ), ], ), ]
The undocumented ability to pass
errors=None
toSimpleTestCase.assertFormError()
andassertFormsetError()
is deprecated. Useerrors=[]
instead.django.contrib.sessions.serializers.PickleSerializer
является устаревшим из-за риска удаленного выполнения кода.Использование
QuerySet.iterator()
в наборе запросов, который выполняет предварительную выборку связанных объектов без предоставления аргументаchunk_size
, устарело. В старых версиях предварительная выборка не производилась. Предоставление значения дляchunk_size
означает, что дополнительный запрос на чанк, необходимый для предварительной выборки, желателен.Передача несохраненных экземпляров модели в связанные фильтры устарела. В Django 5.0 будет возникать исключение.
created=True
добавляется к сигнатуреRemoteUserBackend.configure_user()
. Поддержка подклассовRemoteUserBackend
, которые не принимают этот аргумент, устарела.Псевдоним
django.utils.timezone.utc
дляdatetime.timezone.utc
устарел. Используйтеdatetime.timezone.utc
напрямую.Передача объекта ответа и имени формы/формсета в
SimpleTestCase.assertFormError()
иassertFormsetError()
устарела. Используйте:assertFormError(response.context['form_name'], …) assertFormsetError(response.context['formset_name'], …)
или передать объект формы/formset напрямую.
Недокументированный
django.contrib.gis.admin.OpenLayersWidget
является устаревшим.django.contrib.auth.hashers.CryptPasswordHasher
устарел.Возможность передавать
nulls_first=False
илиnulls_last=False
в методыExpression.asc()
иExpression.desc()
, а также выражениеOrderBy
является устаревшей. Вместо этого используйтеNone
.Шаблоны
"django/forms/default.html"
и"django/forms/formsets/default.html"
, которые являются прокси для шаблонов на основе таблиц, устарели. Вместо них используйте конкретный шаблон.Недокументированный метод
LogoutView.get_next_page()
переименован вget_success_url()
.
Функции, удаленные в 4.1¶
Эти функции достигли конца своего цикла устаревания и будут удалены в Django 4.1.
Подробнее об этих изменениях, в том числе о том, как удалить использование этих функций, смотрите Функции, устаревшие в версии 3.2.
- Устранена поддержка присвоения объектов, не поддерживающих создание глубоких копий с помощью
copy.deepcopy()
, атрибутам класса вTestCase.setUpTestData()
. - Удалена поддержка использования булевого значения в
BaseCommand.requires_system_checks
. - Аргумент
whitelist
и атрибутdomain_whitelist
вdjango.core.validators.EmailValidator
удаляются. - Переменная конфигурации приложения
default_app_config
удалена. TransactionTestCase.assertQuerysetEqual()
больше не вызываетrepr()
на queryset при сравнении со строковыми значениями.- Бэкенд
django.core.cache.backends.memcached.MemcachedCache
удален. - Убрана поддержка формата сообщений, существовавшего до версии Django 3.2 и использовавшегося
django.contrib.messages.storage.cookie.CookieStorage
.