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

1 августа 2016

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

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

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

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

Как и Django 1.9, Django 1.10 требует Python 2.7, 3.4 или 3.5. Мы настоятельно рекомендуем и официально поддерживаем только последний выпуск каждой серии.

Что нового в Django 1.10

Полнотекстовый поиск для PostgreSQL

django.contrib.postgres теперь включает collection of database functions, позволяющий использовать полнотекстовую поисковую систему. Вы можете искать по нескольким полям реляционной базы данных, комбинировать поиск с другими поисками, использовать различные языковые конфигурации и весовые коэффициенты, а также ранжировать результаты по релевантности.

Также в нем появилась поддержка триграмм с использованием поиска trigram_similar и выражений TrigramSimilarity и TrigramDistance.

Промежуточное программное обеспечение нового типа

A new style of middleware is introduced для решения проблемы отсутствия строгого наслоения запросов/ответов в старом стиле промежуточного программного обеспечения, описанного в DEP 0005. Вам потребуется adapt old, custom middleware и переключиться с настройки MIDDLEWARE_CLASSES на новую настройку MIDDLEWARE, чтобы воспользоваться улучшениями.

Официальная поддержка имен пользователей Unicode

Модель User в django.contrib.auth изначально принимала в именах пользователей только буквы и цифры ASCII. Хотя это не было преднамеренным выбором, символы Unicode всегда принимались при использовании Python 3.

Валидатор имени пользователя теперь явно принимает символы Unicode по умолчанию только в Python 3.

Пользовательские модели могут использовать новые ASCIIUsernameValidator или UnicodeUsernameValidator.

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

django.contrib.admin

  • Для сайтов, работающих на подпути, стандартный URL for the "View site" link в верхней части каждой страницы администратора теперь будет указывать на request.META['SCRIPT_NAME'], если он установлен, вместо /.
  • Сообщение об успехе, появляющееся после добавления или редактирования объекта, теперь содержит ссылку на форму изменения объекта.
  • Весь встроенный JavaScript удален, поэтому вы можете включить HTTP-заголовок Content-Security-Policy, если хотите.
  • Новый атрибут InlineModelAdmin.classes позволяет указывать классы для инлайн-наборов полей. Инлайны с классом collapse будут изначально свернуты, а в их заголовке будет небольшая ссылка «показать».
  • Если у пользователя нет прав на добавление, то блок object-tools в списке изменений модели теперь будет отображаться (без кнопки добавления). Это упрощает добавление пользовательских инструментов в этом случае.
  • Модель LogEntry теперь хранит сообщения об изменениях в структуре JSON, чтобы сообщение могло быть динамически переведено с использованием текущего активного языка. Новый метод LogEntry.get_change_message() теперь является предпочтительным способом получения сообщения об изменении.
  • Выбранные объекты для полей в ModelAdmin.raw_id_fields теперь имеют ссылку на форму изменения объекта.
  • Добавлены варианты «Нет даты» и «Имеет дату» для DateFieldListFilter, если поле является нулевым.
  • Библиотека jQuery, встроенная в админку, обновлена с версии 2.1.4 до 2.2.3.

django.contrib.auth

  • Добавлена поддержка Argon2 password hash. Она рекомендуется вместо PBKDF2, однако не используется по умолчанию, так как требует использования сторонней библиотеки.
  • Количество итераций по умолчанию для хешера паролей PBKDF2 было увеличено на 25%. Это обратно совместимое изменение не повлияет на пользователей, которые подклассифицировали django.contrib.auth.hashers.PBKDF2PasswordHasher для изменения значения по умолчанию.
  • Представление django.contrib.auth.views.logout() отправляет заголовки «no-cache» для предотвращения проблемы, когда Safari кэширует перенаправления и не позволяет пользователю выйти из системы.
  • Добавлен необязательный аргумент backend к django.contrib.auth.login(), чтобы можно было использовать его без учетных данных.
  • Новая настройка LOGOUT_REDIRECT_URL управляет перенаправлением представления django.contrib.auth.views.logout(), если представление не получает аргумента next_page.
  • Новый параметр redirect_authenticated_user для представления django.contrib.auth.views.login() позволяет перенаправлять аутентифицированных пользователей, посещающих страницу входа в систему.
  • Новые AllowAllUsersModelBackend и AllowAllUsersRemoteUserBackend игнорируют значение User.is_active, а ModelBackend и RemoteUserBackend теперь отвергают неактивных пользователей.

django.contrib.gis

  • Distance lookups теперь принимают выражения в качестве параметра значения расстояния.
  • Новое свойство GEOSGeometry.unary_union вычисляет объединение всех элементов данной геометрии.
  • Добавлен бинарный предикат GEOSGeometry.covers().
  • Добавлены метод GDALBand.statistics() и атрибуты mean и std.
  • Добавлена поддержка агрегата MakeLine и функции GeoHash в SpatiaLite.
  • Добавлена поддержка функций Difference, Intersection и SymDifference в MySQL.
  • Добавлена поддержка инстанцирования пустых геометрий GEOS.
  • Новые свойства trim и precision свойства WKTWriter позволяют управлять выводом дробной части координат в WKT.
  • Добавлены свойства LineString.closed и MultiLineString.closed.
  • GeoJSON serializer теперь выводит первичный ключ объектов в словаре properties, если не указаны конкретные поля.
  • Добавлена возможность повторения входных данных по методу GDALBand.data(). Теперь данные диапазона можно эффективно обновлять с помощью повторяющихся значений.
  • Добавлены функции базы данных IsValid и MakeValid, а также поиск isvalid, все для PostGIS. Это позволяет фильтровать и исправлять недействительные геометрии на стороне базы данных.
  • Добавлена поддержка растра для всех spatial lookups.

