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

1 апреля 2019 года

Добро пожаловать в Django 2.2!

Эти заметки о выпуске охватывают new features, а также некоторые backwards incompatible changes, о которых вы должны знать при переходе с Django 2.1 или более ранней версии. Мы begun the deprecation process for some features.

См. руководство How to upgrade Django to a newer version, если вы обновляете существующий проект.

Django 2.2 обозначен как long-term support release. Она будет получать обновления безопасности в течение как минимум трех лет после выпуска. Поддержка предыдущей версии LTS, Django 1.11, закончится в апреле 2020 года.

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

Django 2.2 supports Python 3.5, 3.6, 3.7, 3.8 (as of 2.2.8), and 3.9 (as of 2.2.17). We highly recommend and only officially support the latest release of each series.

Что нового в Django 2.2

Ограничения

Новые классы CheckConstraint и UniqueConstraint позволяют добавлять пользовательские ограничения базы данных. Ограничения добавляются в модели с помощью опции Meta.constraints.

Незначительные особенности

django.contrib.admin

  • Добавлен CSS-класс для заголовков столбцов TabularInline.

django.contrib.auth

  • Теперь HttpRequest передается в качестве первого позиционного аргумента в RemoteUserBackend.configure_user(), если он его принимает.

django.contrib.gis

  • Добавлена поддержка Oracle для функции Envelope.
  • Добавлена поддержка SpatiaLite для поиска coveredby и covers.

django.contrib.postgres

  • Новый аргумент ordering для ArrayAgg и StringAgg определяет порядок следования агрегированных элементов.
  • Новые классы BTreeIndex, HashIndex и SpGistIndex позволяют создавать B-Tree, hash и SP-GiST индексы в базе данных.
  • BrinIndex теперь имеет параметр autosummarize.
  • Новый параметр search_type SearchQuery позволяет искать по фразе или необработанному выражению.

