Примечания к выпуску Django 5.0¶
4 декабря 2023
Добро пожаловать в Django 5.0!
Эти заметки о выпуске охватывают new features, а также некоторые backwards incompatible changes, о которых вы должны знать при обновлении с Django 4.2 или более ранней версии. Мы begun the deprecation process for some features.
См. руководство Как обновить Django до более новой версии, если вы обновляете существующий проект.
Совместимость с Python¶
Django 5.0 поддерживает Python 3.10, 3.11 и 3.12. Мы настоятельно рекомендуем и официально поддерживаем только последний релиз каждой серии.
Серия Django 4.2.x является последней, поддерживающей Python 3.8 и 3.9.
Поддержка сторонних библиотек для старых версий Django¶
После выхода Django 5.0 мы предлагаем авторам сторонних приложений отказаться от поддержки всех версий Django, предшествующих 4.2. В это время вы должны иметь возможность запускать тесты вашего пакета, используя python -Wd
, чтобы появились предупреждения об устаревании. После исправления предупреждений об устаревании ваше приложение должно быть совместимо с Django 5.0.
Что нового в Django 5.0¶
Фасетные фильтры в админке¶
Количество фасетов теперь отображается для примененных фильтров в списке изменений в админке при включении через пользовательский интерфейс. Это поведение можно изменить с помощью нового атрибута ModelAdmin.show_facets
. Для получения дополнительной информации смотрите Грани.
Упрощенные шаблоны для отрисовки полей формы¶
В Django 5.0 появилось понятие группы полей и шаблоны групп полей. Это упрощает отрисовку связанных элементов поля формы Django, таких как его метка, виджет, текст подсказки и ошибки.
Например, шаблон ниже:
<form>
...
<div>
{{ form.name.label_tag }}
{% if form.name.help_text %}
<div class="helptext" id="{{ form.name.auto_id }}_helptext">
{{ form.name.help_text|safe }}
</div>
{% endif %}
{{ form.name.errors }}
{{ form.name }}
<div class="row">
<div class="col">
{{ form.email.label_tag }}
{% if form.email.help_text %}
<div class="helptext" id="{{ form.email.auto_id }}_helptext">
{{ form.email.help_text|safe }}
</div>
{% endif %}
{{ form.email.errors }}
{{ form.email }}
</div>
<div class="col">
{{ form.password.label_tag }}
{% if form.password.help_text %}
<div class="helptext" id="{{ form.password.auto_id }}_helptext">
{{ form.password.help_text|safe }}
</div>
{% endif %}
{{ form.password.errors }}
{{ form.password }}
</div>
</div>
</div>
...
</form>
Теперь это можно упростить до:
<form>
...
<div>
{{ form.name.as_field_group }}
<div class="row">
<div class="col">{{ form.email.as_field_group }}</div>
<div class="col">{{ form.password.as_field_group }}</div>
</div>
</div>
...
</form>
<<<По умолчанию as_field_group()
отображает поля с шаблоном "django/forms/field.html"
и может быть настроен для каждого проекта, каждого поля или каждого запроса. Смотрите Шаблоны групп полей многократного использования.
Значения по умолчанию, рассчитанные на основе базы данных¶
Новый параметр Field.db_default
устанавливает значение по умолчанию, вычисленное по базе данных. Например:
from django.db import models
from django.db.models.functions import Now, Pi
class MyModel(models.Model):
age = models.IntegerField(db_default=18)
created = models.DateTimeField(db_default=Now())
circumference = models.FloatField(db_default=2 * Pi())
Поле модели, созданное в базе данных¶
Новый GeneratedField
позволяет создавать колонки, генерируемые базой данных. Это поле можно использовать во всех поддерживаемых бэкендах баз данных для создания поля, которое всегда вычисляется из других полей. Например:
from django.db import models
from django.db.models import F
class Square(models.Model):
side = models.IntegerField()
area = models.GeneratedField(
expression=F("side") * F("side"),
output_field=models.BigIntegerField(),
db_persist=True,
)
Больше возможностей для объявления вариантов полей¶
Field.choices
(для полей модели) и ChoiceField.choices
(для полей формы) позволяют более гибко подходить к объявлению их значений. В предыдущих версиях Django, choices
должен был быть либо списком из двух кортежей, либо подклассом Типы перечисления, но последний требовал обращения к атрибуту .choices
для предоставления значений в ожидаемой форме:
from django.db import models
Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")
SPORT_CHOICES = [
("Martial Arts", [("judo", "Judo"), ("karate", "Karate")]),
("Racket", [("badminton", "Badminton"), ("tennis", "Tennis")]),
("unknown", "Unknown"),
]
class Winner(models.Model):
name = models.CharField(...)
medal = models.CharField(..., choices=Medal.choices)
sport = models.CharField(..., choices=SPORT_CHOICES)
В Django 5.0 добавлена поддержка приема отображения или callable вместо iterable, а также больше не требуется использовать .choices
напрямую для расширения enumeration types:
from django.db import models
Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")
SPORT_CHOICES = { # Using a mapping instead of a list of 2-tuples.
"Martial Arts": {"judo": "Judo", "karate": "Karate"},
"Racket": {"badminton": "Badminton", "tennis": "Tennis"},
"unknown": "Unknown",
}
def get_scores():
return [(i, str(i)) for i in range(10)]
class Winner(models.Model):
name = models.CharField(...)
medal = models.CharField(..., choices=Medal) # Using `.choices` not required.
sport = models.CharField(..., choices=SPORT_CHOICES)
score = models.IntegerField(choices=get_scores) # A callable is allowed.
Под капотом предоставленные choices
нормализуются в список из 2 кортежей в качестве канонической формы каждый раз, когда значение choices
обновляется. Для получения дополнительной информации, пожалуйста, ознакомьтесь с model field reference on choices.
Незначительные особенности¶
django.contrib.admin
¶
- Новый метод
AdminSite.get_log_entries()
позволяет настраивать набор запросов для перечисленных записей журнала сайта. - Фильтры администратора
django.contrib.admin.AllValuesFieldListFilter
,ChoicesFieldListFilter
,RelatedFieldListFilter
иRelatedOnlyFieldListFilter
теперь обрабатывают многозначные параметры запроса. XRegExp
обновлен с версии 3.2.0 до 5.1.1.- Метод new
AdminSite.get_model_admin()
возвращает класс администратора для заданного класса модели. - Свойства в
ModelAdmin.list_display
теперь поддерживают атрибутboolean
. - jQuery обновлен с версии 3.6.4 до 3.7.1.
django.contrib.auth
¶
- Количество итераций по умолчанию для хешера паролей PBKDF2 увеличено с 600 000 до 720 000.
- Новые асинхронные функции теперь предоставляются с использованием префикса
a
:django.contrib.auth.aauthenticate()
,aget_user()
,alogin()
,alogout()
иaupdate_session_auth_hash()
. AuthenticationMiddleware
теперь добавлен асинхронный методHttpRequest.auser()
, который возвращает текущего вошедшего в систему пользователя.- Новая асинхронная функция
django.contrib.auth.hashers.acheck_password()
и методAbstractBaseUser.acheck_password()
позволяют асинхронно проверять пароли пользователей.
django.contrib.contenttypes
¶
QuerySet.prefetch_related()
теперь поддерживает префетчингGenericForeignKey
с неоднородным набором результатов.
django.contrib.gis
¶
- Новая функция
ClosestPoint()
возвращает двумерную точку на геометрии, которая находится ближе всего к другой геометрии. - GIS aggregates теперь поддерживает аргумент
filter
. - Добавлена поддержка GDAL 3.7 и GEOS 3.12.
- Новый метод
GEOSGeometry.equals_identical()
позволяет проверять геометрии на эквивалентность по точкам.
django.contrib.messages
¶
- Новый метод утверждения
MessagesTestMixin.assertMessages()
позволяет проверитьmessages
, добавленный кresponse
.
django.contrib.postgres
¶
- Новый атрибут
violation_error_code
вExclusionConstraint
позволяет настраиватьcode
изValidationError
, поднимаемых во время model validation.
Асинхронные представления¶
- В ASGI теперь обрабатываются события
http.disconnect
. Это позволяет представлениям выполнять необходимую очистку, если клиент отключается до того, как будет сгенерирован ответ. Дополнительные сведения см. в разделе Обработка разъединений.
Декораторы¶
- Следующие декораторы теперь поддерживают обертывание асинхронных функций представления:
cache_control()
never_cache()
no_append_slash()
csrf_exempt()
csrf_protect()
ensure_csrf_cookie()
requires_csrf_token()
sensitive_variables()
sensitive_post_parameters()
gzip_page()
condition()
conditional_page()
etag()
last_modified()
require_http_methods()
require_GET()
require_POST()
require_safe()
vary_on_cookie()
vary_on_headers()
xframe_options_deny()
xframe_options_sameorigin()
xframe_options_exempt()
Отчеты об ошибках¶
sensitive_variables()
иsensitive_post_parameters()
теперь можно использовать с асинхронными функциями.
Хранение файлов¶
File.open()
теперь передает все позиционные (*args
) и ключевые аргументы (**kwargs
) встроенному в Pythonopen()
.
Формы¶
- Новый аргумент
assume_scheme
дляURLField
позволяет указать схему URL по умолчанию. - Для улучшения доступности внесены следующие изменения:
- Поля формы теперь включают HTML-атрибут
aria-describedby
, чтобы программы чтения с экрана могли ассоциировать поля формы с текстом подсказки. - Недействительные поля формы теперь включают HTML-атрибут
aria-invalid="true"
.
- Поля формы теперь включают HTML-атрибут
Интернационализация¶
- Теперь доступны поддержка и перевод на уйгурский язык.
Миграции¶
- Сериализация функций, украшенных символами
functools.cache()
илиfunctools.lru_cache()
, теперь поддерживается без необходимости написания собственного сериализатора.
Модели¶
- Новый аргумент
create_defaults
методовQuerySet.update_or_create()
иQuerySet.aupdate_or_create()
позволяет указывать различные значения полей для операции создания. - Новый атрибут
violation_error_code
дляBaseConstraint
,CheckConstraint
иUniqueConstraint
позволяет настраиватьcode
изValidationError
, поднимаемых во время model validation. - Аргумент force_insert в
Model.save()
теперь позволяет указать кортеж родительских классов, которые должны быть принудительно вставлены. - <<<Методы
QuerySet.bulk_create()
иQuerySet.abulk_create()
теперь устанавливают первичный ключ для каждого экземпляра модели, если включен параметрupdate_conflicts
(если база данных поддерживает его). - Новый атрибут
UniqueConstraint.nulls_distinct
позволяет настраивать обработку значенийNULL
на PostgreSQL 15+. - Новые асинхронные ярлыки
aget_object_or_404()
иaget_list_or_404()
позволяют асинхронно получать объекты. - Новая функция
aprefetch_related_objects()
позволяет осуществлять асинхронную предварительную выборку экземпляров моделей. QuerySet.aiterator()
теперь поддерживает предыдущие вызовыprefetch_related()
.- В MariaDB 10.7+ столбец
UUIDField
теперь создается как столбецUUID
, а не как столбецCHAR(32)
. Более подробную информацию о Перенос существующих UUIDField на MariaDB 10.7+ см. в руководстве по миграции выше. - Django теперь поддерживает oracledb версии 1.3.2 или выше. Поддержка
cx_Oracle
устарела с этого релиза и будет удалена в Django 6.0.
Пагинация¶
- Новый аргумент
django.core.paginator.Paginator.error_messages
позволяет настраивать сообщения об ошибках, выдаваемыеPaginator.page()
.
Сигналы¶
- Новые методы
Signal.asend()
иSignal.asend_robust()
позволяют асинхронно отправлять сигналы. Приемники сигналов могут быть синхронными или асинхронными, и они будут автоматически адаптированы к правильному стилю вызова.
Тесты¶
Client
иAsyncClient
теперь предоставляют асинхронные методы, используя префиксa
:asession()
,alogin()
,aforce_login()
иalogout()
.AsyncClient
теперь поддерживает параметрfollow
.DiscoverRunner
теперь позволяет показывать продолжительность самых медленных тестов, используя опциюtest --durations
(доступна на Python 3.12+).
Валидаторы¶
- Новый аргумент
offset
вStepValueValidator
позволяет указать смещение для допустимых значений.
Изменения в 5.0, несовместимые с обратным ходом событий¶
API бэкенда базы данных¶
В этом разделе описаны изменения, которые могут потребоваться в бэкендах баз данных сторонних производителей.
DatabaseFeatures.supports_expression_defaults
следует установить значениеFalse
, если база данных не поддерживает использование функций базы данных в качестве значений по умолчанию.DatabaseFeatures.supports_default_keyword_in_insert
следует установить значениеFalse
, если база данных не поддерживает ключевое словоDEFAULT
в запросахINSERT
.DatabaseFeatures.supports_default_keyword_in_bulk_insert
следует установить значениеFalse
, если база данных не поддерживает ключевое словоDEFAULT
в массовыхINSERT
запросах.
django.contrib.gis
¶
- Поддержка GDAL 2.2 и 2.3 удалена.
- Поддержка GEOS 3.6 и 3.7 удалена.
django.contrib.sitemaps
¶
- Функция
django.contrib.sitemaps.ping_google()
и команда управленияping_google
удалены, так как конечная точка Google Sitemaps ping устарела и будет удалена в январе 2024 года. - Класс исключений
django.contrib.sitemaps.SitemapNotFound
удален.
Прекращена поддержка MySQL < 8.0.11¶
Убрана поддержка предварительных выпусков MySQL серии 8.0.x. Django 5.0 поддерживает MySQL 8.0.11 и выше.
Использование create_defaults__exact
теперь может потребоваться при использовании QuerySet.update_or_create()
.¶
QuerySet.update_or_create()
теперь поддерживает параметр create_defaults
. Как следствие, все модели, имеющие поле с именем create_defaults
, которое используется с update_or_create()
, должны указывать это поле в поиске с помощью create_defaults__exact
.
Перенос существующих UUIDField
на MariaDB 10.7+¶
В MariaDB 10.7+, UUIDField
теперь создается как UUID
столбец, а не CHAR(32)
. Как следствие, любой UUIDField
, созданный в Django < 5.0, должен быть заменен на подкласс UUIDField
, поддерживаемый CHAR(32)
:
class Char32UUIDField(models.UUIDField):
def db_type(self, connection):
return "char(32)"
def get_db_prep_value(self, value, connection, prepared=False):
value = super().get_db_prep_value(value, connection, prepared)
if value is not None:
value = value.hex
return value
Например:
class MyModel(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
Должно стать:
class Char32UUIDField(models.UUIDField): ...
class MyModel(models.Model):
uuid = Char32UUIDField(primary_key=True, default=uuid.uuid4)
Выполнение команды makemigrations
приведет к созданию миграции, содержащей безоперационную операцию AlterField
.
Разное¶
- Аргумент
instance
недокументированного методаBaseModelFormSet.save_existing()
переименован вobj
. - Недокументированный
django.contrib.admin.helpers.checkbox
удален. - Целочисленные поля теперь проверяются как 64-битные целые числа на SQLite, чтобы соответствовать поведению
sqlite3
. - Недокументированный атрибут
Query.annotation_select_mask
заменен с набора строк на упорядоченный список строк. ImageField.update_dimension_fields()
больше не вызывается по сигналуpost_init
, еслиwidth_field
иheight_field
не установлены.- <<<Функция базы данных
Now
теперь используетLOCALTIMESTAMP
вместоCURRENT_TIMESTAMP
на Oracle. AdminSite.site_header
теперь отображается в теге<div>
вместо<h1>
. Пользователи программ чтения с экрана полагаются на элементы заголовков для навигации по странице. Наличие двух элементов<h1>
приводило к путанице, а заголовок сайта не помогал, так как повторялся на всех страницах.- Чтобы улучшить доступность, область основного содержимого админки и область содержимого заголовка теперь отображаются в тегах
<main>
и<header>
вместо<div>
. - В базах данных без встроенной поддержки оператора SQL
XOR
,^
как исключительный оператор или (XOR
) теперь возвращает строки, которые соответствуют нечетному числу операндов, а не одному операнду. Это соответствует поведению MySQL, MariaDB и Python. - Минимальная поддерживаемая версия
asgiref
увеличена с 3.6.0 до 3.7.0. - Минимальная поддерживаемая версия
selenium
увеличена с 3.8.0 до 4.8.0. - Исключения
AlreadyRegistered
иNotRegistered
перенесены изdjango.contrib.admin.sites
вdjango.contrib.admin.exceptions
. - Минимальная поддерживаемая версия SQLite увеличена с 3.21.0 до 3.27.0.
- Убрана поддержка
cx_Oracle
< 8.3. - Выполнение SQL-запросов до того, как реестр приложений будет полностью заполнен, теперь вызывает ошибку
RuntimeWarning
. BadRequest
будет поднят для запросов с типом содержимого application/x-www-form-urlencoded в кодировке неUTF-8. Более подробную информацию см. в разделе RFC 1866.- Минимальная поддерживаемая версия
colorama
увеличена до 0.4.6. - Минимальная поддерживаемая версия
docutils
увеличена до 0.19. - Фильтрация наборов запросов от переполненных целочисленных значений теперь всегда возвращает пустой набор запросов. Как следствие, в таких случаях вам может потребоваться использовать арифметику от
ExpressionWrapper()
до explicitly wrap для целочисленных полей.
Функции, устаревшие в версии 5.0¶
Разное¶
- Рендеры переходных форм
DjangoDivFormRenderer
иJinja2DivFormRenderer
устарели. - Передача позиционных аргументов
name
иviolation_error_message
вBaseConstraint
устарела в пользу аргументов, состоящих только из ключевых слов. request
добавляется к сигнатуреModelAdmin.lookup_allowed()
. Поддержка подклассовModelAdmin
, которые не принимают этот аргумент, устарела.- Метод
get_joining_columns()
вForeignObject
иForeignObjectRel
устарел. Начиная с версии Django 6.0,django.db.models.sql.datastructures.Join
больше не будет возвращаться кget_joining_columns()
. Вместо этого подклассы должны реализовыватьget_joining_fields()
. - Метод
ForeignObject.get_reverse_joining_columns()
устарел. - Схема по умолчанию для
forms.URLField
будет изменена с"http"
на"https"
в Django 6.0. Установите переходную настройкуFORMS_URLFIELD_ASSUME_HTTPS
наTrue
, чтобы отказаться от использования"https"
во время цикла выпуска Django 5.x. - Переходная установка
FORMS_URLFIELD_ASSUME_HTTPS
устарела. - Поддержка вызова
format_html()
без передачи args или kwargs будет удалена. - Поддержка
cx_Oracle
устарела в пользу драйвера oracledb 1.3.2+ Python. DatabaseOperations.field_cast_sql()
устарел в пользуDatabaseOperations.lookup_cast()
. Начиная с версии Django 6.0,BuiltinLookup.process_lhs()
больше не будет вызыватьfield_cast_sql()
. Сторонние бэкенды баз данных должны реализовыватьlookup_cast()
вместо этого.- Метакласс
django.db.models.enums.ChoicesMeta
переименован вChoicesType
. - Метод
Prefetch.get_current_queryset()
устарел. - Метод
get_prefetch_queryset()
для связанных менеджеров и дескрипторов устарел. Начиная с версии Django 6.0,get_prefetcher()
иprefetch_related_objects()
больше не будут возвращаться кget_prefetch_queryset()
. Вместо этого подклассы должны реализовыватьget_prefetch_querysets()
.
Функции, удаленные в версии 5.0¶
Эти функции достигли конца своего цикла устаревания и будут удалены в Django 5.0.
Подробную информацию об этих изменениях, в том числе о том, как удалить использование этих функций, смотрите в Функции, устаревшие в версии 4.0.
- Тестовая настройка
SERIALIZE
удалена. - Недокументированный модуль
django.utils.baseconv
удален. - Недокументированный модуль
django.utils.datetime_safe
удален. - Значение по умолчанию для настройки
USE_TZ
изменяется сFalse
наTrue
. - Протокол по умолчанию для карт сайта, созданных вне контекста запроса, изменен с
'http'
на'https'
. - Аргумент
extra_tests
дляDiscoverRunner.build_suite()
иDiscoverRunner.run_tests()
удален. - Агрегаты
django.contrib.postgres.aggregates.ArrayAgg
,JSONBAgg
иStringAgg
больше не возвращают[]
,[]
и''
, соответственно, при отсутствии строк. - Настройка
USE_L10N
удаляется. - Переходная настройка
USE_DEPRECATED_PYTZ
удалена. - Убрана поддержка часовых поясов
pytz
. - Аргумент
is_dst
удаляется:QuerySet.datetimes()
django.utils.timezone.make_aware()
django.db.models.functions.Trunc()
django.db.models.functions.TruncSecond()
django.db.models.functions.TruncMinute()
django.db.models.functions.TruncHour()
django.db.models.functions.TruncDay()
django.db.models.functions.TruncWeek()
django.db.models.functions.TruncMonth()
django.db.models.functions.TruncQuarter()
django.db.models.functions.TruncYear()
- Классы
django.contrib.gis.admin.GeoModelAdmin
иOSMGeoAdmin
удалены. - Недокументированный метод
BaseForm._html_output()
удален. - Убрана возможность возвращать
str
, а неSafeString
при рендерингеErrorDict
иErrorList
.
Подробную информацию об этих изменениях, в том числе о том, как удалить использование этих функций, смотрите в Функции, устаревшие в версии 4.1.
- Метод
SitemapIndexItem.__str__()
удален. - Переходная настройка
CSRF_COOKIE_MASKED
удалена. - Аргумент
name
изdjango.utils.functional.cached_property()
удаляется. - Аргумент
opclasses
изdjango.contrib.postgres.constraints.ExclusionConstraint
удаляется. - Убрана недокументированная возможность передачи
errors=None
вSimpleTestCase.assertFormError()
иassertFormsetError()
. django.contrib.sessions.serializers.PickleSerializer
удаляется.- Использование
QuerySet.iterator()
в наборе queryset, который осуществляет предварительную выборку связанных объектов без указания аргументаchunk_size
, больше не допускается. - Передача несохраненных экземпляров моделей в связанные фильтры больше не допускается.
created=True
требуется в сигнатуре подклассовRemoteUserBackend.configure_user()
.- Убрана поддержка выхода из системы через запросы
GET
вdjango.contrib.auth.views.LogoutView
иdjango.contrib.auth.views.logout_then_login()
. - Псевдоним
django.utils.timezone.utc
дляdatetime.timezone.utc
удален. - Передача объекта ответа и имени формы/набора форм в
SimpleTestCase.assertFormError()
иassertFormSetError()
больше не допускается. - Символ
django.contrib.gis.admin.OpenLayersWidget
удаляется.
- Символ
django.contrib.auth.hashers.CryptPasswordHasher
удаляется.
- Шаблоны
"django/forms/default.html"
и"django/forms/formsets/default.html"
удалены. - Стиль отрисовки форм и наборов форм по умолчанию изменен на div-based.
- Передача
nulls_first=False
илиnulls_last=False
в методыExpression.asc()
иExpression.desc()
, а также выражениеOrderBy
больше не допускается.