django.contrib.postgres

  • Для удобства HStoreField теперь приводит свои ключи и значения к строкам.

django.contrib.sessions

  • Команда управления clearsessions теперь удаляет сессии на основе файлов.

django.contrib.sites

django.contrib.staticfiles

  • Тег шаблона static теперь использует django.contrib.staticfiles, если он находится в INSTALLED_APPS. Это особенно полезно для сторонних приложений, которые теперь всегда могут использовать {% load static %} (вместо {% load staticfiles %} или {% load static from staticfiles %}) и не беспокоиться о том, установлено ли приложение staticfiles.
  • Вы можете more easily customize опцию collectstatic --ignore с пользовательской AppConfig.

Кэш

  • Бэкэнд кэша на основе файлов теперь использует самый высокий протокол pickling.

CSRF

  • Стандартные CSRF_FAILURE_VIEW, views.csrf.csrf_failure() теперь принимают необязательный параметр template_name, по умолчанию '403_csrf.html', для управления шаблоном, используемым для рендеринга страницы.
  • Для защиты от атак BREACH механизм защиты CSRF теперь изменяет значение маркера формы при каждом запросе (сохраняя неизменным секрет, который может быть использован для проверки различных маркеров).

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

  • Вычитание временных данных было унифицировано на всех бэкендах.
  • Если база данных поддерживает это, бэкенды могут установить DatabaseFeatures.can_return_ids_from_bulk_insert=True и реализовать DatabaseOperations.fetch_returned_insert_ids() для установки первичных ключей на объекты, созданные с помощью QuerySet.bulk_create().
  • Добавлены аргументы в виде ключевых слов в методы as_sql() различных выражений (Func, When, Case и OrderBy), чтобы позволить бэкендам баз данных настраивать их без изменения self, что небезопасно при использовании различных бэкендов баз данных. Для примера смотрите параметры arg_joiner и **extra_context в Func.as_sql().

Хранение файлов

  • Бэкенды хранилищ теперь представляют API с учетом временной зоны с новыми методами get_accessed_time(), get_created_time() и get_modified_time(). Они возвращают значение datetime, если USE_TZ равно True, и наивное значение datetime в местном часовом поясе в противном случае.
  • Новый метод Storage.generate_filename() облегчает реализацию пользовательских хранилищ, которые не используют вызовы os.path, ранее применявшиеся в FileField.

Формы

  • Форма и виджет Media теперь обслуживается с использованием django.contrib.staticfiles, если он установлен.
  • Тег <input>, отображаемый CharField, теперь включает атрибут minlength, если поле имеет min_length.
  • Обязательные поля формы теперь имеют HTML-атрибут required. Установите новый атрибут Form.use_required_attribute на False, чтобы отключить его. Атрибут required не включен в формы наборов форм, потому что валидация браузера может быть некорректной при добавлении и удалении наборов форм.

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

  • Класс View теперь может быть импортирован из django.views.

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

  • Вспомогательная функция i18n_patterns() теперь может быть использована в корневой URLConf, заданной с помощью request.urlconf.
  • Установив новый параметр prefix_default_language для i18n_patterns() в False, вы можете разрешить доступ к языку по умолчанию без префикса URL.
  • set_language() теперь возвращает код состояния 204 (No Content) для запросов AJAX, если в next или POST нет параметра GET.
  • Представления на основе классов JavaScriptCatalog и JSONCatalog заменяют устаревшие представления на основе функций javascript_catalog() и json_catalog(). Новые представления практически эквивалентны старым, за исключением того, что по умолчанию новые представления собирают все строки JavaScript в домене трансляции djangojs из всех установленных приложений, а не только строки JavaScript из LOCALE_PATHS.

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

  • call_command() теперь возвращает значение, возвращаемое методом command.handle().
  • Новая опция check --fail-level позволяет указать уровень сообщения, который приведет к выходу команды с ненулевым статусом.
  • Новая опция makemigrations --check заставляет команду завершать работу с ненулевым статусом при обнаружении изменений модели без миграций.
  • makemigrations теперь отображает путь к файлам миграции, которые он генерирует.
  • Опция shell --interface теперь принимает python для принудительного использования «обычного» интерпретатора Python.
  • Новая опция shell --command позволяет вам выполнить команду от имени Django и выйти, вместо того, чтобы открывать интерактивную оболочку.
  • Добавлено предупреждение dumpdata, если указана прокси-модель (которая не приводит к выводу) без ее конкретного родителя.
  • Новый атрибут BaseCommand.requires_migrations_checks может быть установлен в True, если вы хотите, чтобы ваша команда выводила предупреждение, как это делает runserver, если набор миграций на диске не совпадает с миграциями в базе данных.
  • Чтобы облегчить тестирование, call_command() теперь принимает объект команды в качестве первого аргумента.
  • Команда shell поддерживает завершение табуляции на системах, использующих libedit, например, macOS.
  • Команда inspectdb позволяет выбрать, какие таблицы должны быть проверены, указав их имена в качестве аргументов.

