• 3.2
  • 5.0
  • 6.1
  • Версия документации: 3.1

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

3 августа 2022 г.

Добро пожаловать в Джанго 4.1!

Эти примечания к выпуску охватывают новые функции, а также некоторые обратно несовместимые изменения, о которых вам следует знать при обновлении с Django 4.0 или более ранней версии. Мы начали процесс прекращения поддержки некоторых функций.

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

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

Django 4.1 поддерживает Python 3.8, 3.9, 3.10 и 3.11 (начиная с версии 4.1.3). Мы настоятельно рекомендуем и официально поддерживаем только последнюю версию каждой серии.

Что нового в Джанго 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!")

Дополнительную информацию см. в разделе Асинхронные представления на основе классов.

Асинхронный интерфейс 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 и интеграцией асинхронных драйверов базы данных. Новый интерфейс асинхронного набора запросов в настоящее время инкапсулирует необходимые операции sync_to_async() и позволит вашему коду использовать преимущества асинхронной поддержки ORM по мере ее развития.

Подробности и ограничения см. в разделе Асинхронные запросы.

Проверка ограничений

Проверьте, unique и exclusion ограничения, определенные в Meta.constraints Параметры теперь проверяются во время проверки модели.

Доступность рендеринга форм

Чтобы помочь пользователям с программами чтения с экрана и другими вспомогательными технологиями, в этом выпуске доступны новые шаблоны форм на основе <div>. Они обеспечивают более доступную навигацию, чем старые шаблоны, и позволяют правильно группировать связанные элементы управления, такие как списки радио, в наборы полей.

Рекомендуется использовать новые шаблоны, которые станут стилем рендеринга формы по умолчанию при выводе формы, например {{ form }} в шаблоне из Django 5.0.

Чтобы облегчить внедрение нового стиля вывода, шаблоны форм и наборов форм по умолчанию теперь можно настроить на уровне проекта с помощью параметра FORM_RENDERER.

Подробную информацию смотрите в разделе «Формы» (ниже)<forms-4.1>.

Минорные изменения

django.contrib.admin

  • Переменные CSS темного режима администратора <admin-theming> теперь применяются в отдельной таблице стилей и блоке шаблона.

  • Фильтры списка ModelAdmin, предоставляющий пользовательские подклассы FieldListFilter, теперь могут управлять разделителем значений строки запроса при фильтрации нескольких значений с использованием поиска __in.

  • Администраторское представление истории <django.contrib.admin.ModelAdmin.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 теперь позволяет указывать классы операторов с помощью выражения OpClass().

django.contrib.sitemaps

  • Шаблон индекса карты сайта по умолчанию <sitemapindex> теперь включает временную метку <lastmod>, где это возможно, посредством нового метода get_latest_lastmod(). Пользовательские шаблоны индексов карты сайта должны быть обновлены для скорректированных контекстных переменных.

django.contrib.staticfiles

  • ManifestStaticFilesStorage теперь заменяет пути к ссылкам на исходную карту CSS их хешированными аналогами.

Серверные базы данных

  • Сторонние базы данных теперь могут указывать минимально необходимую версию базы данных, используя атрибут 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 теперь является свойством, передаваемым средству визуализации, но его можно переопределить строковым значением, чтобы указать имя шаблона для каждого класса формы.

    Аналогично, шаблон по умолчанию, используемый для рендеринга наборов форм, может быть указан через соответствующий атрибут рендерера 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() позволяет предотвратить создание новых объектов.

  • Атрибуты класса js и css Media теперь позволяют использовать хэшируемые объекты, а не только строки пути, если эти объекты реализуют метод __html__() (обычно при декорировании с помощью декоратора html_safe()).

  • Новые атрибуты 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 позволяет включить проверки работоспособности постоянных подключений к базе данных, чтобы уменьшить количество неудачных запросов, например после перезапуска сервера базы данных.

  • 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 теперь поддерживает список протоколов, разделенных запятыми, в значении заголовка.

Сигналы

  • Сигналы pre_delete и post_delete теперь отправляют источник удаления.

Шаблоны

  • Атрибут id элемента HTML <script> больше не требуется при упаковке фильтра шаблона json_script.

  • кэшированный загрузчик шаблонов теперь включен в разработке, когда DEBUG имеет значение True и OPTIONS['loaders'] не указан. При необходимости вы можете указать OPTIONS['loaders'], чтобы переопределить это.

Тесты

  • DiscoverRunner теперь поддерживает параллельный запуск тестов в macOS, Windows и любых других системах, где методом запуска multiprocessing по умолчанию является spawn.

  • Вложенный атомарный блок, помеченный как устойчивый в django.test.TestCase, теперь вызывает ошибку RuntimeError, так же, как и вне тестов.

  • SimpleTestCase.assertFormError() и assertFormsetError() теперь поддерживают прямую передачу объекта формы/набора форм.

