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

Примечание

Посвящается Малкольму Трединнику

17 марта 2013 года проект Django и сообщество свободного программного обеспечения потеряли очень дорогого друга и разработчика.

Малкольм был давним участником проекта Django, образцовым членом сообщества, блестящим умом и другом. Его вклад в Django - и во многие другие проекты с открытым исходным кодом - практически невозможно перечислить. Многие из основной команды Django получили от него свои первые патчи; его наставничество обогатило нас. Его внимательность, терпение и преданность делу всегда будут вдохновлять нас.

Этот выпуск Django предназначен для Малкольма.

– Разработчики Django

Ноябрь 6, 2013

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

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

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

Django 1.6, как и Django 1.5, требует Python 2.6.5 или выше. Python 3 также официально поддерживается. Мы настоятельно рекомендуем последний минорный релиз для каждой поддерживаемой серии Python (2.6.X, 2.7.X, 3.2.X и 3.3.X).

Django 1.6 станет последней серией релизов, поддерживающих Python 2.6; начиная с Django 1.7, минимальная поддерживаемая версия Python будет 2.7.

Python 3.4 не поддерживается, но поддержка будет добавлена в Django 1.7.

Что нового в Django 1.6

Упрощенные шаблоны проектов и приложений по умолчанию

Шаблоны по умолчанию, используемые startproject и startapp, были упрощены и модернизированы. admin теперь включен по умолчанию в новых проектах; фреймворк sites больше не включен. clickjacking prevention теперь включен, а базой данных по умолчанию является SQLite.

Если шаблоны по умолчанию не соответствуют вашим вкусам, вы можете использовать custom project and app templates.

Улучшенное управление транзакциями

Управление транзакциями в Django было переработано. Автокоммит на уровне базы данных теперь включен по умолчанию. Это делает управление транзакциями более явным и должно повысить производительность. Существующие API были устаревшими, и были введены новые API, как описано в transaction management docs.

Постоянные соединения с базой данных

Django теперь поддерживает повторное использование одного и того же соединения с базой данных для нескольких запросов. Это позволяет избежать накладных расходов на повторное установление соединения в начале каждого запроса. Для обратной совместимости эта функция отключена по умолчанию. Подробности смотрите в Постоянные соединения.

Обнаружение тестов в любом тестовом модуле

Django 1.6 поставляется с новым бегунком тестирования, который позволяет более гибко подходить к расположению тестов. Предыдущий бегунок (django.test.simple.DjangoTestSuiteRunner) находил тесты только в модулях models.py и tests.py пакета Python в INSTALLED_APPS.

Новый бегунок (django.test.runner.DiscoverRunner) использует возможности обнаружения тестов, встроенные в unittest2 (версия unittest в стандартной библиотеке Python 2.7+, поставляемая вместе с Django). С помощью функции обнаружения тестов, тесты могут быть расположены в любом модуле, имя которого соответствует шаблону test*.py.

Кроме того, метки тестов, предоставляемые в ./manage.py test для назначения конкретных тестов для запуска, теперь должны быть полными точечными путями Python (или путями каталогов), а не псевдопутями applabel.TestCase.test_method_name. Это позволяет запускать тесты, расположенные в любом месте вашей кодовой базы, а не только в INSTALLED_APPS. Для получения более подробной информации смотрите Тестирование в Django.

Это изменение обратно несовместимо; смотрите backwards-incompatibility notes.

Агрегация с учетом часового пояса

Поддержка time zones, введенная в Django 1.4, не очень хорошо работала с QuerySet.dates(): агрегация всегда выполнялась в UTC. Это ограничение было снято в Django 1.6. Используйте QuerySet.datetimes() для выполнения агрегации с учетом часового пояса на DateTimeField.

Поддержка точек сохранения в SQLite

В Django 1.6 добавлена поддержка точек сохранения в SQLite, с некоторыми limitations.

BinaryField поле модели

Новое поле модели django.db.models.BinaryField позволяет хранить в базе данных необработанные двоичные данные.

Виджеты форм GeoDjango

GeoDjango теперь предоставляет form fields and widgets для своих гео-специализированных полей. По умолчанию они основаны на OpenLayers, но их можно настроить для использования любого другого JS фреймворка.

Команда управления check добавлена для проверки совместимости

Была добавлена команда управления check, позволяющая проверить, совместима ли ваша текущая конфигурация (в настоящее время ориентированная на настройки) с текущей версией Django.

Model.save() алгоритм изменен

Метод Model.save() теперь пытается напрямую UPDATE обратиться к базе данных, если экземпляр имеет значение первичного ключа. Ранее выполнялся SELECT для определения необходимости UPDATE или INSERT. Новый алгоритм требует только одного запроса для обновления существующей строки, в то время как старый алгоритм требовал двух. Более подробную информацию смотрите в Model.save().