Миграции

  • Добавлена поддержка сериализации объектов enum.Enum.
  • Добавлен аргумент elidable к операциям RunSQL и RunPython, чтобы их можно было удалить при сминании миграций.
  • Добавлена поддержка non-atomic migrations путем установки атрибута atomic на Migration.
  • Команды migrate и makemigrations теперь check for a consistent migration history. Если они находят некоторые непримененные зависимости примененной миграции, то появляется сообщение InconsistentMigrationHistory.
  • Сигналы pre_migrate() и post_migrate() теперь отправляют свои миграции plan и apps.

Модели

  • Обратные внешние ключи из прокси-моделей теперь распространяются на их конкретный класс. Обратное отношение, присоединенное с помощью ForeignKey, указывающего на прокси-модель, теперь доступно как дескриптор класса прокси-модели и может быть использовано в фильтрации кверисетов.
  • Новый метод Field.rel_db_type() возвращает тип данных столбца базы данных для таких полей, как ForeignKey и OneToOneField, которые указывают на другое поле.
  • Атрибут класса arity добавляется к Func. Этот атрибут можно использовать для установки количества аргументов, принимаемых функцией.
  • Добавлено BigAutoField, которое действует так же, как AutoField, за исключением того, что оно гарантированно подходит для чисел от 1 до 9223372036854775807.
  • QuerySet.in_bulk() может быть вызван без аргументов, чтобы вернуть все объекты в наборе queryset.
  • related_query_name теперь поддерживает интерполяцию метки приложения и класса с помощью строк '%(app_label)s' и '%(class)s'.
  • Позволяет переопределять поля модели, унаследованные от абстрактных базовых классов.
  • Функция prefetch_related_objects() теперь является общедоступным API.
  • QuerySet.bulk_create() устанавливает первичный ключ для объектов при использовании PostgreSQL.
  • Добавлена функция базы данных Cast.
  • Прокси-модель теперь может наследовать несколько прокси-моделей, имеющих общий неабстрактный родительский класс.
  • Добавлены функции Extract для извлечения компонентов времени даты в виде целых чисел, таких как год и час.
  • Добавлены функции Trunc для усечения даты или времени до значимого компонента. Они позволяют выполнять такие запросы, как продажи за день или продажи за час.
  • Model.__init__() теперь устанавливает значения виртуальных полей из своих аргументов ключевых слов.
  • Новые опции Meta.base_manager_name и Meta.default_manager_name позволяют управлять _base_manager и _default_manager, соответственно.

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

  • Добавлено request.user в представление отладки.
  • Добавлены методы HttpResponse readable() и seekable() для превращения экземпляра в потокоподобный объект и возможности обернуть его с помощью io.TextIOWrapper.
  • Добавлены атрибуты HttpRequest.content_type и content_params, которые анализируются из заголовка CONTENT_TYPE.
  • Парсер для request.COOKIES упрощен, чтобы лучше соответствовать поведению браузеров. request.COOKIES теперь может содержать куки, которые недействительны согласно RFC 6265, но могут быть установлены с помощью document.cookie.

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

  • django.core.serializers.json.DjangoJSONEncoder теперь знает, как сериализовать ленивые строки, обычно используемые для переводимого содержимого.

Шаблоны

  • Добавлена опция autoescape к бэкенду DjangoTemplates и классу Engine.
  • Добавлены операторы сравнения is и is not к тегу if.
  • Позволяет dictsort упорядочить список списков по элементу с указанным индексом.
  • Контекстный процессор debug() содержит запросы для всех псевдонимов базы данных, а не только для псевдонима по умолчанию.
  • Добавлена поддержка относительных путей для строковых аргументов тегов шаблонов extends и include.

Тесты

  • Чтобы лучше отлавливать ошибки, TestCase теперь проверяет откладываемые ограничения базы данных в конце каждого теста.
  • Тесты и тестовые случаи могут быть marked with tags и запускаться выборочно с помощью новых опций test --tag и test --exclude-tag.
  • Теперь вы можете входить и использовать сессии с тестовым клиентом, даже если django.contrib.sessions не находится в INSTALLED_APPS.

URL-адреса

  • Добавление в django.setup() позволяет разрешению URL, происходящему вне цикла запрос/ответ (например, в командах управления и автономных скриптах), учитывать FORCE_SCRIPT_NAME при его установке.

Валидаторы

  • URLValidator теперь ограничивает длину меток доменных имен до 63 символов, а общую длину доменных имен до 253 символов на RFC 1034.
  • int_list_validator() теперь принимает необязательный булев параметр allow_negative, по умолчанию False, чтобы разрешить отрицательные целые числа.

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

Предупреждение