django.contrib.staticfiles

  • К опции collectstatic --ignore добавлено сопоставление путей, чтобы можно было использовать шаблоны типа /vendor/*.js.

Бэкенды баз данных

  • Добавлена потоковая передача результатов для QuerySet.iterator() на SQLite.

Общие представления

  • The new View.setup hook initializes view attributes before calling dispatch(). It allows mixins to set up instance attributes for reuse in child classes.

Интернационализация

  • Добавлена поддержка и переводы для армянского языка.

Команды управления

  • Новая опция --force-color принудительно окрашивает вывод команды.
  • inspectdb теперь создает модели для иностранных таблиц на PostgreSQL.
  • inspectdb --include-views теперь создает модели для материализованных представлений на Oracle и PostgreSQL.
  • Новая опция inspectdb --include-partitions позволяет создавать модели для таблиц разделов на PostgreSQL. В старых версиях модели создавались дочерними таблицами вместо родительской.
  • inspectdb теперь интроспектирует DurationField для Oracle и PostgreSQL, и AutoField для SQLite.
  • В Oracle, dbshell обертывается rlwrap, если доступно. rlwrap предоставляет историю команд и редактирование ввода с клавиатуры.
  • Новая опция makemigrations --no-header позволяет избежать записи комментариев к заголовкам в сгенерированный файл(ы) миграции. Эта опция также доступна для squashmigrations.
  • runserver теперь может использовать Watchman для повышения производительности при просмотре большого количества файлов на предмет изменений.

Миграции

  • Новая опция migrate --plan выводит список операций миграции, которые будут выполнены.
  • NoneType теперь можно сериализовать в миграциях.
  • Теперь вы можете register custom serializers для миграций.

Модели

  • Добавлена поддержка классов операторов PostgreSQL (Index.opclasses).
  • Добавлена поддержка частичных индексов (Index.condition).
  • Добавлены функции базы данных NullIf и Reverse, а также многие math database functions.
  • Установка нового параметра ignore_conflicts из QuerySet.bulk_create() в True говорит базе данных игнорировать отказ вставки строк, которые не проходят ограничения уникальности или другие проверки.
  • Новая функция ExtractIsoYear извлекает годы недели по ISO-8601 из DateField и DateTimeField, а новый поиск iso_year позволяет выполнять запрос по году недели по ISO-8601.
  • Новый метод QuerySet.bulk_update() позволяет эффективно обновлять определенные поля на нескольких экземплярах модели.
  • Django больше не всегда начинает транзакцию при выполнении одного запроса, например, Model.save(), QuerySet.update() и Model.delete(). Это улучшает производительность autocommit, уменьшая количество обходов базы данных.
  • Добавлена поддержка SQLite для функций StdDev и Variance.
  • Обработка агрегации DISTINCT добавлена в класс Aggregate. Добавление allow_distinct = True в качестве атрибута класса для подклассов Aggregate позволяет указать аргумент ключевого слова distinct при инициализации, чтобы гарантировать, что агрегатная функция вызывается только для каждого отдельного значения expressions.
  • Методы RelatedManager.add(), create(), remove(), set(), get_or_create() и update_or_create() теперь разрешены для отношений «многие-ко-многим» с промежуточными моделями. Новый аргумент through_defaults используется для указания значений для новых экземпляров промежуточных моделей.

Запросы и ответы

  • Добавлено HttpRequest.headers для простого доступа к заголовкам запроса.

Сериализация

  • Теперь вы можете десериализовать данные, используя натуральные ключи, содержащие forward references, передавая handle_forward_references=True в serializers.deserialize(). Кроме того, loaddata автоматически обрабатывает прямые ссылки.

Тесты

  • Новое утверждение SimpleTestCase.assertURLEqual() проверяет заданный URL, игнорируя порядок строки запроса. assertRedirects() использует новое утверждение.
  • Тест Client теперь поддерживает автоматическую JSON сериализацию списка и кортежа data при content_type='application/json'.
  • Новая настройка тестовой базы данных ORACLE_MANAGED_FILES позволяет использовать табличные пространства Oracle Managed Files (OMF).
  • Откладываемые ограничения базы данных теперь проверяются в конце каждого теста TestCase на SQLite 3.20+, как и на других бэкендах, поддерживающих откладываемые ограничения. Эти проверки не реализованы для более старых версий SQLite, поскольку они потребовали бы дорогостоящего интроспекта таблиц.
  • DiscoverRunner теперь пропускает настройку баз данных не referenced by tests.

URL-адреса

  • Новый атрибут ResolverMatch.route хранит маршрут соответствующего шаблона URL.

Валидаторы

Изменения в версии 2.2, несовместимые с обратными изменениями

API бэкенда базы данных

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

  • Бэкенды баз данных сторонних производителей должны реализовать поддержку ограничений проверки таблиц или установить DatabaseFeatures.supports_table_check_constraints в False.
  • Сторонние бэкенды баз данных должны реализовать поддержку игнорирования ограничений или ошибок уникальности при вставке или установить DatabaseFeatures.supports_ignore_conflicts в False.
  • Сторонние бэкенды баз данных должны реализовать интроспекцию для DurationField или установить DatabaseFeatures.can_introspect_duration_field в False.
  • DatabaseFeatures.uses_savepoints теперь по умолчанию True.
  • Сторонние бэкенды баз данных должны реализовать поддержку частичных индексов или установить DatabaseFeatures.supports_partial_indexes в False.
  • DatabaseIntrospection.table_name_converter() и column_name_converter() удалены. Сторонним бэкендам баз данных может понадобиться вместо этого реализовать DatabaseIntrospection.identifier_converter(). В этом случае имена ограничений, которые возвращает DatabaseIntrospection.get_constraints(), должны быть нормализованы по identifier_converter().
  • Генерация SQL для индексов перенесена с Index на SchemaEditor и добавлены эти методы SchemaEditor:
    • _create_primary_key_sql() и _delete_primary_key_sql().
    • _delete_index_sql() (в паре с _create_index_sql())
    • _delete_unique_sql (в паре с _create_unique_sql())
    • _delete_fk_sql() (в паре с _create_fk_sql())
    • _create_check_sql() и _delete_check_sql().
  • Третий аргумент DatabaseWrapper.__init__(), allow_thread_sharing, удаляется.

Действия администратора больше не собираются из базовых классов ModelAdmin

Например, в старых версиях Django:

from django.contrib import admin

class BaseAdmin(admin.ModelAdmin):
    actions = ['a']

class SubAdmin(BaseAdmin):
    actions = ['b']

SubAdmin будет иметь действия 'a' и 'b'.

Теперь actions следует стандартному наследованию Python. Чтобы получить тот же результат, что и раньше:

class SubAdmin(BaseAdmin):
    actions = BaseAdmin.actions + ['b']

django.contrib.gis

  • Поддержка GDAL 1.9 и 1.10 прекращена.

TransactionTestCase загрузка сериализованных данных

Начальные миграции данных теперь загружаются в TransactionTestCase в конце теста, после промывки базы данных. В старых версиях эти данные загружались в начале теста, но это не позволяло опции test --keepdb работать правильно (база данных была пустой в конце всего набора тестов). Это изменение не должно повлиять на ваши тесты, если только вы не изменили внутреннее устройство TransactionTestCase.

sqlparse является обязательной зависимостью

Чтобы упростить некоторые части работы Django с базой данных, sqlparse 0.2.2+ теперь является обязательной зависимостью. Она автоматически устанавливается вместе с Django.

cached_property псевдонимы

В использовании, например:

from django.utils.functional import cached_property

class A:

    @cached_property
    def base(self):
        return ...

    alias = base

alias не кэшируется. Там, где проблема может быть обнаружена (Python 3.6 и более поздние версии), такое использование теперь вызывает TypeError: Cannot assign the same cached_property to two different names ('base' and 'alias')..

Вместо этого используйте следующее:

import operator

class A:

    ...

    alias = property(operator.attrgetter('base'))

Разрешения для прокси-моделей

Permissions for proxy models теперь создаются с использованием типа содержимого прокси-модели, а не типа содержимого конкретной модели. При выполнении migrate миграция обновит существующие разрешения.

В админке изменение прозрачно для прокси-моделей, имеющих тот же app_label, что и их конкретная модель. Однако в старых версиях пользователи с правами на прокси-модель с отличным app_label, чем у ее конкретной модели, не могли получить доступ к модели в админке. Теперь это исправлено, но вы, возможно, захотите проверить назначения прав для таких прокси-моделей ([add|view|change|delete]_myproxy) перед обновлением, чтобы убедиться, что новый доступ соответствует требованиям.

Наконец, строки разрешений прокси-модели должны быть обновлены, чтобы использовать свои собственные app_label. Например, для app.MyProxyModel, наследующего от other_app.ConcreteModel, обновите user.has_perm('other_app.add_myproxymodel') до user.has_perm('app.add_myproxymodel').

Слияние формы Media активов

Активы Form Media теперь объединяются с помощью алгоритма топологической сортировки, так как старый алгоритм попарного объединения недостаточен для некоторых случаев. Файлы CSS и JavaScript, не включающие свои зависимости, теперь могут быть отсортированы неправильно (там, где старый алгоритм по совпадению выдавал правильные результаты).

Проверьте все классы Media на наличие отсутствующих зависимостей. Например, виджеты, зависящие от django.jQuery, должны указать js=['admin/js/jquery.init.js', ...], когда declaring form media assets.

Разное

  • Для улучшения читабельности поле формы UUIDField теперь отображает значения с тире, например, 550e8400-e29b-41d4-a716-446655440000 вместо 550e8400e29b41d4a716446655440000.

  • На SQLite, PositiveIntegerField и PositiveSmallIntegerField теперь включают проверочное ограничение для предотвращения отрицательных значений в базе данных. Если у вас есть недопустимые данные и вы запустили миграцию, которая воссоздает таблицу, вы увидите CHECK constraint failed.

  • Для согласованности с серверами WSGI тестовый клиент теперь устанавливает заголовок Content-Length в строку, а не в целое число.

  • Возвращаемое значение django.utils.text.slugify() больше не помечено как HTML-безопасное.

  • Символ усечения, используемый по умолчанию фильтрами шаблонов urlizetrunc, truncatechars, truncatechars_html, truncatewords и truncatewords_html, теперь представляет собой настоящий символ многоточия () вместо трех точек. Возможно, вам придется адаптировать некоторые тестовые сравнения вывода.

  • Устранена поддержка байтовых путей в загрузчике файловой системы шаблона.

  • django.utils.http.urlsafe_base64_encode() теперь возвращает строку, а не байтовую строку, а django.utils.http.urlsafe_base64_decode() больше не может быть передана байтовая строка.

  • Удалена поддержка cx_Oracle < 6.0.

  • Минимальная поддерживаемая версия mysqlclient увеличена с 1.3.7 до 1.3.13.

  • Минимальная поддерживаемая версия SQLite увеличена с 3.7.15 до 3.8.3.

  • В попытке обеспечить более семантические данные запроса, NullBooleanSelect теперь выдает <option> значения unknown, true и false вместо 1, 2 и 3. Для обратной совместимости старые значения по-прежнему принимаются в качестве данных.

  • Group.name max_length увеличивается с 80 до 150 символов.

  • Тесты, нарушающие откладываемые ограничения базы данных, теперь ошибаются при выполнении на SQLite 3.20+, как и на других бэкендах, поддерживающих такие ограничения.

  • Чтобы отловить ошибки использования, тесты Client и django.utils.http.urlencode() теперь выдают сообщение TypeError, если в качестве значения для кодирования передается None, поскольку None не может быть закодировано в GET и POST данных. Либо передайте пустую строку, либо опустите значение.

  • Команда управления ping_google теперь по умолчанию использует https вместо http для URL карты сайта. Если ваш сайт использует http, используйте новую опцию ping_google --sitemap-uses-http. Если вы используете функцию ping_google(), установите новый аргумент sitemap_uses_https в значение False.

  • runserver больше не поддерживает pyinotify (заменен на Watchman).

  • Агрегатные функции Avg, StdDev и Variance теперь возвращают Decimal вместо float, когда на вход подается Decimal.

  • Тесты не будут работать на SQLite, если приложения без миграций имеют отношения к приложениям с миграциями. Это было документированное ограничение с тех пор, как миграции были добавлены в Django 1.7, но теперь оно работает более надежно. Вы увидите, что тесты завершаются с ошибками типа no such table: <app_label>_<model>. Это наблюдалось в нескольких сторонних приложениях, которые имели модели в тестах без миграций. Вы должны добавить миграции для таких моделей.

  • Предоставление целого числа в аргументе key для cache.delete() или cache.get() теперь приводит к появлению ValueError.

  • Уравнения множественного числа для некоторых языков изменены, поскольку включены последние версии от Transifex.

    Примечание

    В Django 2.2.12 была добавлена возможность обрабатывать файлы .po, содержащие различные множественные числа для одного и того же языка.

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

Модель Meta.ordering больше не будет влиять на запросы GROUP BY

Запросы модели Meta.ordering, влияющие на запросы GROUP BY (например, .annotate().values()), являются распространенным источником путаницы. Теперь такие запросы выдают предупреждение об устаревании с советом добавить order_by(), чтобы сохранить текущий запрос. Meta.ordering будет игнорироваться в таких запросах, начиная с Django 3.1.

Разное

  • django.utils.timezone.FixedOffset устарело в пользу datetime.timezone.
  • Недокументированный псевдоним QuerySetPaginator django.core.paginator.Paginator является устаревшим.
  • Поля модели и формы FloatRangeField в django.contrib.postgres устарели в пользу нового названия DecimalRangeField, чтобы соответствовать основному типу данных numrange, используемому в базе данных.
  • Параметр FILE_CHARSET устарел. Начиная с Django 3.1, файлы, считываемые с диска, должны быть в кодировке UTF-8.
  • django.contrib.staticfiles.storage.CachedStaticFilesStorage является устаревшим из-за неразрешимых проблем. Вместо него используйте ManifestStaticFilesStorage или стороннее облачное хранилище.
  • RemoteUserBackend.configure_user() теперь передается request в качестве первого позиционного аргумента, если он его принимает. Поддержка переопределений, которые его не принимают, будет удалена в Django 3.1.
  • Атрибуты SimpleTestCase.allow_database_queries, TransactionTestCase.multi_db и TestCase.multi_db устарели в пользу SimpleTestCase.databases, TransactionTestCase.databases и TestCase.databases. Эти новые атрибуты позволяют объявлять зависимости баз данных, чтобы предотвратить неожиданные запросы к базам данных не по умолчанию для утечки состояния между тестами. Прежнее поведение allow_database_queries=True и multi_db=True может быть достигнуто установкой databases='__all__'.
Вернуться на верх