В некоторых редких случаях при выполнении триггера UPDATE база данных не сообщает, что найден совпадающий ряд. Примером может служить триггер PostgreSQL ON UPDATE, который возвращает NULL. В таких случаях можно установить флаг django.db.models.Options.select_on_save, чтобы заставить сохранение использовать старый алгоритм.

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

  • Бэкенды аутентификации могут поднять PermissionDenied для немедленного отказа в цепочке аутентификации.
  • Флаг HttpOnly может быть установлен на CSRF cookie с помощью CSRF_COOKIE_HTTPONLY.
  • Теперь assertQuerysetEqual() проверяет неопределенный порядок и выдает ValueError, если обнаружен неопределенный порядок. Порядок считается неопределенным, если заданный QuerySet не является упорядоченным и существует более одного упорядоченного значения для сравнения.
  • Добавлено earliest() для симметрии с latest().
  • В дополнение к year, month и day, ORM теперь поддерживает поиск hour, minute и second.
  • Django теперь оборачивает все исключения PEP 249.
  • Виджеты по умолчанию для EmailField, URLField, IntegerField, FloatField и DecimalField используют новые атрибуты типов, доступные в HTML5 (type='email', type='url', type='number'). Обратите внимание, что из-за нестабильной поддержки типа ввода number с локализованными числами в текущих браузерах, Django использует его только тогда, когда числовые поля не локализованы.
  • Аргумент number для lazy plural translations может быть предоставлен во время перевода, а не во время определения.
  • Для пользовательских команд управления: Проверка наличия валидных настроек в командах, запрашивающих их с помощью внутренней опции BaseCommand.can_import_settings, теперь выполняется независимо от обработки локали, которая должна быть активна во время выполнения команды. На последнюю теперь можно влиять с помощью новой внутренней опции BaseCommand.leave_locale_alone. Более подробную информацию смотрите в Команды управления и локали.
  • Теперь success_url из DeletionMixin интерполируется с object из __dict__.
  • HttpResponseRedirect и HttpResponsePermanentRedirect теперь предоставляют атрибут url (эквивалент URL, на который будет перенаправлен ответ).
  • Бэкэнд кэша MemcachedCache теперь использует последний доступный протокол pickle.
  • Добавлен SuccessMessageMixin, который предоставляет атрибут success_message для классов, основанных на FormView.
  • Добавлены опции django.db.models.ForeignKey.db_constraint и django.db.models.ManyToManyField.db_constraint.
  • Библиотека jQuery, встроенная в админку, была обновлена до версии 1.9.1.
  • Синдикационные фиды (django.contrib.syndication) теперь могут передавать дополнительный контекст шаблонам фидов с помощью нового обратного вызова Feed.get_context_data().
  • Колонки списка администратора имеют класс column-<field_name> в HTML, поэтому заголовок колонки может быть оформлен с помощью CSS, например, для установки ширины колонки.
  • isolation level может быть настроен под PostgreSQL.
  • Тег шаблона blocktrans теперь уважает TEMPLATE_STRING_IF_INVALID для переменных, не присутствующих в контексте, как и другие конструкции шаблона.
  • SimpleLazyObjects теперь будет представлять более полезные представления в ситуациях отладки оболочки.
  • Generic GeometryField теперь можно редактировать с помощью виджета OpenLayers в админке.
  • В документации содержится deployment checklist.
  • Команда diffsettings обрела опцию --all.
  • django.forms.fields.Field.__init__ теперь вызывает super(), что позволяет полевым миксинам реализовывать методы __init__(), которые будут надежно вызываться.
  • Параметр validate_max был добавлен в BaseFormSet и formset_factory(), а также в ModelForm и инлайн-версии. Поведение валидации для наборов форм с max_num было уточнено. Ранее недокументированное поведение, которое защищало наборы форм от атак на исчерпание памяти, было задокументировано, а недокументированное ограничение на большее из 1000 или max_num форм было изменено так, чтобы оно всегда было на 1000 больше, чем max_num.
  • Добавлено BCryptSHA256PasswordHasher для решения проблемы усечения пароля в bcrypt.
  • Pillow теперь является предпочтительной библиотекой для работы с изображениями в Django. PIL находится на стадии устаревания (поддержка будет удалена в Django 1.8). Для обновления вам следует начала удалить PIL, потом установить Pillow.
  • ModelForm принимает несколько новых опций Meta.
    • Поля, включенные в список localized_fields, будут локализованы (путем установки localize на поле формы).
    • Опции labels, help_texts и error_messages могут быть использованы для настройки полей по умолчанию, подробнее см. в Переопределение полей по умолчанию.
  • Аргумент choices для полей модели теперь принимает итерацию итераций вместо того, чтобы требовать итерацию списков или кортежей.
  • Фраза причины может быть настроена в ответах HTTP с помощью reason_phrase.
  • При указании URL следующей страницы для django.contrib.auth.views.logout(), django.contrib.auth.views.password_reset(), django.contrib.auth.views.password_reset_confirm() и django.contrib.auth.views.password_change() теперь можно передавать имена URL, и они будут разрешены.
  • Новая опция dumpdata --pks задает первичные ключи объектов для дампа. Эта опция может использоваться только с одной моделью.
  • Добавлены методы QuerySet first() и last(), которые представляют собой методы удобства, возвращающие первый или последний объект, соответствующий фильтрам. Возвращает None, если нет ни одного подходящего объекта.
  • View и RedirectView теперь поддерживают метод HTTP PATCH.
  • GenericForeignKey теперь принимает необязательный аргумент for_concrete_model, который при установке значения False позволяет полю ссылаться на прокси-модели. По умолчанию используется значение True, чтобы сохранить старое поведение.
  • LocaleMiddleware теперь сохраняет активный язык в сессии, если он там отсутствует. Это предотвращает потерю языковых настроек после удаления сессии, например, выхода из системы.
  • SuspiciousOperation был дифференцирован на ряд подклассов, и каждый из них будет вести журнал в соответствующий именованный регистратор в иерархии регистрации django.security. Наряду с этим изменением, механизм handler400 и представление по умолчанию используются всякий раз, когда SuspiciousOperation достигает обработчика WSGI, чтобы вернуть HttpResponseBadRequest.
  • Исключение DoesNotExist теперь включает сообщение с указанием имени атрибута, используемого для поиска.
  • Метод get_or_create() больше не требует наличия хотя бы одного аргумента в виде ключевого слова.
  • Класс SimpleTestCase включает новый помощник assertion для тестирования ошибок набора форм: assertFormsetError().
  • Список связанных полей, добавленных к QuerySet с помощью select_related(), может быть очищен с помощью select_related(None).
  • Методы get_extra() и get_max_num() на InlineModelAdmin могут быть переопределены для настройки дополнительного и максимального количества встроенных форм.
  • Наборы форм теперь имеют метод total_error_count().
  • Поля ModelForm теперь могут переопределять сообщения об ошибках, определенные в полях модели, используя аргумент error_messages в конструкторе Field. Чтобы воспользоваться преимуществами этой новой возможности с вашими пользовательскими полями, see the updated recommendation для поднятия ValidationError.
  • ModelAdmin теперь сохраняет фильтры в представлении списка после создания, редактирования или удаления объекта. Можно восстановить прежнее поведение очистки фильтров, установив атрибут preserve_filters в значение False.
  • Добавлено FormMixin.get_prefix (которое по умолчанию возвращает FormMixin.prefix) для возможности настройки prefix формы.
  • Необработанные запросы (Manager.raw() или cursor.execute()) теперь могут использовать стиль параметров «pyformat», при котором заполнители в запросе передаются в виде '%(name)s', а параметры передаются в виде словаря, а не списка (за исключением SQLite). Это уже давно возможно (но официально не поддерживается) в MySQL и PostgreSQL, а теперь доступно и в Oracle.
  • Число итераций по умолчанию для хешера паролей PBKDF2 было увеличено на 20%. Это обратно совместимое изменение не повлияет на существующие пароли или пользователей, которые подклассифицировали django.contrib.auth.hashers.PBKDF2PasswordHasher для изменения значения по умолчанию. Пароли will be upgraded будут использовать новое количество итераций по мере необходимости.

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

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

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