В дополнение к изменениям, описанным в этом разделе, обязательно просмотрите Функции, удаленные в версии 1.10 для функций, которые достигли конца своего цикла устаревания и поэтому были удалены. Если вы не обновили свой код в течение срока устаревания данной функции, ее удаление может выглядеть как изменение, несовместимое с обратным ходом развития.

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

  • В AreaField GIS используется неопределенный базовый числовой тип, который на практике может быть любым числовым типом Python. Значения decimal.Decimal, получаемые из базы данных, теперь преобразуются в float, чтобы облегчить их совмещение со значениями, используемыми библиотеками GIS.
  • Чтобы включить временное вычитание, необходимо установить флаг функции базы данных supports_temporal_subtraction в True и реализовать метод DatabaseOperations.subtract_temporals(). Этот метод должен возвращать SQL и параметры, необходимые для вычисления разницы в микросекундах между аргументами lhs и rhs в типе данных, используемом для хранения DurationField.

_meta.get_fields() возвращает согласованные обратные поля для прокси-моделей

До версии Django 1.10 метод get_fields() возвращал разные обратные поля при вызове на прокси-модели по сравнению с проксируемым конкретным классом. Это несоответствие было исправлено путем возврата полного набора полей, указывающих на конкретный класс или один из его прокси в обоих случаях.

AbstractUser.username max_length увеличено до 150

Миграция для django.contrib.auth.models.User.username включена. Если у вас есть пользовательская модель пользователя, наследующая от AbstractUser, вам необходимо создать и применить миграцию базы данных для вашей модели пользователя.

Мы рассматривали возможность увеличения до 254 символов, чтобы легче было разрешить использование адресов электронной почты (которые ограничены 254 символами) в качестве имен пользователей, но отказались от этого из-за ограничения MySQL. При использовании кодировки utf8mb4 (рекомендуемой для правильной поддержки Unicode), MySQL по умолчанию может создавать уникальные индексы только из 191 символа. Поэтому, если вам нужна большая длина, пожалуйста, используйте пользовательскую модель пользователя.

Если вы хотите сохранить ограничение в 30 символов для имен пользователей, используйте пользовательскую форму при создании пользователя или изменении имени пользователя:

from django.contrib.auth.forms import UserCreationForm

class MyUserCreationForm(UserCreationForm):
    username = forms.CharField(
        max_length=30,
        help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
    )

Если вы хотите сохранить это ограничение в админке, установите UserAdmin.add_form для использования этой формы:

from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User

class UserAdmin(BaseUserAdmin):
    add_form = MyUserCreationForm

admin.site.unregister(User)
admin.site.register(User, UserAdmin)

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

Поддержка PostgreSQL 9.1 заканчивается в сентябре 2016 года. Как следствие, Django 1.10 устанавливает PostgreSQL 9.2 в качестве минимальной версии, которую он официально поддерживает.

runserver выход проходит через логирование

Обработка запросов и ответов команды runserver отправляется в логгер django.server, а не в sys.stderr. Если вы отключите конфигурацию логирования Django или переопределите ее своей собственной, вам нужно будет добавить соответствующую конфигурацию логирования, если вы хотите видеть этот вывод:

'formatters': {
    'django.server': {
        '()': 'django.utils.log.ServerFormatter',
        'format': '[%(server_time)s] %(message)s',
    }
},
'handlers': {
    'django.server': {
        'level': 'INFO',
        'class': 'logging.StreamHandler',
        'formatter': 'django.server',
    },
},
'loggers': {
    'django.server': {
        'handlers': ['django.server'],
        'level': 'INFO',
        'propagate': False,
    }
}

auth.CustomUser и auth.ExtensionUser тестовые модели были удалены

После введения миграций для приложений contrib в Django 1.8, таблицы этих пользовательских тестовых моделей больше не создавались, что делает их непригодными для использования в контексте тестирования.

Реестр приложений больше не заполняется автоматически при распаковке моделей вне Django

Реестр приложений больше не заполняется автоматически при распаковке моделей. Это было добавлено в Django 1.7.2 как попытка позволить распаковывать модели вне Django, например, в RQ worker, без вызова django.setup(), но это создает возможность тупика. Чтобы адаптировать ваш код в случае RQ, вы можете provide your own worker script, который вызывает django.setup().

Устранена проверка присвоения нуля для не нулевых полей внешнего ключа

В старых версиях присвоение None ненулевому ForeignKey или OneToOneField приводило к появлению ValueError('Cannot assign None: "model.field" does not allow null values.'). Для согласованности с другими полями модели, не имеющими подобной проверки, эта проверка удалена.

Удалены слабые хешеры паролей из настройки по умолчанию PASSWORD_HASHERS

Django 0.90 хранил пароли в виде несоленого MD5. В Django 0.91 добавлена поддержка соленого SHA1 с автоматическим обновлением паролей при входе пользователя в систему. Django 1.4 добавил PBKDF2 в качестве хешера паролей по умолчанию.

Если у вас есть старый проект Django с кодированными паролями MD5 или SHA1 (даже солеными), имейте в виду, что они могут быть взломаны довольно легко с помощью современного оборудования. Чтобы заставить пользователей Django признать дальнейшее использование слабых хешеров, следующие хешеры удалены из настройки по умолчанию PASSWORD_HASHERS:

'django.contrib.auth.hashers.SHA1PasswordHasher'
'django.contrib.auth.hashers.MD5PasswordHasher'
'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher'
'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher'
'django.contrib.auth.hashers.CryptPasswordHasher'

