Портирование ваших приложений с Django 0.96 на 1.0.¶
Django 1.0 в некоторых областях нарушает совместимость с версией 0.96.
Это руководство поможет вам перенести проекты и приложения версии 0.96 на версию 1.0. Первая часть этого документа включает общие изменения, необходимые для работы с версией 1.0. Если после прохождения первой части ваш код по-прежнему не работает, проверьте раздел «Менее распространенные изменения», чтобы найти список менее распространенных проблем совместимости.
См.также
Примечания к выпуску 1.0. В этом документе более подробно объясняются новые функции версии 1.0; руководство по портированию больше направлено на то, чтобы помочь вам быстро обновить код.
Общие изменения¶
В этом разделе описаны изменения между версиями 0,96 и 1,0, которые необходимо будет внести большинству пользователей.
Используйте Юникод¶
Замените строковые литералы ('foo') на литералы Юникода (u'foo'). Django теперь повсюду использует строки Unicode. В большинстве случаев необработанные строки будут продолжать работать, но обновление для использования литералов Unicode предотвратит некоторые неясные проблемы.
Подробную информацию см. в Данные Unicode.
Модели¶
Общие изменения в файле вашей модели:
Переименуйте maxlength в max_length¶
Переименуйте аргумент maxlength в max_length (это было изменено, чтобы соответствовать полям формы):
Замените __str__ на __unicode__¶
Замените функцию __str__ вашей модели на метод __unicode__ и убедитесь, что вы используете Unicode`_ (``u'foo') в этом методе.
Удалить prepopulated_from¶
Удалите аргумент prepopulated_from в полях модели. Он больше не действителен и перемещен в класс ModelAdmin в admin.py. См. раздел «Администратор» ниже для получения более подробной информации об изменениях в администраторе.
Удалить ядро¶
Удалите аргумент core из полей вашей модели. В этом больше нет необходимости, поскольку эквивалентная функциональность (часть встроенного редактирования) теперь по-другому обрабатывается интерфейсом администратора. Вам не придется беспокоиться о встроенном редактировании, пока вы не перейдете в раздел «Администратор» ниже. А пока удалите все ссылки на core.
Замените class Admin: на admin.py.¶
Удалите все ваши внутренние объявления класса Admin из ваших моделей. Они ничего не сломают, если вы их оставите, но и ничего не сделают. Чтобы зарегистрировать приложения у администратора, вы переместите эти объявления в файл admin.py; дополнительную информацию см. в разделе «Администратор» ниже.
См.также
Участник djangosnippets написал скрипт, который сканирует ваш файл models.py и генерирует соответствующий admin.py.
Пример¶
Ниже приведен пример файла models.py со всеми изменениями, которые вам необходимо внести:
Старый (0.96) models.py:
class Author(models.Model):
first_name = models.CharField(maxlength=30)
last_name = models.CharField(maxlength=30)
slug = models.CharField(maxlength=60, prepopulate_from=("first_name", "last_name"))
class Admin:
list_display = ["first_name", "last_name"]
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
Новый (1.0) models.py:
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
slug = models.CharField(max_length=60)
def __unicode__(self):
return "%s %s" % (self.first_name, self.last_name)
Новый (1.0) admin.py:
from django.contrib import admin
from models import Author
class AuthorAdmin(admin.ModelAdmin):
list_display = ["first_name", "last_name"]
prepopulated_fields = {"slug": ("first_name", "last_name")}
admin.site.register(Author, AuthorAdmin)
Администратор¶
Одно из самых больших изменений в версии 1.0 — новый администратор. Административный интерфейс Django (django.contrib.admin) был полностью переработан; определения администратора теперь полностью отделены от определений модели, инфраструктура была переписана для использования новой библиотеки обработки форм Django и переработана с учетом расширяемости и настройки.
На практике это означает, что вам придется переписать все объявления class Admin. Вы уже видели в models`_ выше, как заменить ваш ``class Admin на вызов admin.site.register() в файле admin.py. Ниже приведены некоторые дополнительные сведения о том, как переписать это объявление Admin в новый синтаксис.
Используйте новый встроенный синтаксис¶
Все новые параметры edit_inline были перенесены в admin.py. Вот пример:
Старый (0,96):
class Parent(models.Model): ...
class Child(models.Model):
parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)
Новое (1.0):
class ChildInline(admin.StackedInline):
model = Child
extra = 3
class ParentAdmin(admin.ModelAdmin):
model = Parent
inlines = [ChildInline]
admin.site.register(Parent, ParentAdmin)
Дополнительную информацию см. в Объект InlineModelAdmin.
Упростите поля или используйте наборы полей.¶
Старый синтаксис полей был довольно запутанным и был упрощен. Старый синтаксис по-прежнему работает, но вместо него вам придется использовать наборы полей.
Старый (0,96):
class ModelOne(models.Model):
...
class Admin:
fields = ((None, {"fields": ("foo", "bar")}),)
class ModelTwo(models.Model):
...
class Admin:
fields = (
("group1", {"fields": ("foo", "bar"), "classes": "collapse"}),
("group2", {"fields": ("spam", "eggs"), "classes": "collapse wide"}),
)
Новое (1.0):
class ModelOneAdmin(admin.ModelAdmin):
fields = ("foo", "bar")
class ModelTwoAdmin(admin.ModelAdmin):
fieldsets = (
("group1", {"fields": ("foo", "bar"), "classes": "collapse"}),
("group2", {"fields": ("spam", "eggs"), "classes": "collapse wide"}),
)
См.также
Более подробную информацию об изменениях и причинах их можно найти на вики-странице NewformsAdminBranch.
Новый администратор предлагает массу новых функций; вы можете прочитать о них в административной документации.
URL-адреса¶
Обновите корневой файл urls.py.¶
Если вы используете сайт администратора, вам необходимо обновить корневой файл urls.py.
Старый (0.96) urls.py:
from django.conf.urls.defaults import *
urlpatterns = patterns(
"",
(r"^admin/", include("django.contrib.admin.urls")),
# ... the rest of your URLs here ...
)
Новый (1.0) urls.py:
from django.conf.urls.defaults import *
# The next two lines enable the admin and load each admin.py file:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(
"",
(r"^admin/(.*)", admin.site.root),
# ... the rest of your URLs here ...
)
Просмотры¶
Используйте django.forms вместо newforms.¶
Замените django.newforms на django.forms - Django 1.0 переименовал модуль newforms (представленный в версии 0.96) в старые добрые forms. Модуль oldforms также был удален.
Если вы уже используете библиотеку newforms и использовали рекомендуемый нами синтаксис операторов импорта, все, что вам нужно сделать, это изменить операторы импорта.
Старый:
from django import newforms as forms
Новый:
from django import forms
Если вы используете старую систему форм (ранее известную как django.forms и django.oldforms), вам придется переписать свои формы. Хорошим местом для начала является документация по формам
Обрабатывайте загруженные файлы с помощью нового API¶
Замените использование загруженных файлов, то есть записей в request.FILES, как простых словарей, на новый UploadedFile. Старый синтаксис словаря больше не работает.
Таким образом, в представлении типа:
def my_view(request):
f = request.FILES["file_field_name"]
...
…вам необходимо внести следующие изменения:
Старый (0,96) |
Новый (1.0) |
|---|---|
|
|
|
|
|
|
Работайте с полями файлов с помощью нового API¶
Внутренняя реализация django.db.models.FileField изменилась. Видимым результатом этого является то, что изменился способ доступа к специальным атрибутам (URL, имя файла, размер изображения и т. д.) этих полей модели. Вам нужно будет внести следующие изменения, предполагая, что FileField вашей модели называется myfile:
Старый (0,96) |
Новый (1.0) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Обратите внимание, что атрибуты width и height имеют смысл только для полей ImageField. Более подробную информацию можно найти в документации model API.
Используйте Paginator вместо ObjectPaginator.¶
ObjectPaginator в версии 0.96 был удален и заменен улучшенной версией: django.core.paginator.Paginator.
Шаблоны¶
Научитесь любить автопобег¶
По умолчанию система шаблонов теперь автоматически экранирует вывод каждой переменной в формате HTML. Чтобы узнать больше, см. Автоматическое экранирование HTML.
Чтобы отключить автоматическое экранирование для отдельной переменной, используйте фильтр safe:
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
Чтобы отключить автоматическое экранирование для всего шаблона, оберните шаблон (или только определенный раздел шаблона) тегом autoescape:
{% autoescape off %}
... unescaped template content here ...
{% endautoescape %}
Менее распространенные изменения¶
Следующие изменения представляют собой более мелкие и более локализованные изменения. Они должны затронуть только более продвинутых пользователей, но, вероятно, стоит прочитать список и проверить свой код на наличие этих вещей.
Сигналы¶
Добавьте
**kwargsко всем зарегистрированным обработчикам сигналов.Подключайте, отключайте и отправляйте сигналы с помощью методов объекта
Signalвместо методов модуля вdjango.dispatch.dispatcher.Удалите любое использование параметров отправителя «Анонимный» и «Любой»; их больше нет. Вы по-прежнему можете получать сигналы, отправленные любым отправителем, используя
sender=None.Превратите любые объявленные вами пользовательские сигналы в экземпляры
django.dispatch.Signalвместо анонимных объектов.
Вот краткое описание изменений кода, которые вам необходимо внести:
Старый (0,96) |
Новый (1.0) |
|---|---|
|
|
|
|
|
|
|
|
|
|
Комментарии¶
Если вы использовали приложение django.contrib.comments в Django 0.96, вам необходимо обновиться до нового приложения комментариев, представленного в версии 1.0. Подробности смотрите в руководстве по обновлению.
Местные вкусы¶
Местный вкус США¶
django.contrib.localflavor.usa был переименован в django.contrib.localflavor.us. Это изменение было внесено, чтобы соответствовать схеме наименования других местных вкусов. Чтобы перенести код, все, что вам нужно сделать, это изменить импорт.
Сессии¶
Получение нового сеансового ключа¶
SessionBase.get_new_session_key() был переименован в _get_new_session_key(). get_new_session_object() больше не существует.
Светильники¶
Загрузка строки больше не вызывает метод save().¶
Раньше при загрузке строки автоматически запускался метод модели save(). Это уже не так, поэтому любые поля (например, временные метки), которые были автоматически заполнены с помощью метода save(), теперь требуют явных значений в любом приборе.
Настройки¶
Лучшие исключения¶
Старый EnvironmentError разделился на ImportError, когда Django не может найти модуль настроек, и на RuntimeError, когда вы пытаетесь перенастроить настройки после того, как они уже использовались.
LOGIN_URL перемещен¶
Константа LOGIN_URL перемещена из django.contrib.auth в модуль settings. Вместо использования from django.contrib.auth import LOGIN_URL обратитесь к settings.LOGIN_URL.
APPEND_SLASH поведение было обновлено.¶
В версии 0.96, если URL-адрес не заканчивался косой чертой или имел точку в последнем компоненте пути, а APPEND_SLASH имел значение True, Django перенаправлял на тот же URL-адрес, но с добавленной косой чертой в конце. Теперь Django проверяет, соответствует ли шаблон без косой черты чему-либо в ваших шаблонах URL. Если да, то перенаправления не происходит, поскольку предполагается, что вы намеренно хотели уловить этот шаблон.
Для большинства людей это не потребует каких-либо изменений. Однако у некоторых людей шаблоны URL-адресов выглядят следующим образом:
r"/some_prefix/(.*)$"
Раньше эти шаблоны перенаправлялись с косой чертой в конце. Если вам всегда нужна косая черта на таких URL-адресах, перепишите шаблон как:
r"/some_prefix/(.*/)$"
Небольшие изменения модели¶
Другое исключение из get()¶
Менеджеры теперь возвращают исключение MultipleObjectsReturned вместо AssertionError:
Старый (0,96):
try:
Model.objects.get(...)
except AssertionError:
handle_the_error()
Новое (1.0):
try:
Model.objects.get(...)
except Model.MultipleObjectsReturned:
handle_the_error()
LazyDate был уволен¶
Вспомогательный класс LazyDate больше не существует.
Значения полей по умолчанию и аргументы запроса могут быть вызываемыми объектами, поэтому экземпляры LazyDate можно заменить ссылкой на datetime.datetime.now:
Старый (0,96):
class Article(models.Model):
title = models.CharField(maxlength=100)
published = models.DateField(default=LazyDate())
Новое (1.0):
import datetime
class Article(models.Model):
title = models.CharField(max_length=100)
published = models.DateField(default=datetime.datetime.now)
DecimalField является новым, а FloatField теперь является правильным числом с плавающей запятой.¶
Старый (0,96):
class MyModel(models.Model):
field_name = models.FloatField(max_digits=10, decimal_places=3)
...
Новое (1.0):
class MyModel(models.Model):
field_name = models.DecimalField(max_digits=10, decimal_places=3)
...
Если вы забудете внести это изменение, вы увидите ошибки о том, что FloatField не принимает атрибут max_digits в __init__, поскольку новый FloatField не принимает аргументов, связанных с точностью.
Если вы используете MySQL или PostgreSQL, никаких дополнительных изменений не требуется. Типы столбцов базы данных для DecimalField такие же, как и для старого FloatField.
Если вы используете SQLite, вам необходимо заставить базу данных просматривать соответствующие столбцы как десятичные типы, а не как числа с плавающей запятой. Для этого вам необходимо перезагрузить данные. Сделайте это после того, как вы внесли изменения в использование DecimalField в своем коде и обновили код Django.
Предупреждение
Сначала создайте резервную копию базы данных!
Для SQLite это означает создание копии единственного файла, в котором хранится база данных (имя этого файла — «DATABASE_NAME» в вашем файле «settings.py»).
Чтобы обновить каждое приложение для использования DecimalField, вы можете сделать следующее, заменив в приведенном ниже коде <app> именем каждого приложения:
$ ./manage.py dumpdata --format=xml <app> > data-dump.xml
$ ./manage.py reset <app>
$ ./manage.py loaddata data-dump.xml
Примечания:
Важно не забыть использовать формат XML на первом этапе этого процесса. Мы используем особенность дампов данных XML, которая делает возможным перенос чисел с плавающей запятой в десятичные числа с помощью SQLite.
На втором этапе вам будет предложено подтвердить, что вы готовы потерять данные для рассматриваемых приложений. Скажи да; мы восстановим эти данные на третьем этапе.
DecimalFieldне использовался ни в одном из приложений, поставляемых с Django до внесения этого изменения, поэтому вам не нужно беспокоиться о выполнении этой процедуры для любой из стандартных моделей Django.
Если в описанном выше процессе что-то пойдет не так, просто скопируйте резервную копию файла базы данных поверх исходного файла и начните заново.
Интернационализация¶
django.views.i18n.set_language() теперь требует POST-запроса¶
Ранее использовался запрос GET. Старое поведение означало, что состояние (язык, используемый для отображения сайта) можно было изменить с помощью запроса GET, что противоречит рекомендациям спецификации HTTP. Код, вызывающий это представление, должен гарантировать, что теперь выполняется запрос POST, а не GET. Это означает, что вы больше не можете использовать ссылку для доступа к представлению, а должны использовать какую-либо отправку формы (например, кнопку).
_() больше нет во встроенных функциях¶
_() (вызываемый объект, имя которого представляет собой одинарное подчеркивание) больше не добавляется во встроенные функции, то есть он больше не доступен волшебным образом в каждом модуле.
Если раньше вы полагались на постоянное присутствие _(), теперь вам следует явно импортировать ugettext или ugettext_lazy, если это необходимо, и присвоить ему псевдоним _ самостоятельно:
from django.utils.translation import ugettext as _
Объекты HTTP-запроса/ответа¶
Доступ по словарю к HttpRequest¶
Объекты HttpRequest больше не поддерживают напрямую доступ в стиле словаря; ранее данные GET и POST были напрямую доступны в объекте HttpRequest (например, вы могли проверить фрагмент данных формы, используя if „some_form_key“ в запросе или прочитав request['some_form_key']. Это больше не поддерживается; если вам нужен доступ к комбинированным данным GET и POST, используйте Вместо этого request.REQUEST.
Однако настоятельно рекомендуется всегда явно искать в соответствующем словаре тип запроса, который вы ожидаете получить («request.GET» или «request.POST»); полагаясь на объединенный словарь request.REQUEST, можно замаскировать происхождение входящих данных.
Доступ к заголовкам HTTPResponse¶
django.http.HttpResponse.headers был переименован в _headers, и HttpResponse теперь поддерживает прямую проверку содержания. Поэтому используйте if заголовок в ответе: вместо если заголовок в ответе.headers:.
Родовые отношения¶
Общие отношения были удалены из ядра.¶
Общие классы отношений — GenericForeignKey и GenericRelation — перемещены в модуль django.contrib.contenttypes.
Тестирование¶
django.test.Client.login() изменился¶
Старый (0,96):
from django.test import Client
c = Client()
c.login("/path/to/login", "myuser", "mypassword")
Новое (1.0):
# ... same as above, but then:
c.login(username="myuser", password="mypassword")
Команды управления¶
Запуск команд управления из вашего кода¶
django.core.management был значительно переработан.
Для вызовов служб управления в вашем коде теперь необходимо использовать call_command. Например, если у вас есть тестовый код, который вызывает флеш и load_data:
from django.core import management
management.flush(verbosity=0, interactive=False)
management.load_data(["test_data"], verbosity=0)
… вам нужно изменить этот код на следующий:
from django.core import management
management.call_command("flush", verbosity=0, interactive=False)
management.call_command("loaddata", "test_data", verbosity=0)
Подкоманды теперь должны предшествовать опциям¶
django-admin.py и manage.py теперь требуют, чтобы подкоманды предшествовали опциям. Так:
$ django-admin.py --settings=foo.bar runserver
… больше не работает и его следует изменить на:
$ django-admin.py runserver --settings=foo.bar
Структуры данных¶
SortedDictFromList исчез.¶
django.newforms.forms.SortedDictFromList был удален. django.utils.datastructures.SortedDict теперь можно создать с помощью последовательности кортежей.
Чтобы обновить код:
Используйте django.utils.datastructures.SortedDict везде, где вы использовали django.newforms.forms.SortedDictFromList.
Поскольку django.utils.datastructures.SortedDict.copy не возвращает глубокую копию, как это сделал SortedDictFromList.copy(), вам придется обновить свой код, если вы полагались на глубокую копию. Сделайте это, используя напрямую
copy.deepcopy.
Бэкэнд-функции базы данных¶
Внутренние функции базы данных были переименованы.¶
Почти все функции внутреннего уровня базы данных были переименованы и/или перемещены. Ни одна из них не была задокументирована, но вам придется изменить свой код, если вы используете любую из этих функций, все они находятся в django.db:
Старый (0,96) |
Новый (1.0) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|