Новая модель управления транзакциями

Изменения в поведении

Автокоммит на уровне базы данных включен по умолчанию в Django 1.6. Хотя это не меняет общего духа управления транзакциями в Django, есть несколько несовместимостей в обратную сторону.

Точки сохранения и assertNumQueries

Изменения в управлении транзакциями могут привести к появлению дополнительных операторов для создания, освобождения или отката точек сохранения. Скорее всего, это произойдет с SQLite, поскольку он не поддерживал точки сохранения до этого выпуска.

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

Опция автокоммита для PostgreSQL

В предыдущих версиях автокоммит на уровне базы данных был опцией только для PostgreSQL, и по умолчанию он был отключен. Теперь эта опция игнорируется и может быть удалена.

Новая испытательная машина

Для поддержания большей согласованности с модулем Python unittest новый бегунок тестирования (django.test.runner.DiscoverRunner) не поддерживает автоматически некоторые типы тестов, которые поддерживались предыдущим бегунком:

  • Тесты в файлах models.py и tests/__init__.py больше не будут найдены и запущены. Переместите их в файл, имя которого начинается с test.
  • Доктесты больше не будут обнаруживаться автоматически. Чтобы интегрировать доктесты в свой набор тестов, следуйте инструкциям recommendations in the Python documentation.

Django использует модифицированную версию модуля doctest из стандартной библиотеки Python (в django.test._doctest) и включает некоторые дополнительные утилиты doctest. Эти утилиты устарели и будут удалены в Django 1.8; наборы doctest должны быть обновлены для работы с модулем doctest стандартной библиотеки (или преобразованы в unittest-совместимые тесты).

Если вы хотите отложить обновление вашего набора тестов, вы можете установить параметр TEST_RUNNER в значение django.test.simple.DjangoTestSuiteRunner, чтобы полностью восстановить старое поведение тестов. DjangoTestSuiteRunner является устаревшим, но не будет удален из Django до версии 1.8.

Удаление пользовательской программы тестирования django.contrib.gis.tests.GeoDjangoTestSuiteRunner GeoDjango

Это касается разработчиков, работающих над самим приложением GeoDjango, и связано с пунктом выше об изменениях в тестовых бегунках:

Программа запуска тестов django.contrib.gis.tests.GeoDjangoTestSuiteRunner была удалена, и реализованная в ней автономная установка выполнения тестов GeoDjango больше не поддерживается. Для запуска тестов GeoDjango просто используйте новый DiscoverRunner и укажите приложение django.contrib.gis.

Пользовательские модели пользователей в тестах

Внедрение нового бегуна тестирования также немного изменило способ импорта тестовых моделей. В результате, любой тест, который переопределяет AUTH_USER_MODEL для проверки поведения с одной из тестовых пользовательских моделей Django ( django.contrib.auth.tests.custom_user.CustomUser и django.contrib.auth.tests.custom_user.ExtensionUser), теперь должен явно импортировать модель User в вашем тестовом модуле:

from django.contrib.auth.tests.custom_user import CustomUser

@override_settings(AUTH_USER_MODEL='auth.CustomUser')
class CustomUserFeatureTests(TestCase):
    def test_something(self):
        # Test code here ...

Этот импорт заставляет пользовательскую модель пользователя быть зарегистрированной. Без этого импорта тест не сможет подменить пользовательскую модель пользователя, и вы получите сообщение об ошибке:

ImproperlyConfigured: AUTH_USER_MODEL refers to model 'auth.CustomUser' that has not been installed

Поиск с учетом временной зоны day, month и week_day

В Django 1.6 появилась поддержка часовых поясов для поиска day, month и week_day, когда USE_TZ равен True. Ранее эти поиски выполнялись в UTC независимо от текущего часового пояса.

Для этого требуется time zone definitions in the database. Если вы используете SQLite, вы должны установить pytz. Если вы используете MySQL, вы должны установить pytz и загрузить таблицы часовых поясов с помощью mysql_tzinfo_to_sql.

Добавление QuerySet.datetimes()

Когда time zone support, добавленный в Django 1.4, был активен, поиск QuerySet.dates() возвращал неожиданные результаты, поскольку агрегация выполнялась в UTC. Чтобы исправить это, Django 1.6 вводит новый API, QuerySet.datetimes(). Это требует нескольких изменений в вашем коде.

QuerySet.dates() возвращает date объекты

QuerySet.dates() теперь возвращает список date. Раньше он возвращал список datetime.

QuerySet.datetimes() возвращает список datetime.

QuerySet.dates() больше не используется на DateTimeField

QuerySet.dates() вызывает ошибку, если используется на DateTimeField, когда активна поддержка часовых поясов. Вместо этого используйте QuerySet.datetimes().

date_hierarchy требует определения часового пояса

Функция date_hierarchy в админке теперь полагается на QuerySet.datetimes(), когда она используется на DateTimeField.

Это требует определения часового пояса в базе данных, когда USE_TZ является True. Learn more.

date_list в общих представлениях требует определения часового пояса

По той же причине обращение к date_list в контексте общего представления, основанного на дате, требует определения часового пояса в базе данных, если представление основано на DateTimeField, а USE_TZ является True. Learn more.

Новые поисковые запросы могут конфликтовать с полями модели

Django 1.6 вводит hour, minute и second поиск по DateTimeField. Если у вас были поля модели с именами hour, minute или second, то новые поиски будут конфликтовать с вашими именами полей. Добавьте явный поиск exact, если это является проблемой.

BooleanField больше не используется по умолчанию False

Когда у BooleanField нет явного default, неявным значением по умолчанию является None. В предыдущей версии Django это было False, но это не совсем точно отражало отсутствие значения.

Код, который полагается на значение по умолчанию False, может вызвать исключение при сохранении новых экземпляров модели в базе данных, поскольку None не является приемлемым значением для BooleanField. Вы должны либо указать default=False в определении поля, либо убедиться, что поле установлено в True или False перед сохранением объекта.

Переводы и комментарии в шаблонах

Извлечение переводов после комментариев