Рассмотрите возможность использования wrapped password hasher для усиления хэшей в вашей базе данных. Если это невозможно, добавьте параметр PASSWORD_HASHERS в ваш проект и добавьте обратно все хэши, которые вам нужны.

Вы можете проверить, есть ли в вашей базе данных удаленные хэшеры, следующим образом:

from django.contrib.auth import get_user_model
User = get_user_model()

# Unsalted MD5/SHA1:
User.objects.filter(password__startswith='md5$$')
User.objects.filter(password__startswith='sha1$$')
# Salted MD5/SHA1:
User.objects.filter(password__startswith='md5$').exclude(password__startswith='md5$$')
User.objects.filter(password__startswith='sha1$').exclude(password__startswith='sha1$$')
# Crypt hasher:
User.objects.filter(password__startswith='crypt$$')

from django.db.models import CharField
from django.db.models.functions import Length
CharField.register_lookup(Length)
# Unsalted MD5 passwords might not have an 'md5$$' prefix:
User.objects.filter(password__length=32)

Методы Field.get_prep_lookup() и Field.get_db_prep_lookup() удалены

Если у вас есть пользовательское поле, реализующее один из этих методов, зарегистрируйте для него пользовательский поиск. Например:

from django.db.models import Field
from django.db.models.lookups import Exact

class MyField(Field):
    ...

class MyFieldExact(Exact):
    def get_prep_lookup(self):
        # do_custom_stuff_for_myfield
        ....

MyField.register_lookup(MyFieldExact)

django.contrib.gis

  • Поддержка SpatiaLite < 3.0 и GEOS < 3.3 прекращена.
  • Псевдоним add_postgis_srs() для обратной совместимости django.contrib.gis.utils.add_srs_entry() удален.
  • В Oracle/GIS агрегатная функция Area теперь возвращает float вместо decimal.Decimal. (Она по-прежнему обернута в меру квадратных метров).
  • Представление GEOSGeometry по умолчанию (вывод WKT) обрезается по умолчанию. То есть, вместо POINT (23.0000000000000000 5.5000000000000000), вы получите POINT (23 5.5).

Максимальный размер тела запроса и количество параметров GET/POST ограничены

Две новые настройки помогают смягчить атаки типа «отказ в обслуживании» через большие запросы:

  • DATA_UPLOAD_MAX_MEMORY_SIZE ограничивает размер тела запроса. Загрузка файлов не учитывается в этом ограничении.
  • DATA_UPLOAD_MAX_NUMBER_FIELDS ограничивает количество разбираемых параметров GET/POST.

Приложениям, которые получают необычно большие сообщения формы, может потребоваться настройка этих параметров.

