О релизе Django 1.4

23 марта 2012

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

These release notes cover the new features, as well as some backwards incompatible changes you’ll want to be aware of when upgrading from Django 1.3 or older versions. We’ve also dropped some features, which are detailed in our deprecation plan, and we’ve begun the deprecation process for some features.

Обзор

Самым важным изменением стало `support for time zones`_, которая учитывает разницу даты/времени. Если эта опция включена, то Django сохраняет дату/время в формате UTC и переводит его в часовой пояс пользователя для отображения.

Если вы обновляете существующий проект до версии 1.4, перевод на новую функциональность требует осторожности: новый режим запрещает некоторое неряшливое поведение, которое было принято ранее. Мы призываем всех обратить внимание на timezone migration guide и timezone FAQ.

Другие изменения в Django 1.4:

Везде, где это возможно, мы стараемся поддерживать обратную совместимость согласно политике our API stability policy. Однако, как и предыдущие версии, Django 1.4 ломает некоторую совместимость (backwards incompatible changes). Будьте осторожны при обновлении с предыдущих версий.

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

Django 1.4 более не поддерживает Python 2.4. Теперь минимальной версией является Python 2.5. Этот релиз мы протестировали на Python 2.5, 2.6, 2.7.

Это изменение должно затронуть лишь небольшое число пользователей, т.к. большинство ОС поставляется с Python 2.5 или чем-то поновее. Если у вас нет возможности уйти с Python 2.4, то лучше оставайтесь на 1.3. Согласно our support policy мы будем выпускать обновления безопасности вплоть до выпуска Django 1.5.

Django пока ещё не поддерживает Python 3.x, но в скором времени мы планируем опубликовать документ с планом перехода на Python 3.x.

Что нового в Django 1.4

Поддержка часовых поясов.

В предыдущих версиях Django использует “наивную” дату/время (без указания временной зоны), соответственно, каждый разработчик должен сам следить за тем, что же она означает по местному времени. Это провоцировало много ошибок.

В Django 1.4 вы можете активировать поддержку временных зон. В этом случае дата будет записываться в базу данных в формате UTC, а используя time-zone-объекты перевод в тайм-зону пользователя будет происходить автоматически. Это может понадобиться в следующих случаях:

  • Настройка отображения даты и времени для пользователей по всему миру.

  • Сохранение даты/времени в формате UTC обеспечивает совместимость и переносимость. Это не относится к PostgreSQL, потому что это уже реализовано в Django 1.3.

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

Поддержка временных зон включена по умолчанию для новых проектов, созданных с помощью startproject. Если вы хотите его включить в существующем проекте, обратитесь к migration guide. При возникновении проблем загляните в FAQ.

Поддержка фреймворков для тестирования в браузере

Django 1.4 поддерживает интеграцию с фреймворками для тестирования в браузере типа Selenium. Новый класс django.test.LiveServerTestCase позволяет тестировать взаимодействие клиентской и серверной части. Подробную информацию и примеры можно найти в documentation.

Обновлён шаблон нового проекта и manage.py

Django 1.4 поставляется с обновлённым шаблоном для нового приложения, который создаётся командой startproject. Он исправляет несколько ошибок, связанных с дублирующим импортом, трудностями развертывания и прочими сложными в отладке проблемами.

Предыдущий manage.py использовал функциональность, которая стала устаревшей, так что надо бы обновить и его в проекте. Но можно пока не торопиться - он будет работать до версии 1.6, правда, в 1.5 вам напомнят исключением DeprecationWarning.

Новый рекомендуемый manage.py должен выглядеть как-то так:

#!/usr/bin/env python
import os, sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

где {{ project_name }} – имя вашего приложения.

Если настройки, пути и приложения импортируются в рамках проекта с помощью имени префикса (например, myproject.settings, ROOT_URLCONF = "myproject.urls"), то новый manage.py должен быть перемещён на директорию выше относительно settings.py и urls.py.

Например, как-то так:

manage.py
mysite/
    __init__.py
    settings.py
    urls.py
    myapp/
        __init__.py
        models.py

Вы должны импортировать mysite.settings, mysite.urls, mysite.myapp, а не settings, urls, myapp в виде модулей верхнего уровня.

Всё, что импортируется как модуль верхнего уровня, может быть размещено рядом с новым manage.py. Например, чтобы отделить “myapp” от проекта и импортировать его просто как myapp, просто вынесите его из каталога mysite/:

manage.py
myapp/
    __init__.py
    models.py
mysite/
    __init__.py
    settings.py
    urls.py

Если же импорт идёт непоследовательно (где-то с префиксом проекта, где-то без), то его необходимо почистить при обновлении manage.py.

Пользовательские проекты и шаблоны приложений

Команды startapp и startproject теперь имеют опцию --template для указания пути или URL до пользовательского приложения или шаблона.

Например, Django будет использовать каталог /path/to/my_project_template при выполнении следующего кода:

django-admin.py startproject --template=/path/to/my_project_template myproject

Вы также можете указать каталог назначения вторым аргументом к startapp и startproject:

django-admin.py startapp myapp /path/to/new/app
django-admin.py startproject myproject /path/to/new/project

За подробностями обратитесь к startapp и startproject.

Улучшение поддержки WSGI

Команда startproject теперь добавляет в новый проект файл wsgi.py, содержащий простое приложение WSGI, которое используется deploying with WSGI app servers.

built-in development server теперь поддерживает внешние определения вызовов WSGI, что даёт возможность запустить runserver с конфигурацией на боевом сервере. Новая настройка WSGI_APPLICATION определяет какие вызовы WSGI использует runserver.

(Команда runfcgi является обёрткой для WSGI, настроенной с помощью WSGI_APPLICATION.)

Поддержка SELECT FOR UPDATE

В Django 1.4 есть метод QuerySet.select_for_update(), который генерирует SQL запрос SELECT ... FOR UPDATE. Это блокирует записи до окончания транзакции, так что остальные пользователи не смогут их изменить или удалить.

За подробностями обратитесь к select_for_update().

Model.objects.bulk_create в ORM

Этот метод позволяет создавать несколько объектов более эффективно. Это может привести к значительному увеличению производительности, если у вас много объектов.

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

Подробнее описано в bulk_create().

Улучшенное хеширование паролей

Система аутентификации Django (django.contrib.auth) хранит пароли с односторонним алгоритмом шифрования. Django 1.3 использует SHA1, однако с ростом производительности компьютеров риск успешной атаки всё повышается. В Django 1.4 представлена новая система хранения паролей, основанная на алгоритме PBKDF2 (рекомендован NIST). Тем не менее вы можете указать свой, например, популярный bcrypt. Для подробностей смотрите в Как Django хранит пароли.

Поддержка HTML5

В админке и прочих стандартных шаблонах мы теперь используем тип документа HTML5. В то же время Django старается сохранить совместимость со старыми браузерами. Это изменение позволяет использовать возможности HTML5 без потери корректности HTML, а также указать самому тип документа.

Фильтрация списков в интерфейса администратора

До Django 1.4 admin позволяло указывать значения отдельных полей без возможности создания своих фильтров. Это было исправлено с помощью небольшого API (ранее использовался внутренний “FilterSpec”). Подробнее можно прочитать здесь list_filter.

Множественная сортировка в интерфейсе администратора

Теперь в админке можно указывать сортировку по нескольким столбцам. Учитываются все элементы, указанные в атрибуте ordering. Поведение взято из настольного GUI - достаточно кликнуть по заголовку столбца. Мы также добавили метод get_ordering() для указания сортировки динамически, например, в зависимости от запроса.

Новые методы в ModelAdmin

Мы добавили метод save_related() в модель ModelAdmin для возможности управления сохранением связанных объектов.

Два других новых метода класса ModelAdmin get_list_display() и get_list_display_links() включают динамическое управление полями и ссылками, которые будут показаны в таблицах админки.

Проверка прав в панели администратора

В админке теперь доступны только те действия, на которые пользователь имеет разрешения. Для отношения ManyToMany, когда создаётся модель, на которую пользователь не имеет явных прав, они определяются из прав на отношение.

Инструменты для криптографических подписей

Django 1.4 добавляет как низкоуровневые, так и высокоуровневые средства для работы с куками, которые являются одним из самых распространённых способов подписи веб-приложения.

Подробнее можно посмотреть здесь cryptographic signing.

Новый FormWizard

The previous FormWizard from django.contrib.formtools has been replaced with a new implementation based on the class-based views introduced in Django 1.3. It features a pluggable storage API and doesn’t require the wizard to pass around hidden fields for every previous step.