Извлечение переводимых литералов из шаблонов с помощью команды makemessages теперь правильно определяет конструкции i18n, если они расположены после комментария типа {# / #} на той же строке. Например:

{# A comment #}{% trans "This literal was incorrectly ignored. Not anymore" %}

Расположение комментариев переводчика

Комментарии Комментарии для переводчиков в шаблонах, заданные с помощью {# / #}, должны находиться в конце строки. Если это не так, комментарии игнорируются, а makemessages выдаст предупреждение. Например:

{# Translators: This is ignored #}{% trans "Translate me" %}
{{ title }}{# Translators: Extracted and associated with 'Welcome' below #}
<h1>{% trans "Welcome" %}</h1>

Цитирую в reverse()

При реверсировании URL Django не применял django.utils.http.urlquote к аргументам перед интерполяцией их в шаблоны URL. Эта ошибка исправлена в Django 1.6. Если вы обошли эту ошибку, применяя URL цитирование перед передачей аргументов в reverse(), это может привести к двойному цитированию. Если это произошло, просто удалите URL-кавычки из вашего кода. Вам также придется заменить специальные символы в URL, используемые в assertRedirects(), на их кодированные версии.

Хранение IP-адресов в приложении для комментариев

Приложение комментариев теперь использует GenericIPAddressField для хранения IP-адресов комментаторов, чтобы поддерживать комментарии, отправленные с адресов IPv6. До сих пор они хранились в формате IPAddressField, который предназначен только для поддержки IPv4. При сохранении комментария, отправленного с адреса IPv6, адрес молча усекался в базах данных MySQL и вызывал исключение в Oracle. Вам нужно будет изменить тип столбца в вашей базе данных, чтобы воспользоваться этим изменением.

Для MySQL выполните этот запрос на базе данных вашего проекта:

ALTER TABLE django_comments MODIFY ip_address VARCHAR(39);

Для Oracle выполните этот запрос:

ALTER TABLE DJANGO_COMMENTS MODIFY (ip_address VARCHAR2(39));

Если вы не примените это изменение, поведение не изменится: в MySQL адреса IPv6 усекаются молча; в Oracle генерируется исключение. Для баз данных SQLite или PostgreSQL изменение базы данных не требуется.

Процентные литералы в запросах cursor.execute

Когда вы выполняете необработанные SQL-запросы с помощью метода cursor.execute, правило об удвоении процентных литералов (%) внутри запроса было унифицировано. В прошлом поведение зависело от бэкенда базы данных. Теперь, для всех бэкендов, удваивать литеральные символы процентов нужно только в том случае, если вы также предоставляете параметры замены. Например:

# No parameters, no percent doubling
cursor.execute("SELECT foo FROM bar WHERE baz = '30%'")

# Parameters passed, non-placeholders have to be doubled
cursor.execute("SELECT foo FROM bar WHERE baz = '30%%' and id = %s", [self.id])

Пользователям SQLite необходимо проверять и обновлять такие запросы.

Справочный текст полей формы модели для полей ManyToManyField

HTML-рендеринг полей формы модели, соответствующих полям модели ManyToManyField, используемым для получения жестко закодированного предложения:

Удерживайте клавишу «Control» или «Command» на Mac, чтобы выбрать более одного.

(или ее перевод в активную локаль) накладывается как легенда справки, отображаемая вдоль них, если ни model, ни form help_text атрибуты не были указаны пользователем (или эта строка была добавлена к любой help_text, которая была предоставлена).

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

Начиная с Django 1.6, в качестве временной временной меры по обеспечению обратной совместимости, логика добавления предложения «Hold down…» была перенесена на уровень поля формы модели и изменена таким образом, чтобы добавлять текст только тогда, когда связанный виджет SelectMultiple или выбранные подклассы.

Это изменение может повлиять на вас обратным несовместимым образом, если вы используете пользовательские поля формы модели и/или виджеты для полей модели ManyToManyField, чьи пользовательские интерфейсы полагаются на автоматическое предоставление упомянутого жестко закодированного предложения. Такие реализации полей форм должны адаптироваться к новому сценарию, обеспечив собственную обработку атрибута help_text.

Приложения, использующие средства Django model form вместе со встроенными в Django формами fields и widgets, не затронуты, но должны знать о том, что описано ниже в Изменение текста справки полей формы модели для полей ManyToManyField.

Итерация QuerySet

Итерация QuerySet была изменена для немедленного преобразования всех найденных строк в объекты Model. В Django 1.5 и более ранних версиях извлеченные строки преобразовывались в объекты Model по 100 штук.

Существующий код будет работать, но количество строк, преобразованных в объекты, может измениться в некоторых случаях использования. К таким случаям относится частичный цикл по набору запросов или любое использование, которое заканчивается выполнением __bool__ или __contains__.

Примечательно, что уже в версии 1.5 большинство бэкендов баз данных получали все строки за один раз.

Все еще можно лениво преобразовать извлеченные строки в объекты Model, используя метод iterator().

BoundField.label_tag теперь включает label_suffix формы

Это соответствует тому, как такие методы, как Form.as_p и Form.as_ul отображают метки.

Если вы вручную отображаете label_tag в своих шаблонах:

{{ form.my_field.label_tag }}: {{ form.my_field }}

вы захотите удалить двоеточие (или любой другой разделитель, который вы используете), чтобы избежать дублирования при обновлении до Django 1.6. Следующий шаблон в Django 1.6 будет отображаться идентично приведенному выше шаблону в Django 1.5, за исключением того, что двоеточие появится внутри элемента <label>.

{{ form.my_field.label_tag }} {{ form.my_field }}

будет выглядеть примерно так:

<label for="id_my_field">My Field:</label> <input id="id_my_field" type="text" name="my_field" />

Если вы хотите сохранить текущее поведение отображения label_tag без label_suffix, создайте форму label_suffix=''. Вы также можете настроить label_suffix на основе каждого поля, используя новый параметр label_suffix в label_tag().

Представления администратора _changelist_filters GET-параметр

Чтобы обеспечить сохранение и восстановление фильтров представления списка, представления администратора теперь передают GET-параметр _changelist_filters. Важно, чтобы вы учли это изменение, если у вас есть пользовательские шаблоны администраторов или если ваши тесты полагаются на прежние URL. Если вы хотите вернуться к первоначальному поведению, вы можете установить атрибут preserve_filters на False.

django.contrib.auth сброс пароля использует кодировку base 64 для User PK

Прошлые версии Django использовали кодировку base 36 для первичного ключа User в представлениях сброса пароля и URL (django.contrib.auth.views.password_reset_confirm()). Кодировки base 36 достаточно, если первичный ключ пользователя является целым числом, однако, с введением пользовательских моделей пользователей в Django 1.5, это предположение может перестать быть верным.

django.contrib.auth.views.password_reset_confirm() был модифицирован, чтобы принимать параметр uidb64 вместо uidb36. Если вы изменяете это представление, например, в пользовательском шаблоне password_reset_email.html, обязательно обновите свой код.

Для обеспечения обратной совместимости был добавлен временный шим для django.contrib.auth.views.password_reset_confirm(), который позволит ссылкам сброса пароля, созданным до Django 1.6, продолжать работать; он будет удален в Django 1.7. Таким образом, пока ваш сайт работает на Django 1.6 более PASSWORD_RESET_TIMEOUT_DAYS, это изменение не будет иметь никакого эффекта. В противном случае (например, если вы переходите непосредственно с Django 1.5 на Django 1.7), то все ссылки на сброс пароля, созданные до перехода на Django 1.7 или более позднюю версию, не будут работать после обновления.

Кроме того, если у вас есть пользовательские URL-адреса сброса пароля, вам необходимо обновить их, заменив uidb36 на uidb64 и тире, следующее за этим шаблоном, на косую черту. Также добавьте _\- в список символов, которые могут соответствовать шаблону uidb64.

Например:

url(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
    'django.contrib.auth.views.password_reset_confirm',
    name='password_reset_confirm'),

становится:

url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
    'django.contrib.auth.views.password_reset_confirm',
    name='password_reset_confirm'),

Возможно, вы также захотите добавить shim для поддержки ссылок сброса старого стиля. Используя пример выше, вы измените существующий url, заменив django.contrib.auth.views.password_reset_confirm на django.contrib.auth.views.password_reset_confirm_uidb36, а также удалите аргумент name, чтобы он не конфликтовал с новым url:

url(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
    'django.contrib.auth.views.password_reset_confirm_uidb36'),

Вы можете удалить этот шаблон URL после развертывания вашего приложения с помощью Django 1.6 для PASSWORD_RESET_TIMEOUT_DAYS.

Сериализация сеанса по умолчанию переключена на JSON

Исторически сложилось так, что django.contrib.sessions использовал pickle для сериализации данных сессии перед их хранением в бэкенде. Если вы используете signed cookie session backend и SECRET_KEY известен злоумышленнику (в Django нет врожденной уязвимости, которая могла бы привести к его утечке), злоумышленник может вставить в сессию строку, которая, будучи распакованной, выполнит произвольный код на сервере. Техника для этого проста и легко доступна в интернете. Хотя хранилище сессий cookie подписывает данные, хранящиеся в cookie, чтобы предотвратить подделку, утечка SECRET_KEY немедленно перерастает в уязвимость удаленного выполнения кода.

От этой атаки можно защититься, если сериализовать данные сессии с помощью JSON, а не pickle. Для этого в Django 1.5.3 появилась новая настройка SESSION_SERIALIZER для настройки формата сериализации сессий. Для обратной совместимости, в Django 1.5.3 эта настройка по умолчанию использовала pickle, но в 1.6 мы изменили значение по умолчанию на JSON. Если вы обновитесь и переключитесь с pickle на JSON, сессии, созданные до обновления, будут потеряны. Хотя сериализация JSON не поддерживает все объекты Python, как это делает pickle, мы настоятельно рекомендуем использовать сериализованные в JSON сессии. Проверяя свой код, чтобы определить, будет ли сериализация JSON работать в вашем приложении, обратите внимание на следующее:

  • JSON требует строковых ключей, поэтому вы, скорее всего, столкнетесь с проблемами, если будете использовать нестроковые ключи в request.session.
  • Установка истечения срока действия сессии путем передачи значений datetime в set_expiry() не будет работать, поскольку значения datetime не сериализуемы в JSON. Вместо этого вы можете использовать целочисленные значения.

Более подробную информацию см. в документации Сериализация сеанса.

Изменения в объектно-реляционном картографе

Django 1.6 содержит множество изменений в ORM. Эти изменения в основном делятся на три категории:

  1. Исправления ошибок (например, правильные условия присоединения для общих отношений, объединение запросов, продвижение присоединения и обрезка присоединения)
  2. Подготовка к новым возможностям. Например, ORM теперь внутренне готов к многоколоночным внешним ключам.
  3. Генеральная уборка.

Эти изменения могут привести к некоторым проблемам совместимости. Например, некоторые запросы теперь будут генерировать разные псевдонимы таблиц. Это может повлиять на QuerySet.extra(). Кроме того, некоторые запросы теперь будут давать разные результаты. Примером может служить exclude(condition), где условие является сложным (обращение к многосвязным соединениям внутри Q objects). Во многих случаях затронутые запросы не давали правильных результатов в Django 1.5, но теперь дают. К сожалению, есть также случаи, которые дают разные результаты, но ни Django 1.5, ни 1.6 не выдают правильных результатов.

Наконец, было внесено много изменений во внутренние API ORM.

Разное

  • django.db.models.query.EmptyQuerySet больше не может быть инстанцирован - он используется только как класс-маркер для проверки, был ли вызван none(): isinstance(qs.none(), EmptyQuerySet)

  • Если ваш код CSS/JavaScript использовал доступ к виджетам ввода HTML по типу, вам следует пересмотреть его, поскольку виджеты type='text' теперь могут быть выведены как type='email', type='url' или type='number' в зависимости от соответствующего типа поля.

  • Поле формы error_messages, содержащее заполнитель, теперь всегда должно использовать именованный заполнитель ("Value '%(value)s' is too big" вместо "Value '%s' is too big"). Подробности об именах заполнителей см. в документации к соответствующему полю. Изменения в версии 1.6 особенно затрагивают DecimalField и ModelMultipleChoiceField.

  • Некоторые error_messages для IntegerField, EmailField, IPAddressField, GenericIPAddressField и SlugField были подавлены, поскольку они дублировали сообщения об ошибках, уже предоставленные валидаторами, привязанными к полям.

  • Из-за изменения рабочего процесса валидации формы, метод TypedChoiceField coerce всегда должен возвращать значение, присутствующее в атрибуте поля choices. Это ограничение должно быть снова снято в Django 1.7.

  • Были внесены изменения в способ обработки таймаутов в бэкендах кэша. Явная передача timeout=None больше не приводит к использованию таймаута по умолчанию. Теперь будет установлен неистекающий таймаут. Передача 0 в бэкенд memcache больше не использует таймаут по умолчанию, теперь значение будет устанавливаться и сразу же истекать.

  • Приложение django.contrib.flatpages использовало установку пользовательских HTTP-заголовков в целях отладки. Эта функциональность не была документирована и делала кэширование неэффективным, поэтому она была удалена вместе с ее общей реализацией, ранее доступной в django.core.xheaders.

  • XViewMiddleware был перемещен из django.middleware.doc в django.contrib.admindocs.middleware, потому что это деталь реализации admindocs, доказавшая свою непригодность для повторного использования в целом.

  • GenericIPAddressField теперь будет разрешать значения blank только в том случае, если значения null также разрешены. Создание GenericIPAddressField, в котором blank разрешено, а null нет, вызовет ошибку проверки модели, поскольку значения blank всегда хранятся как null. Ранее хранение значения blank в поле, которое не допускает null, вызывало исключение базы данных во время выполнения.

  • Если при рендеринге шаблона в методе возникает исключение NoReverseMatch, оно не заглушается. Например, {{ obj.view_href }} приведет к сбою рендеринга шаблона, если view_href() вызовет NoReverseMatch. Для тега {% url %} никаких изменений нет, он вызывает отрисовку шаблона, как всегда, при возникновении NoReverseMatch.

  • django.test.Client.logout() теперь вызывает django.contrib.auth.logout(), который пошлет сигнал user_logged_out().

  • Authentication views теперь инвертируются по имени, а не по их расположению в django.contrib.auth.views. Если вы используете представления без name, вам следует обновить ваши urlpatterns, чтобы использовать django.conf.urls.url() с параметром name. Например:

    (r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete')
    

    становится:

    url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete')
    
  • RedirectView теперь имеет атрибут pattern_name, который позволяет ему выбирать цель путем инверсии URL.

  • В Django 1.4 и 1.5 пустая строка непреднамеренно не считалась действительным паролем. Это означало, что set_password() сохранит пустой пароль как непригодный для использования, как это делает set_unusable_password(), и, таким образом, check_password() всегда возвращал False для пустых паролей. Это исправлено в данном выпуске: пустые пароли теперь действительны.

  • Администратор changelist_view ранее принимал GET-параметр pop, чтобы указать, что он должен отображаться во всплывающем окне. Этот параметр был переименован в _popup, чтобы соответствовать остальным представлениям администратора. Вам следует обновить свои пользовательские шаблоны, если в них используется прежнее имя параметра.

  • validate_email() теперь принимает адреса электронной почты с localhost в качестве домена.

  • Опция new makemessages --keep-pot предотвращает удаление временного файла .pot, созданного перед созданием файла .po.

  • Недокументированная django.core.servers.basehttp.WSGIServerException была удалена. Вместо этого используйте socket.error, предоставляемый стандартной библиотекой. Это изменение также было выпущено в Django 1.5.5.

  • Сигнатура django.views.generic.base.RedirectView.get_redirect_url() изменилась и теперь также принимает позиционные аргументы (*args, **kwargs). Любая неименованная захваченная группа теперь будет передаваться в get_redirect_url(), что может привести к TypeError, если вы не обновите сигнатуру вашего пользовательского метода.

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

API для управления транзакциями

Управление транзакциями было полностью переработано в Django 1.6, и текущие API устарели:

  • django.middleware.transaction.TransactionMiddleware
  • django.db.transaction.autocommit
  • django.db.transaction.commit_on_success
  • django.db.transaction.commit_manually
  • установка TRANSACTIONS_MANAGED

django.contrib.comments

Фреймворк комментариев Django был устаревшим и больше не поддерживается. Он будет доступен в Django 1.6 и 1.7, и будет удален в Django 1.8. Большинству пользователей будет лучше использовать собственные решения или хостинговые продукты, такие как Disqus.

Код, ранее известный как django.contrib.comments, стал still available in an external repository.

Поддержка версий PostgreSQL старше 8.4

В декабре 2011 года закончился срок поддержки PostgreSQL 8.2, а в феврале 2013 года - 8.3. Как следствие, Django 1.6 устанавливает 8.4 в качестве минимальной версии PostgreSQL, которую он официально поддерживает.

Настоятельно рекомендуется использовать самую последнюю доступную версию PostgreSQL, чтобы повысить производительность и воспользоваться преимуществами встроенной потоковой репликации, доступной в PostgreSQL 9.x.

Изменения в cycle и firstof

Система шаблонов обычно экранирует все переменные, чтобы избежать XSS-атак. Однако, по исторической случайности, теги cycle и firstof выводят свои аргументы как есть.

Django 1.6 начинает процесс исправления этого несоответствия. Библиотека шаблонов future предоставляет альтернативные реализации cycle и firstof, которые автоэскейпируют свои входы. Если вы используете эти теги, вам рекомендуется включить следующую строку в верхнюю часть ваших шаблонов, чтобы включить новое поведение:

{% load cycle from future %}

или:

{% load firstof from future %}

Теги, реализующие старое поведение, были устаревшими, и в Django 1.8 старое поведение будет заменено новым. Для обеспечения совместимости с будущими версиями Django, существующие шаблоны должны быть изменены для использования версий future.

При необходимости вы можете временно отключить автоэскейп с помощью mark_safe() или {% autoescape off %}.

CACHE_MIDDLEWARE_ANONYMOUS_ONLY установка

CacheMiddleware и UpdateCacheMiddleware раньше предоставляли возможность кэшировать запросы, только если они были сделаны не вошедшим в систему пользователем. Этот механизм был в значительной степени неэффективен, поскольку промежуточное ПО правильно учитывает HTTP-заголовок Vary: Cookie, а этот заголовок устанавливается в самых разных случаях, например:

  • доступ к сессии, или
  • используя защиту CSRF, которая включена по умолчанию, или
  • использование библиотеки на стороне клиента, которая устанавливает cookies, например Google Analytics.

Это заставляет кэш эффективно работать на основе каждой сессии независимо от настройки CACHE_MIDDLEWARE_ANONYMOUS_ONLY.

Метод _has_changed на виджетах

Если вы определили собственные виджеты формы и определили метод _has_changed на виджете, то теперь вы должны определить этот метод на самом поле формы.

module_name атрибут _meta модели

Model._meta.module_name был переименован в model_name. Несмотря на то, что это частный API, он пройдет через обычный путь депривации.

get_(add|change|delete)_permission методы модели _meta

Model._meta.get_(add|change|delete)_permission методы были устаревшими. Даже если они не были частью публичного API, они также пройдут через обычный путь обесценивания. Вы можете заменить их на django.contrib.auth.get_permission_codename('action', Model._meta), где 'action' - это 'add', 'change' или 'delete'.

get_query_set и подобные методы переименованы в get_queryset

Методы, возвращающие QuerySet, такие как Manager.get_query_set или ModelAdmin.queryset, были переименованы в get_queryset.

Если вы пишете библиотеку, реализующую, например, метод Manager.get_query_set, и вам нужно поддерживать старые версии Django, вам следует переименовать метод и условно добавить псевдоним со старым именем:

class CustomManager(models.Manager):
    def get_queryset(self):
        pass # ...

    if django.VERSION < (1, 6):
        get_query_set = get_queryset

    # For Django >= 1.6, models.Manager provides a get_query_set fallback
    # that emits a warning when used.

Если вы пишете библиотеку, которая должна вызывать метод get_queryset и должна поддерживать старые версии Django, вам следует написать:

get_queryset = (some_manager.get_query_set
                if hasattr(some_manager, 'get_query_set')
                else some_manager.get_queryset)
return get_queryset() # etc

В общем случае пользовательского менеджера, который реализует свой собственный метод get_queryset и вызывает этот метод, а также должен работать со старыми версиями Django и библиотеками, которые еще не обновлены, полезно определить метод get_queryset_compat, как показано ниже, и использовать его внутри вашего менеджера:

class YourCustomManager(models.Manager):
    def get_queryset(self):
        return YourCustomQuerySet() # for example

    if django.VERSION < (1, 6):
        get_query_set = get_queryset

    def active(self): # for example
        return self.get_queryset_compat().filter(active=True)

    def get_queryset_compat(self):
        get_queryset = (self.get_query_set
                        if hasattr(self, 'get_query_set')
                        else self.get_queryset)
        return get_queryset()

Это помогает минимизировать необходимые изменения, а также корректно работает в случае подклассов (таких как RelatedManagers из Django 1.5), которые могут переопределять get_query_set или get_queryset.

shortcut просмотр и URLconf

Представление shortcut было перемещено из django.views.defaults в django.contrib.contenttypes.views вскоре после релиза 1.0, но старое расположение так и не было устаревшим. Эта оплошность была исправлена в Django 1.6, и теперь вам следует использовать новое расположение.

URLconf django.conf.urls.shortcut также был устаревшим. Если вы включаете его в URLconf, просто замените:

(r'^prefix/', include('django.conf.urls.shortcut')),

с:

(r'^prefix/(?P<content_type_id>\d+)/(?P<object_id>.*)/$', 'django.contrib.contenttypes.views.shortcut'),

ModelForm без fields или exclude

Раньше, если вы хотели, чтобы ModelForm использовал все поля модели, вы могли просто опустить атрибут Meta.fields, и все поля были использованы.

Это может привести к проблемам безопасности, когда поля добавляются в модель и непреднамеренно автоматически становятся доступными для редактирования конечным пользователям. В некоторых случаях, особенно при использовании булевых полей, эта проблема может быть совершенно незаметной. Это форма Mass assignment vulnerability.

По этой причине такое поведение является устаревшим, и использование опции Meta.exclude настоятельно не рекомендуется. Вместо этого все поля, предназначенные для включения в форму, должны быть явно перечислены в атрибуте fields.

Если эта проблема безопасности действительно не применима в вашем случае, есть короткий способ явно указать, что все поля должны быть использованы - используйте специальное значение "__all__" для атрибута fields:

class MyModelForm(ModelForm):
    class Meta:
        fields = "__all__"
        model = MyModel

Если у вас есть пользовательские ModelForms, которые нужно использовать только в админке, есть другой вариант. В админке есть свои методы определения полей (fieldsets и т.д.), поэтому добавление списка полей в ModelForm является излишним. Вместо этого просто опустите внутренний класс Meta в ModelForm, или опустите атрибут Meta.model. Поскольку подкласс ModelAdmin знает, для какой модели он предназначен, он может добавить необходимые атрибуты, чтобы получить функционирующий ModelForm. Это поведение работает и для более ранних версий Django.

UpdateView и CreateView без явных полей

Общие представления CreateView и UpdateView, а также все остальное, производное от ModelFormMixin, уязвимы к проблеме безопасности, описанной в разделе выше, поскольку они могут автоматически создавать ModelForm, использующие все поля модели.

По этой причине, если вы используете эти представления для редактирования моделей, вы должны также предоставить атрибут fields (новый в Django 1.6), который представляет собой список полей модели и работает так же, как атрибут ModelForm Meta.fields. В качестве альтернативы, вы можете установить атрибут form_class в ModelForm, который явно определяет поля, которые будут использоваться. Определение подкласса UpdateView или CreateView для использования с моделью, но без явного списка полей, является устаревшим.

Изменение текста справки полей формы модели для полей ManyToManyField

Все специальные обработки атрибута help_text полей модели ManyToManyField, выполняемые стандартными полями модели или полями формы модели, как описано в Справочный текст полей формы модели для полей ManyToManyField выше, устарели и будут удалены в Django 1.8.

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

Вернуться на верх