Разное

  • repr() из QuerySet оборачивается в <QuerySet >, чтобы при отладке отличить его от обычного списка.
  • utils.version.get_version() возвращает PEP 440 совместимые версии кандидатов в релизы (например, „1.10rc1“ вместо „1.10c1“).
  • Значения CSRF-токенов теперь должны быть строками из 64 буквенно-цифровых символов; значения из 32 буквенно-цифровых символов, установленные в старых версиях Django по умолчанию, автоматически заменяются строками из 64 символов. Другие значения считаются недопустимыми. Это должно повлиять только на разработчиков или пользователей, которые заменяют эти маркеры.
  • Настройка LOGOUT_URL удалена, так как Django не использует ее с версии до 1.0. Если вы используете его в своем проекте, вы можете добавить его в настройки проекта. Значение по умолчанию было '/accounts/logout/'.
  • Объекты с методом close(), такие как файлы и генераторы, переданные в HttpResponse, теперь закрываются немедленно, а не тогда, когда сервер WSGI вызывает close() в ответе.
  • Убран избыточный вызов transaction.atomic() в QuerySet.update_or_create(). Это может повлиять на количество запросов, проверяемых TransactionTestCase.assertNumQueries().
  • Удалена поддержка skip_validation в BaseCommand.execute(**options). Вместо этого используйте skip_checks (добавлено в Django 1.7).
  • loaddata теперь выдает CommandError вместо предупреждения, когда указанный файл приспособления не найден.
  • Вместо прямого обращения к атрибуту LogEntry.change_message теперь лучше вызвать метод LogEntry.get_change_message(), который предоставит сообщение на текущем языке.
  • Представления ошибок по умолчанию теперь поднимают TemplateDoesNotExist, если указано несуществующее template_name.
  • Удален неиспользуемый аргумент choices ключевого слова Select и SelectMultiple метода render() виджетов. Аргумент choices метода render_options() также удаляется, делая selected_choices первым аргументом.
  • Тесты, нарушающие откладываемые ограничения базы данных, теперь будут ошибаться при запуске на базе данных, поддерживающей откладываемые ограничения.
  • Встроенные команды управления теперь используют индексацию ключей в options, например options['verbosity'], вместо options.get(), и больше не выполняют принудительное приведение типов. Это может стать проблемой, если вы вызываете команды, используя Command.execute() (который обходит парсер аргументов, устанавливающий значение по умолчанию) вместо call_command(). Вместо вызова Command.execute() передайте объект команды в качестве первого аргумента в call_command().
  • ModelBackend и RemoteUserBackend теперь отвергают неактивных пользователей. Это означает, что неактивные пользователи не смогут войти в систему и будут выведены из нее, если их переключить с is_active=True на False. Если вам нужно прежнее поведение, используйте вместо него новые AllowAllUsersModelBackend или AllowAllUsersRemoteUserBackend в AUTHENTICATION_BACKENDS.
  • В свете предыдущего изменения метод login() тестового клиента больше не всегда отклоняет неактивных пользователей, а делегирует это решение бэкенду аутентификации. force_login() также делегирует это решение бэкенду аутентификации, поэтому если вы используете бэкенды по умолчанию, вам необходимо использовать активного пользователя.
  • django.views.i18n.set_language() теперь может возвращать код состояния 204 для запросов AJAX.
  • Атрибут base_field в RangeField теперь является типом поля, а не экземпляром поля. Если вы создали пользовательский подкласс RangeField, вам следует изменить атрибут base_field.
  • Классы Middleware теперь инициализируются при запуске сервера, а не во время первого запроса.
  • Если вы переопределяете is_authenticated() или is_anonymous() в пользовательской модели пользователя, вы должны преобразовать их в атрибуты или свойства, как описано в the deprecation note.
  • При использовании ModelAdmin.save_as=True кнопка «Сохранить как новый» теперь перенаправляет на представление изменений для нового объекта, а не на список изменений модели. Если вам нужно прежнее поведение, установите новый атрибут ModelAdmin.save_as_continue на False.
  • Обязательные поля формы теперь имеют HTML-атрибут required. Установите атрибут Form.use_required_attribute на False, чтобы отключить его. Вы также можете добавить атрибут novalidate к <form>, если вам не нужна валидация браузера. Чтобы отключить атрибут required на пользовательских виджетах, переопределите метод Widget.use_required_attribute().
  • Обработчик WSGI больше не удаляет содержимое ответов на HEAD запросы или ответы с status_code из 100-199, 204 или 304. Большинство веб-серверов уже реализуют такое поведение. Ответы, полученные с помощью тестового клиента Django, продолжают иметь эти «исправления ответа».
  • Model.__init__() теперь получает django.db.models.DEFERRED в качестве значения отложенных полей.
  • Атрибут Model._deferred удаляется в качестве классов динамических моделей при использовании QuerySet.defer() и only() удаляется.
  • Storage.save() больше не заменяет '\' на '/'. Это поведение перенесено в FileSystemStorage, так как это специфическая деталь реализации хранилища. Любой пользователь Windows с пользовательской реализацией хранилища, которая полагается на это поведение, должен будет реализовать его в методе save() пользовательского хранилища.
  • Приватные методы FileField get_directory_name() и get_filename() больше не вызываются (и теперь являются устаревшими), что является обратно несовместимым изменением для пользователей, переопределяющих эти методы в пользовательских полях. Чтобы адаптировать такой код, переопределите FileField.generate_filename() или Storage.generate_filename() вместо этого. Возможно, также можно использовать upload_to.
  • Тема письма, отправленного с помощью AdminEmailHandler, больше не обрезается до 989 символов. Если вы рассчитывали на ограниченную длину, усеките тему самостоятельно.
  • Частные выражения django.db.models.expressions.Date и DateTime удалены. Новые выражения Trunc обеспечивают ту же функциональность.
  • Атрибуты _base_manager и _default_manager удаляются из экземпляров модели. Они остаются доступными в классе модели.
  • Доступ к удаленному полю в экземпляре модели, например, после del obj.field, перезагружает значение поля вместо того, чтобы поднять AttributeError.
  • Если вы создаете подкласс AbstractBaseUser и переопределяете clean(), убедитесь, что он вызывает super(). AbstractBaseUser.normalize_username() вызывается в новом методе AbstractBaseUser.clean().
  • Частный API django.forms.models.model_to_dict() возвращает кверисет, а не список первичных ключей для ManyToManyFields.
  • Если установлен django.contrib.staticfiles, тег шаблона static использует хранилище staticfiles для построения URL, а не просто соединяет значение с STATIC_ROOT. Новый подход кодирует URL, что может быть обратно несовместимо в таких случаях, как включение фрагмента в путь, например, {% static 'img.svg#fragment' %}, поскольку # кодируется как %23. Чтобы адаптироваться, переместите фрагмент за пределы тега шаблона: {% static 'img.svg' %}#fragment.
  • Когда USE_L10N равно True, локализация теперь применяется для фильтров date и time, когда не указана строка формата. Вместо одноименных настроек используются спецификаторы DATE_FORMAT и TIME_FORMAT из активной локали.

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

Прямое присвоение обратному внешнему ключу или отношению «многие-ко-многим

Вместо присвоения связанных объектов с помощью прямого присвоения:

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list

Используйте метод set(), добавленный в Django 1.9:

>>> e.related_set.set([obj1, obj2, obj3])

Это предотвращает путаницу, когда присваивание приводит к неявному сохранению.

API без учета временных зон Storage

Старые методы accessed_time(), created_time() и modified_time(), не учитывающие временные зоны, устарели в пользу новых методов get_*_time().