URL-адреса

  • Новый атрибут ResolverMatch.captured_kwargs хранит захваченные аргументы ключевого слова, полученные из URL-адреса.

  • Новый атрибут ResolverMatch.extra_kwargs хранит дополнительные аргументы ключевого слова, передаваемые функции просмотра.

Утилиты

  • SimpleLazyObject теперь поддерживает операции сложения.

  • mark_safe() теперь сохраняет ленивые объекты.

Валидаторы

  • Новый StepValueValidator проверяет, является ли значение целым кратным заданному размеру шага. Этот новый валидатор используется для нового аргумента «step_size», добавленного для формирования полей, представляющих числовые значения.

Изменения обратной несовместимости в версии 4.1

Серверный API базы данных

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

  • BaseDatabaseFeatures.has_case_insensitivity_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 и возвращают 2-кортеж, содержащий некоторый 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 удалена.

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

Поддержка исходной версии PostgreSQL 10 заканчивается в ноябре 2022 года. Django 4.1 поддерживает PostgreSQL 11 и выше.

Прекращена поддержка MariaDB 10.2.

Восходящая поддержка MariaDB 10.2 заканчивается в мае 2022 года. Django 4.1 поддерживает MariaDB 10.3 и выше.

Поиск по списку изменений администратора, охватывающий изменения многозначных отношений.

Поиск по списку изменений администратора с использованием нескольких поисковых запросов теперь применяется за один вызов filter(), а не за последовательные вызовы filter().

Для многозначных отношений это означает, что строки из связанной модели должны соответствовать всем терминам, а не какому-либо термину. Например, если для параметра search_fields установлено значение ['child_name', 'child__age'], а пользователь ищет 'Джамал 17', родительские строки будут возвращены только в том случае, если существует связь с некоторым 17-летним ребенком по имени Джамал, а не возвращаются также родители, у которых просто есть младший или старший ребенок по имени Джамал в дополнение к какому-то другому 17-летнему ребенку.

Дополнительную информацию об этой разнице можно найти в теме Фильтрация по связям многие-ко-многим. В Django 4.0 и более ранних версиях get_search_results() следовал второму примеру запроса, но это недокументированное поведение приводило к запросам с чрезмерным количеством соединений.

Отменить изменения внешнего ключа для несохраненных экземпляров модели.

Чтобы унифицировать поведение с отношениями «многие ко многим» для несохраненных экземпляров модели, обратный внешний ключ теперь вызывает ValueError при вызове связанных менеджеров для несохраненных объектов.

Разнообразный

  • Связанные менеджеры для ForeignKey, ManyToManyField и GenericRelation теперь кэшируются в экземпляре Model, которому они принадлежат. Это изменение было отменено в Django 4.1.2.

  • DiscoverRunner теперь возвращает ненулевой код ошибки при неожиданных успехах тестов, отмеченных unittest.expectedFailure().

  • CsrfViewMiddleware больше не маскирует файл cookie CSRF, как это делает токен 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() заменяется на исключение.

  • Аргумент 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.

  • Команда makemessages больше не изменяет файлы .po, если они обновлены. В старых версиях POT-Creation-Date всегда обновлялся.

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

Выйти через GET

Выход из системы с помощью запросов GET к встроенному представлению выхода из системы устарел. Вместо этого используйте запросы 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;
}

Разнообразный

  • Контекст для шаблонов индекса карты сайта в виде плоского списка URL-адресов устарел. Пользовательские шаблоны индексов карты сайта должны быть обновлены для скорректированных контекстных переменных, ожидая список объектов с 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(...),
                ],
            ),
        ]
    
  • Недокументированная возможность передавать errors=None в SimpleTestCase.assertFormError() и assertFormsetError() устарела. Вместо этого используйте errors=[].

  • 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"], ...)
    

    или вместо этого передайте объект формы/набора форм напрямую.

  • Недокументированный django.contrib.gis.admin.OpenLayersWidget устарел.

  • django.contrib.auth.hashers.CryptPasswordHasher устарел.

  • Возможность передавать nulls_first=False или nulls_last=False в методы Expression.asc() и Expression.desc(), а выражение OrderBy считается устаревшим. Вместо этого используйте «Нет».

  • Шаблоны "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() для набора запросов по сравнению со строковыми значениями.

  • Серверная часть django.core.cache.backends.memcached.MemcachedCache удалена.

  • Поддержка формата сообщений до Django 3.2, используемого django.contrib.messages.storage.cookie.CookieStorage, удалена.

Back to Top