Django 1.4 поставляется с возможностью хранения информации пользователя в сессиях или куках. Последние имеют инструменты для cryptographic signing, которые введены в Django 1.4 для хранения состояния помощника (wizard`а) в куках.

reverse_lazy

Ленивая версия вычисления django.core.urlresolvers.reverse() была добавлена для расшифровки URL до загрузки URLconf.

Трансляция шаблонов URL

С помощью функции хэлпера i18n_patterns() Django теперь может учитывать языковой префикс в URL. Благодаря ugettext_lazy() стало возможным определять URL для интернационализации. Смотри Интернационализация: в шаблонах URL для информации об использовании языковых префиксов и интернационализации шаблонов URL.

Поддержка контекстного перевода для {% trans %} и {% blocktrans %}

Поддержка contextual translation была введена в Django 1.3 с помощью функции pgettext, которая расширяла теги trans и blocktrans через ключевое слово context.

Настройка SingleObjectMixin URLConf kwargs

Два новых атрибута pk_url_kwarg и slug_url_kwarg были добавлены в класс SingleObjectMixin для возможности настройки URLconf через единственный общий объект представления.

Связывание тегов шаблонизатора

Новая функция assignment_tag была добавлена в template.Library для упрощения создания тегов, которые хранят данные в контекстной переменной.

Поддержка *args и **kwargs для хэлперов тегов

The simple_tag, inclusion_tag and newly introduced assignment_tag template helper functions may now accept any number of positional or keyword arguments. For example:

@register.simple_tag
def my_tag(a, b, *args, **kwargs):
    warning = kwargs['warning']
    profile = kwargs['profile']
    ...
    return ...

Тогда в шаблоне любое число аргументов может быть передано в тег:

{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}

Обёртывание исключений в режиме TEMPLATE_DEBUG

In previous versions of Django, whenever the TEMPLATE_DEBUG setting was True, any exception raised during template rendering (even exceptions unrelated to template syntax) were wrapped in TemplateSyntaxError and re-raised. This was done in order to provide detailed template source location information in the debug 500 page.

In Django 1.4, exceptions are no longer wrapped. Instead, the original exception is annotated with the source information. This means that catching exceptions from template rendering is now consistent regardless of the value of TEMPLATE_DEBUG, and there’s no need to catch and unwrap TemplateSyntaxError in order to catch other errors.

Фильтр шаблона truncatechars

Новый фильтр урезает строку до определённого количества символов. Обрезанная строка заканчивается последовательностью ”...”. Подробнее в документации по truncatechars.

Тег шаблона static

В модуль staticfiles добавлен новый тег шаблонизатора static, который позволяет указать на файл, который был сохранён с помощью STATICFILES_STORAGE. Он поддерживает метод url, так что позволяет serving files from a cloud service.

Поддержка бэкенда CachedStaticFilesStorage

В модуль staticfiles добавлен класс бэкенда CachedStaticFilesStorage, который кэширует файлы при сохранении (при запуске команды collectstatic), добавляя MD5 к имени файла. Например, файл css/styles.css будет сохранён как css/styles.55e7cbb9ba48.css.

Подробнее описано здесь CachedStaticFilesStorage.

Простая защита от кликджекинга

Мы добавили поддержку защиты от clickjacking, который использует атрибут заголовка X-Frame-Options. Из-за обратной совместимости она отключена по умолчанию; как её включить можно посмотреть в enable it, чтобы обезопасить пользователей браузеров, которые поддерживают этот заголовок.

Улучшение CSRF

We’ve made various improvements to our CSRF features, including the ensure_csrf_cookie() decorator, which can help with AJAX-heavy sites; protection for PUT and DELETE requests; and the CSRF_COOKIE_SECURE and CSRF_COOKIE_PATH settings, which can improve the security and usefulness of CSRF protection. See the CSRF docs for more information.

Фильтрации отчётов об ошибках

Мы добавили два декоратора функций (sensitive_variables() и sensitive_post_parameters()) для обработки переменных и POST-параметров с целью исключения какой-либо персонализированной информации из отчётов об ошибках.

Все POST-параметры теперь постоянно фильтруют вывод отчёта для определённых представлений (login, password_reset_confirm, password_change и add_view в модуле django.contrib.auth.views, известном также как user_change_password в админке) для предотвращения утечки информации, например, паролей.

Вы можете перекрыть поведение по умолчанию, написав свой фильтр custom filter. Подробнее можно прочитать в Filtering error reports.

Расширена поддержка IPv6

В Django 1.4 улучшена поддержка IPv6 с помощью нового класса поля модели GenericIPAddressField, поля формы GenericIPAddressField и валидаторов validate_ipv46_address и validate_ipv6_address.

Сравнение HTML в тестах

В базовый класс тестов django.test добавлены хелперы для нестрого сравнения HTML, исключающие несовпадение пробелов, кавычки аргументов, их порядок. Вы можете сравнить непосредственно два HTML-документа через новые методы assertHTMLEqual() и assertHTMLNotEqual() или использовать флаг html=True в методе assertContains() и assertNotContains() для проверки что же отдаётся клиенту. Смотрите документацию по assertions documentation.

Два новых формата даты

Два новых формата date добавлены в фильтры шаблонов, тегов и Формат локализации:

  • e – название временной зоны у объекта даты/времени

  • o – номер года по ISO 8601

Если вы используете e или o, обновитесь согласно custom format files. Например, для локализации на испанский экранируйте аналогично d:

DATE_FORMAT = r'j \de F \de Y'

Теперь же нужно экранировать и e с o:

DATE_FORMAT = r'j \d\e F \d\e Y'

Подробнее можно посмотреть в документации к date.

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

Django 1.4 включает в себя также несколько небольших изменений:

  • Улучшенная техническая страница ошибки 500. Фреймы стека, которые относятся к коду Django, затемнены, а код приложения подсвечен. Это облегчит разбор ошибок приложения.

  • Tablespace support в PostgreSQL.

  • Настраиваемые имена для simple_tag().

  • Посмотрите раздел security overview в документации.

  • Функция django.contrib.auth.models.check_password перемещена в модуль django.contrib.auth.hashers. Старый импорт всё ещё работает, но рекомендуется его обновить.

  • Команда collectstatic обзавелась опцией --clear, при указании которой перед копированием все старые файлы будут удалены.

  • Стало возможным использовать для MySQL/InnoDB фикстуры со сложными зависимостями.

  • Новый обработчик ошибки 403 добавлен как 'django.views.defaults.permission_denied'. Вы можете указать свой обработчик в django.conf.urls.handler403. Подробнее можно посмотреть в документации по the 403 (HTTP Forbidden) view.

  • Команда makemessages использует новый более точный лексер JsLex для получения строк для локализации из файлов JavaScript.

  • Тег шаблонизатора trans теперь принимает опциональный аргумент as, чтобы получить строку перевода без её отображения, а вместо этого настроить какую-либо контекстную переменную.

  • Тег шаблонизатора if теперь поддерживает {% elif %}.

  • Если вы используете Django за прокси, то вам может пригодиться новая настройка SECURE_PROXY_SSL_HEADER. Она решает проблему, когда прокси отбрасывает тот факт, что запрос пришёл через HTTPS. Используёте её только когда точно понимаете, что вы делаете.

  • Новая, текстовая, версия HTTP ошибки 500, которая показывается при DEBUG равным True, теперь отсылает код JavaScript, в том случае, если Django узнает, что ошибка произошла в AJAX-запросе (метод is_ajax()).

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

    Это должно помочь при отладке взаимодействия клиентского JavaScript и серверной части.

  • Добавление опции --no-location в команду makemessages

  • Вместо бэкенда кэша locmem следует использовать pickle.HIGHEST_PROTOCOL для лучшей совместимости с остальными кэширующими бэкендами.

  • В ORM добавлена поддержка DISTINCT ON для запросов SELECT.

    Метод distinct() у QuerySet теперь может опционально принимать список полей модели. Если он указан, то выражение DISTINCT действует только на эти поля. Поддерживается пока только в PostgreSQL.

    Подробнее в документации distinct().

  • В страницу входа в админку добавлена ссылка на восстановление пароля, если в urls.py добавлена ‘admin_password_reset’. Теперь подключить встроенный механизм сброса пароля стало ещё проще. За подробностями обратитесь к Добавление возможности сброса пароля.

  • В поддержку MySQL добавлена функциональность по работе с точками сохранения, которые были реализованы в версии 5.0.3 для движка InnoDB.

  • Стало возможным передавать начальные значение в форму модели, которая представляет из себя набор форм, построенных с помощью modelformset_factory или inlineformset_factory. Тем не менее, начальные значения применяются только к дополнительным формам, то есть те, которые не связаны с существующего экземпляра модели.

  • В поддержку карты сайта добавлена возможность работы с HTTPS-ссылками, которая реализована с помощью атрибута Sitemap.protocol.

  • Новый класс django.test.SimpleTestCase, потомок unittest.TestCase, который легче, чем django.test.TestCase и прочие. Его следует применять, когда не требуется подключение к БД, подробнее в Иерархия классов для тестов в Django.

Обратная несовместимость в 1.4

SECRET_KEY теперь обязателен

Работа сайта с пустой или известной злоумышленнику настройкой SECRET_KEY сразу нивелирует многие средства защиты вплоть до выполнения чужого кода. Ни один сайт на Django не должен запускаться без этой настройки.

В Django 1.4 запуск сайта без SECRET_KEY вызовет DeprecationWarning. В Django 1.5 будет исключение, что приведёт к отказу выполнения. Этот ускоренный путь устаревания поведения был выбран из-за серьёзности последствий при работе без SECRET_KEY.

django.contrib.admin

Включаемое по умолчанию приложение django.contrib.admin долгое время поставлялось с набором статики: JavaScript, CSS, картинки... В Django 1.3 Добавлено новое приложение django.contrib.staticfiles для обработки этих файлов в общем виде и определения соглашений для всех включённых приложений.

Начиная с Django 1.4, файлы статики для админки следуют этому соглашению, что должно упростить развертывание проекта. В предыдущей версии была добавлена настройка ADMIN_MEDIA_PREFIX, которая указывала на местоположение этих файлов. На данный момент она считается устаревшей и заменена на более общую STATIC_URL. Django будет искать файлы для админки по адресу <STATIC_URL>/admin/.

Если у вас используется ADMIN_MEDIA_PREFIX (например, /media/) убедитесь, что настройки STATIC_URL и STATIC_ROOT заданы верно. Встроенный веб-сервер продолжает работать также, как и раньше. Подробности можно подсмотреть здесь static files howto.

Если ADMIN_MEDIA_PREFIX указывает на какой-либо домен (например, http://media.example.com/admin/), убедитесь, что в STATIC_URL правильный путь – например, http://media.example.com/.

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

Если вы использовали знание внутреннего расположения файлов статики для админки, то вам нужно обновить пути: эти объекты были перемещены из django/contrib/admin/media/ в django/contrib/admin/static/admin/.

Поддерживаемые браузеры для админки

Django не следует какой-либо чёткой политике поддержки браузеров в админке. На практике же это сводится к следующему: браузеры из YUI’s A-grade должны поддерживаться полностью, за исключением IE 6, который снят с поддержки.

IE 6, выпущенный более 10 лет назад, накладывает значительные ограничения на веб-разработку. Если их отбросить, то развивать Django становится гораздо легче.

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

Иконки для админки

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

А именно: selector-add.gif, selector-addall.gif, selector-remove.gif, selector-removeall.gif, selector_stacked-add.gif и selector_stacked-remove.gif слиты в selector-icons.gif; arrow-up.gif и arrow-down.gif в sorting-icons.gif.

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

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

Дабы избежать конфликтов с остальными именами классов CSS (например, “button”), мы добавили префикс (“field-”) ко всем иенам классов, которые генерируются автоматически из имён полей формы, встраиваемых форм и ячеек таблиц. Адаптируйте ваши таблицы стилей и JavaScript код для учёта этого факта.

Совместимость с ранее подписанными данными

В Django 1.3 изменился механизм криптографической подписи данных, который использовался в ряде мест. Для обеспечения совместимости Django 1.3 поддерживал оба метода - и старый, и новый, однако в Django 1.4 обратная совместимость удалена.

Так что, если вы обновляетесь до 1.4 с версии 1.2 или меньшей, вы можете потерять некоторые части данных, которые были подписаны с помощью старого криптографического метода. В данном случае рекомендуется какое-то время использовать Django 1.3, чтобы срок хранения подписанных данных истёк, и они бы шифровались новым алгоритмом. Подверженные этой проблеме данные описаны ниже, где 1) последствия при игнорировании рекомендации 2) время, необходимое для новой подписи данных.

  • проверка целостности данных в contrib.sessions

    • Последствия: Пользователь будет разлогинен, и данные сессии потеряются.

    • Срок перевалидации: Определён в SESSION_COOKIE_AGE.

  • Хеш восстановления пароля в contrib.auth

    • Последствия: Старые ссылки для восстановления пароля перестанут работать.

    • Срок перевалидации: Определён в PASSWORD_RESET_TIMEOUT_DAYS.

Хеши для форм: они имеют очень короткое время жизни. Так что это актуально только когда пользователь заполняет форму, сгенерированную Django до обновления, а отправляет уже в обновлённую версию:

  • Хеш безопасности contrib.comments

    • Последствия: Пользователь увидит ошибку валидации “Security hash failed.”

    • Срок перевалидации: Всё время, пока пользователь пишет комментарий.

  • Хеш безопасности FormWizard

    • Consequences: The user will see an error about the form having expired and will be sent back to the first page of the wizard, losing the data entered so far.
    • Срок перевалидации: Всё время, пока пользователь заполняет форму.

  • Проверка CSRF

    • Замечание: Это актуально для совместимости с Django 1.1 (не Django 1.2), и имеет значение только при обновлении с версии 1.1.

    • Последствия: Пользователь увидит ошибку 403 с сообщением о том, что сработала CSRF-защита.

    • Срок перевалидации: Всё время, пока пользователь заполняет форму.

  • Обновление паролей пользователей через contrib.auth

    • Последствия: При записи в БД пароль пользователя будет обновлён с помощью нового криптостойкого алгоритма. Так что если вы обновитесь до 1.4, а потом откатитесь на 1.3, некоторые пользователи не смогут войти.

    • Лекарство: Установите PASSWORD_HASHERS

django.contrib.flatpages

Начиная с версии 1.4 класс FlatpageFallbackMiddleware только добавляет конечный слэш и перенаправляет на получившийся URL, если такая страница есть в приложении. Например, при запросе /notaflatpageoravalidurl в предыдущей версии шло перенаправление на /notaflatpageoravalidurl/, что порождало исключение, теперь же уже /notaflatpageoravalidurl будет вызывать ошибку 404.

К тому же перенаправление таким образом считается перманентным (с кодом 301) в соответствии с поведением класса CommonMiddleware.

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

В следствии поддержки часовых поясов и согласно спецификации ECMA-262, мы внесли изменения в сериализатор JSON:

  • Для datetime-объектов добавляется временная зона, в случае с time-объектами генерируется исключение.

  • Для datetime- и time-объектов добавлена поддержка миллисекунд. Немного теряется точность, потому что Python хранит микросекунды (6 знаков), а JSON миллисекунды (3 знака). Однако, это всё равно лучше, чем простое их игнорирование в предыдущих версиях.

Мы добавили в XML-сериализатор поддержку формата ISO8601 для даты со временем. Для разделения части даты от части времени используется буква T вместо пробела. Информация по временной зоне включает в себя формат [+-]HH:MM.

Хотя сериализаторы теперь используют новые форматы при создании фикстур, они все еще могут загрузить фикстуры, созданные ранее.

Для SQLite supports_timezone установлен в False

Для SQLite поддержка временных зон может быть включена, однако, если вы сохраняете datetime-объект, SQLite представляет его как строку с указанием UTC. При загрузке же из базы эта информация отбрасывается, что может привести к порче данных.

В контексте поддержки временных зон этот флаг изменён на False, и дата-время сохраняется без этой информации. Когда настройка USE_TZ установлена в False, при попытке сохранения со сведениями UTC произойдёт исключение.

Специфические исключения MySQLdb

Исторически MySQL-бэкенд вызывал MySQLdb.OperationalError, если в запросе происходило исключение. Мы исправили этот баг, теперь вызывается django.db.DatabaseError. Если у вас были завязки на MySQLdb.OperationalError, адаптируйте блок except.

Потокобезопасные соединения с БД

Объекты DatabaseWrapper (включая соединения типа django.db.connection и django.db.connections["что_то_там"]) потокобезопасны. Сейчас они представляют из себя глобальные объекты, дабы имелся доступ из разных потоков. В то время как собственно объекты соединений глобальны, словарь django.db.connections остаётся потокобезопасным. Однако, если вы используете ORM или DatabaseWrapper.cursor(), то заметите некоторое изменение в поведении. Теперь django.db.connection не ссылается напрямую на DatabaseWrapper, а использует прокси для доступа к атрибутам объекта. Если вам всё-таки нужен непосредственно текущий DatabaseWrapper, используйте django.db.connections[DEFAULT_DB_ALIAS].

Как часть изменений все основные соединения SQLite теперь могут быть потенциально доступны из других потоков (передав атрибут check_same_thread=False в pysqlite), однако DatabaseWrapper следует предыдущему поведению, где такой доступ запрещён. Это изменение не затронет тех пользователей, которые работали только с ORM или DatabaseWrapper.cursor().

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

Настройка COMMENTS_BANNED_USERS_GROUP

Django’s comments has historically supported excluding the comments of a special user group, but we’ve never documented the feature properly and didn’t enforce the exclusion in other parts of the app such as the template tags. To fix this problem, we removed the code from the feed class.

Если вам всё-таки нужно старое поведение, используйте свой менеджер моделей для исключения групп пользователей, например:

from django.conf import settings
from django.contrib.comments.managers import CommentManager

class BanningCommentManager(CommentManager):
    def get_query_set(self):
        qs = super(BanningCommentManager, self).get_query_set()
        if getattr(settings, 'COMMENTS_BANNED_USERS_GROUP', None):
            where = ['user_id NOT IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)']
            params = [settings.COMMENTS_BANNED_USERS_GROUP]
            qs = qs.extra(where=where, params=params)
        return qs

Save this model manager in your custom comment app (e.g., in my_comments_app/managers.py) and add it your custom comment app model:

from django.db import models
from django.contrib.comments.models import Comment

from my_comments_app.managers import BanningCommentManager

class CommentWithTitle(Comment):
    title = models.CharField(max_length=300)

    objects = BanningCommentManager()

Настройки IGNORABLE_404_STARTS и IGNORABLE_404_ENDS

До Django 1.4 было возможным исключить из обработки некоторые URL (404 error reporting) путём добавления префикса в IGNORABLE_404_STARTS и суффикса в IGNORABLE_404_ENDS.

Теперь же обе эти настройки переместились в IGNORABLE_404_URLS, в котором хранится список скомпилированных регулярных выражений. Django не будет генерировать ошибку 404 для любого из них.

Однако, IGNORABLE_404_STARTS и IGNORABLE_404_ENDS имели настройки по умолчанию:

IGNORABLE_404_STARTS = ('/cgi-bin/', '/_vti_bin', '/_vti_inf')
IGNORABLE_404_ENDS = ('mail.pl', 'mailform.pl', 'mail.cgi', 'mailform.cgi',
                      'favicon.ico', '.php')

Django не будет определять остались ли у вас всякие /cgi-bin/ или favicon.ico.Теперь по умолчанию списки IGNORABLE_404_URLS, IGNORABLE_404_STARTS и IGNORABLE_404_ENDS пусты.

Если вы настраивали IGNORABLE_404_STARTS или IGNORABLE_404_ENDS, или если хотите сохранить старое поведение по умолчанию, добавьте в файл настроек следующие строки:

import re
IGNORABLE_404_URLS = (
    # for each <prefix> in IGNORABLE_404_STARTS
    re.compile(r'^<prefix>'),
    # for each <suffix> in IGNORABLE_404_ENDS
    re.compile(r'<suffix>$'),
)

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

CSRF-защита распространена на запросы PUT и DELETE

Previously, Django’s CSRF protection provided protection only against POST requests. Since use of PUT and DELETE methods in AJAX applications is becoming more common, we now protect all methods not defined as safe by RFC 2616 – i.e., we exempt GET, HEAD, OPTIONS and TRACE, and we enforce protection on everything else.

Если вы используете методы PUT или DELETE в AJAX-приложениях, изучите instructions about using AJAX and CSRF.

Представление сброса пароля теперь принимает subject_template_name

Представление password_reset в django.contrib.auth теперь принимает параметр subject_template_name, который передаёт форму пароля как аргумент. Если вы используете это представление со своей формой сброса пароля, то убедитесь, что метод save() принимает этот аргумент.

django.core.template_loaders

Начиная с 2005 года это была ссылка на django.template.loader, и теперь мы наконец-то удалили её. Замените в коде django.core.template_loaders на django.template.loader.

django.db.models.fields.URLField.verify_exists

Эта функциональность была удалена в следствии ошибок безопасности и падения производительности. Все вызовы verify_exists должны быть удалены.

django.core.files.storage.Storage.open

Метод open базового класса Storage принимал непонятный параметр mixin, который позволял динамически менять класс возвращаемого файлового объекта. Теперь он удалён. В тех редких случаях, когда он всё же использовался, вы можете адаптировать код, переопределив метод open:

from django.core.files import File
from django.core.files.storage import FileSystemStorage

class Spam(File):
    """
    Spam, spam, spam, spam and spam.
    """
    def ham(self):
        return 'eggs'

class SpamStorage(FileSystemStorage):
    """
    A custom file storage backend.
    """
    def open(self, name, mode='rb'):
        return Spam(open(self.path(name), mode))

Десериализатор YAML теперь использует yaml.safe_load

yaml.load может построить любой объект Python, который может выполнить любой код из ненадёжного источника. Это функция не нужна непосредственно десериализатору YAML для Django, которой использует загрузку фикстур только примитивных объектов. Так что для обеспечения безопасности теперь используется yaml.safe_load.

По умолчанию сессионные куки имеют флаг httponly

Сессионные куки теперь идут по умолчанию вместе с атрибутом httponly для избежания потенциальных XSS атак. Вследствие этого некоторые вещи (например, sessionid) более недоступны для JavaScript для большинства браузеров. Для совместимости вы можете вернуть старое поведение, указав в настройках SESSION_COOKIE_HTTPONLY = False.

Фильтр urlize более не экранирует каждый URL

Если URL содержит %xx, где xx - числа, то urlize понимает, что этот URL уже экранирован и не пытается проделать это ещё раз. Такое поведение неверно для URL, которые содержат последовательность %xx, но вряд ли они появятся в реальном окружении, к тому же браузеры не смогут правильно понять куда же им идти.

assertTemplateUsed и assertTemplateNotUsed как менеджеры контекстов

Теперь стало возможным проверить используется ли шаблон в блоке кода с помощью методов assertTemplateUsed() и assertTemplateNotUsed(). Эти методы можно использовать как менеджеры контекстов:

with self.assertTemplateUsed('index.html'):
    render_to_string('index.html')
with self.assertTemplateNotUsed('base.html'):
    render_to_string('index.html')

Подробнее здесь assertion documentation.

Соединения к БД после запуска тестов

Исполнитель тестов более не восстанавливает соединение с БД после выполнения тестов. Это предотвращает боевую базу от потенциального воздействия потоков, которые будут висеть и порождать новые соединения.

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

Вывод manage.py help

manage.py help теперь группирует доступные команды по приложениям. Если вы зависели от этого вывода – например, парсили его – адаптируйте свой код. Получить список всех доступных команд можно с помощью manage.py help --commands.

Тег шаблона extends

Ранее тег extends использовал примитивный алгоритм разбора аргументов, ошибочно считая строкой то, что по сути не было ею. Теперь же parser.compile_filter работает также, как и остальные теги.

Внутренности этого тега не были частью публичного API, но в интересах реализации ExtendsNode.__init__ изменилось, что может сказаться на совместимости с тегами, основанными на этом классе.

Загрузка неполных фикстур более не поддерживается

До версии 1.4 для полей даты и времени в модели можно было указать значения auto_now и auto_now_add при загрузке фикстур. Это работало не всегда так, как хотелось, и в 1.4 было решено убрать такую возможность, потому что фикстуры загружались в “сыром” виде, вне зависимости от опций модели.

Многопоточность встроенного сервера

Встроенный сервер теперь по умолчанию запускается в многопоточном режиме. Для отключения этой функциональности используйте опцию --nothreading:

django-admin.py runserver --nothreading

Отключены атрибуты в разметке при активации безопасного режима

До Django 1.4 атрибуты были включены в вывод разметки вне зависимости от настроек безопасности фильтра. В версии 2.1 в библиотеку Python-Markdown была добавлена опция enable_attributes. При установке safe_mode=True и enable_attributes=False в фильтр будут передаваться безопасные аргументы. Использование версии Python-Markdown < 2.1, приведёт к предупреждению безопасности.

get_initial у FormMixin возвращает изначальный словарь

В Django 1.3 метод get_initial класса django.views.generic.edit.FormMixin возвращал класс initial словаря. Мы решили возвращать копию словаря, так как экземпляры форм могли модифицировать исходные данные без изменения переменной класса.

Устаревшая функциональность в 1.4

Старый стиль вызова декоратора cache_page

Некоторые вызовы cache_page() стали устаревшими. Обратитесь к документации для правильного использования этого декоратора.

Поддержка версий PostgreSQL меньше 8.2

Django 1.3 не работает с PostgreSQL младше 8.0, и мы настоятельно рекомендуем использовать более новые версии, тем более что срок окончания поддержки 8.0 и 8.1 уже близок (ноябрь 2010).

В Django 1.4 мы учли это и сделали версию 8.2 минимально поддерживаемой.

Исключения в запросе теперь всегда логгируются

После того как мы добавили logging support в Django 1.3, оповещение администратора по email было перемещено в класс django.utils.log.AdminEmailHandler, который прикреплялся к логгеру django.request. В целях совместимости с предыдущим поведением логгер django.request будет вызван только если DEBUG установлен в False.

Для увеличения гибкости регистрации ошибок запросов логгер 'django.request' сейчас вызывается независимо от значения DEBUG, однако в новом проекте по умолчанию добавлен фильтр в django.utils.log.AdminEmailHandler для предотвращения отправки сообщений об ошибках в режиме разработки:

'filters': {
     'require_debug_false': {
         '()': 'django.utils.log.RequireDebugFalse'
     }
 },
 'handlers': {
     'mail_admins': {
         'level': 'ERROR',
         'filters': ['require_debug_false'],
         'class': 'django.utils.log.AdminEmailHandler'
     }
 },

Если вы адаптируете уже существующий проект, то в настройке LOGGING этого фильтра нет. Для обратной совместимости Django определит, что у вашего обработчика 'mail_admins' нет раздела 'filters' и автоматически добавит его. В Django 1.5 мы будем выводить предупреждение, а в версии 1.6 эта совместимость будет удалена.

Добавление ключа 'filters' в обработчик 'mail_admins' рушит обратную совместимость.

django.conf.urls.defaults

Вплоть до Django 1.3 функции include(), patterns() и url(), а также handler404, handler500 располагались в модуле django.conf.urls.defaults.

В Django 1.4 они перемещены в модуль django.conf.urls.

django.contrib.databrowse

Просмотрщик данных долгое время не развивался, и по сей день не было новых коммитов. Было предложено GSOC project интегрировать в панель администратора, но никакого прогресса не видно. В то время как Databrowse стал устаревшим, некоторая его функциональность переместилась в django.contrib.admin.

Лицензия на Databrowse совпадает с лицензией Django, так что любой желающий может доработать его для себя.

django.core.management.setup_environ

Эта функция временно модифицирует sys.path, делая возможным импорт каталога проекта для старой структуры проекта, создаваемой startproject. Эта функция более не нужна с новым manage.py и структурой проекта.

Эта функция никогда не документировалась в API, но рекомендовалась для настройки окружения Django для пользовательских скриптов. Вместо неё следует использовать функцию django.conf.settings.configure() или переменную окружения DJANGO_SETTINGS_MODULE.

django.core.management.execute_manager

Эта функция ранее использовалась manage.py для выполнения команд приложения.Она идентична django.core.management.execute_from_command_line за исключением первого вызова setup_environ. Так что теперь объявлена устаревшей, вместо неё следует использовать execute_from_command_line. Ни одна из этих функций не документирована в рамках API, но объявить устаревшей django.core.management.execute_manager всё-таки нужно для дальнейшего использования manage.py.

Атрибуты фильтров в шаблонах needs_autoescape и is_safe

Два флага (is_safe и needs_autoescape) определяют как каждый фильтр шаблона взаимодействует с автоэкранированием Django. Раньше они были атрибутами функции:

@register.filter
def noop(value):
    return value
noop.is_safe = True

Однако, это вызывало проблемы при комбинировании декораторов, особенно @stringfilter. Теперь же флаги являются аргументами @register.filter:

@register.filter(is_safe=True)
def noop(value):
    return value

Подробнее в документации filters and auto-escaping.

Раскрытие шаблонов имен приложений в INSTALLED_APPS

До Django 1.3 INSTALLED_APPS позволяло использовать маску в именах приложения, например, django.contrib.*. Расшифровка была возможна за счёт реализации from <package> import *, основанной на структуре файлов. К сожалению, this can’t be done reliably.

This behavior was never documented. Since it is unpythonic and not obviously useful, it was removed in Django 1.4. If you relied on it, you must edit your settings file to list all your applications explicitly.

HttpRequest.raw_post_data переименован в HttpRequest.body

Этот атрибут назывался HttpRequest.raw_post_data, но на самом деле представлял собой тело HTTP запроса. Теперь он объявлен устаревшим, а вместо него следует использовать HttpRequest.body.

Исправлена потенциальная ошибка производительности в django.contrib.sitemaps

В предыдущих версиях объекты Paginator кэшировали карту сайта, что могло сказаться на актуальности. Мы избавились от этого, так что при каждом запросе к sitemap создаётся новый объект Paginator и вызывается метод items() класса Sitemap. В зависимости от того, что ваш метод items() делает, это может сказаться на производительности. Для смягчения последствий рассмотрите возможность использования caching framework в ваших подклассах Sitemap.

Версии Python-Markdown меньшие 2.1

Версии Python-Markdown меньшие, чем 2,1 не поддерживают возможность отключения атрибутов. В целях безопасности старые версии этой библиотеки не будут поддерживаться для разметки в 1.5 и подлежат скорейшему отключению.