Сторонние бэкенды хранилищ должны реализовать новые методы и пометить старые как устаревшие. До тех пор новые методы get_*_time() в базовом Storage классе конвертируют datetimeиз старых методов по мере необходимости и выдают предупреждение об устаревании.

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

django.contrib.gis

  • Методы get_srid() и set_srid() из GEOSGeometry устарели в пользу свойства srid.
  • Методы get_x(), set_x(), get_y(), set_y(), get_z() и set_z() из Point устарели в пользу свойств x, y и z.
  • Методы get_coords() и set_coords() из Point устарели в пользу свойства tuple.
  • Свойство cascaded_union для MultiPolygon устарело в пользу свойства unary_union.
  • Функция django.contrib.gis.utils.precision_wkt() устарела в пользу WKTWriter.

CommaSeparatedIntegerField поле модели

CommaSeparatedIntegerField устарел в пользу CharField с валидатором validate_comma_separated_integer_list():

from django.core.validators import validate_comma_separated_integer_list
from django.db import models

class MyModel(models.Model):
    numbers = models.CharField(..., validators=[validate_comma_separated_integer_list])

Если вы используете Oracle, CharField использует другой тип поля базы данных (NVARCHAR2), чем CommaSeparatedIntegerField (VARCHAR2). В зависимости от настроек вашей базы данных, это может означать разную кодировку и, следовательно, разную длину (в байтах) для одного и того же содержимого. Если длина ваших хранимых значений превышает 4000 байт, установленных в NVARCHAR2, то вместо этого следует использовать TextField (NCLOB). В этом случае, если у вас есть какие-либо запросы, которые группируют по полю (например, аннотируя модель агрегацией или используя distinct()), вам нужно будет изменить их (чтобы отложить поле).

__search поиск запросов

Поиск search, который поддерживает только MySQL и крайне ограничен в возможностях, устарел. Замените его на собственный поиск:

from django.db import models

class Search(models.Lookup):
    lookup_name = 'search'

    def as_mysql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return 'MATCH (%s) AGAINST (%s IN BOOLEAN MODE)' % (lhs, rhs), params

models.CharField.register_lookup(Search)
models.TextField.register_lookup(Search)

Использование User.is_authenticated() и User.is_anonymous() в качестве методов

Методы is_authenticated() и is_anonymous() классов AbstractBaseUser и AnonymousUser теперь являются свойствами. Они будут работать как методы до версии Django 2.0, но все их использование в Django теперь использует доступ к атрибутам.

Например, если вы используете AuthenticationMiddleware и хотите узнать, вошел ли пользователь в систему в данный момент, вы можете использовать:

if request.user.is_authenticated:
    ... # Do something for logged-in users.
else:
    ... # Do something for anonymous users.

вместо request.user.is_authenticated().

Это изменение позволяет избежать случайной утечки информации, если вы забыли вызвать метод, например:

if request.user.is_authenticated:
    return sensitive_information

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

Django использует объект CallableBool, чтобы позволить этим атрибутам работать и как свойство, и как метод. Таким образом, до окончания срока амортизации вы не можете сравнивать эти свойства с помощью оператора is. То есть, следующее не будет работать:

if request.user.is_authenticated is True:
    ...

«Убегающая» половина django.utils.safestring.

Функция mark_for_escaping() и классы, которые она использует: EscapeData, EscapeBytes, EscapeText, EscapeString и EscapeUnicode являются устаревшими.

В результате «ленивое» поведение фильтра escape (когда он всегда применялся как последний фильтр, независимо от того, где в цепочке фильтров он появлялся) устарело. В Django 2.0 фильтр изменится на немедленное применение conditional_escape().

Разное

  • Опция makemigrations --exit устарела в пользу опции makemigrations --check.
  • django.utils.functional.allow_lazy() устарела в пользу новой функции keep_lazy(), которая может быть использована с более естественным синтаксисом декоратора.
  • Опция shell --plain устарела в пользу -i python или --interface python.
  • Импорт из модуля django.core.urlresolvers устарел в пользу его нового расположения, django.urls.
  • Шаблонный метод Context.has_key() устарел в пользу in.
  • Частный атрибут virtual_fields из Model._meta устарел в пользу private_fields.
  • Закрытые ключевые аргументы virtual_only в Field.contribute_to_class() и virtual в Model._meta.add_field() устарели в пользу private_only и private, соответственно.
  • Представления javascript_catalog() и json_catalog() устарели в пользу основанных на классах представлений JavaScriptCatalog и JSONCatalog.
  • При многотабличном наследовании неявное повышение OneToOneField до parent_link устарело. Добавьте parent_link=True к таким полям.
  • Приватный API Widget._format_value() становится публичным и переименовывается в format_value(). Старое название будет работать в течение периода амортизации.
  • Частные методы FileField get_directory_name() и get_filename() устарели в пользу выполнения этой работы в Storage.generate_filename()).
  • Промежуточные программы старого образца, использующие settings.MIDDLEWARE_CLASSES, устарели. Adapt old, custom middleware и использовать новую настройку MIDDLEWARE.

Функции, удаленные в версии 1.10

Эти функции достигли конца своего цикла устаревания и будут удалены в Django 1.10. Смотрите Функции, устаревшие в версии 1.8 для подробностей, включая то, как удалить использование этих функций.

  • Устранена поддержка прямого вызова SQLCompiler в качестве псевдонима для вызова его метода quote_name_unless_alias.
  • Теги шаблонов cycle и firstof удалены из библиотеки тегов шаблонов future.
  • django.conf.urls.patterns() удаляется.
  • Устранена поддержка аргумента prefix для django.conf.urls.i18n.i18n_patterns().
  • SimpleTestCase.urls удаляется.
  • Использование неправильного подсчета распакованных значений в теге шаблона for вызывает исключение вместо молчаливого отказа.
  • Удалена возможность reverse() URL-адресов, использующих точечный путь Python.
  • Возможность использовать пунктирный путь Python для параметров LOGIN_URL и LOGIN_REDIRECT_URL удалена.
  • Поддержка optparse отменена для пользовательских команд управления.
  • Класс django.core.management.NoArgsCommand удаляется.
  • django.core.context_processors модуль удален.
  • django.db.models.sql.aggregates модуль удален.
  • django.contrib.gis.db.models.sql.aggregates модуль удален.
  • Следующие методы и свойства django.db.sql.query.Query удалены:
    • Свойства: aggregates и aggregate_select.
    • Методы: add_aggregate, set_aggregate_mask и append_aggregate_mask.
  • django.template.resolve_variable удаляется.
  • Следующие частные API удалены из django.db.models.options.Options (Model._meta):
    • get_field_by_name()
    • get_all_field_names()
    • get_fields_with_model()
    • get_concrete_fields_with_model()
    • get_m2m_with_model()
    • get_all_related_objects()
    • get_all_related_objects_with_model()
    • get_all_related_many_to_many_objects()
    • get_all_related_m2m_objects_with_model()
  • Аргумент error_message из django.forms.RegexField удаляется.
  • Фильтр unordered_list больше не поддерживает списки старого стиля.
  • Удалена поддержка строковых аргументов view для url().
  • Удален обратно совместимый шим для переименования django.forms.Form._has_changed() в has_changed().
  • Фильтр шаблона removetags удален.
  • Функции remove_tags() и strip_entities() в django.utils.html удалены.
  • Аргумент is_admin_site для django.contrib.auth.views.password_reset() удаляется.
  • django.db.models.field.subclassing.SubfieldBase удаляется.
  • django.utils.checksums удаляется.
  • Атрибут original_content_type_id на django.contrib.admin.helpers.InlineAdminForm удален.
  • Шим обратной совместимости, позволяющий определять FormMixin.get_form() без значения по умолчанию для его аргумента form_class, удален.
  • Следующие настройки удаляются, и вы должны перейти на настройки TEMPLATES:
    • ALLOWED_INCLUDE_ROOTS
    • TEMPLATE_CONTEXT_PROCESSORS
    • TEMPLATE_DEBUG
    • TEMPLATE_DIRS
    • TEMPLATE_LOADERS
    • TEMPLATE_STRING_IF_INVALID
  • Псевдоним обратной совместимости django.template.loader.BaseLoader удален.
  • Объекты шаблона Django, возвращаемые get_template() и select_template(), больше не принимают Context в своем методе render().
  • Template response APIs принудительно использовать dict и бэкенд-зависимые шаблонные объекты вместо Context и Template соответственно.
  • Параметр current_app для следующих функций и классов удален:
    • django.shortcuts.render()
    • django.template.Context()
    • django.template.RequestContext()
    • django.template.response.TemplateResponse()
  • Параметры dictionary и context_instance для следующих функций удалены:
    • django.shortcuts.render()
    • django.shortcuts.render_to_response()
    • django.template.loader.render_to_string()
  • Параметр dirs для следующих функций удален:
    • django.template.loader.get_template()
    • django.template.loader.select_template()
    • django.shortcuts.render()
    • django.shortcuts.render_to_response()
  • Проверка сеанса включена независимо от того, находится ли 'django.contrib.auth.middleware.SessionAuthenticationMiddleware' в MIDDLEWARE_CLASSES или нет. SessionAuthenticationMiddleware больше не имеет никакого назначения и может быть удалено из MIDDLEWARE_CLASSES. Он оставлен в качестве заглушки до Django 2.0 в качестве любезности для пользователей, которые не читают эту заметку.
  • Частный атрибут django.db.models.Field.related удален.
  • Опция --list команды управления migrate удалена.
  • Тег шаблона ssi удаляется.
  • Удалена поддержка оператора сравнения = в теге шаблона if.
  • Убрана обратная совместимость, позволяющая определять Storage.get_available_name() и Storage.save() без аргумента max_length.
  • Устранена поддержка устаревшего синтаксиса %(<foo>)s в ModelFormMixin.success_url.
  • Агрегатные методы GeoQuerySet collect(), extent(), extent3d(), make_line() и unionagg() удалены.
  • Возможность указать ContentType.name при создании экземпляра типа содержимого удалена.
  • Поддержка старой сигнатуры allow_migrate удалена.
  • Удалена поддержка синтаксиса {% cycle %}, использующего аргументы, разделенные запятыми.
  • Предупреждение, которое Signer выдавалось при указании недопустимого разделителя, теперь является ValueError.
Вернуться на верх