Перенос ваших приложений с Django 0.96 на 1.0

Django 1.0 в некоторых областях нарушает совместимость с 0.96.

Это руководство поможет вам перенести проекты и приложения 0.96 на 1.0. Первая часть этого документа включает общие изменения, необходимые для работы с 1.0. Если после прохождения первой части ваш код по-прежнему ломается, проверьте раздел « Менее распространенные изменения», чтобы просмотреть список менее распространенных проблем совместимости.

Смотрите также

В версии 1.0 замечания . В этом документе более подробно объясняются новые возможности версии 1.0; руководство по портированию больше заботится о том, чтобы помочь вам быстро обновить код.

Общие изменения

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

Используйте Unicode

Измените строковые литералы ( '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аргумент из полей вашей модели. В этом больше нет необходимости, поскольку эквивалентная функциональность (часть встроенного редактирования ) теперь по-другому обрабатывается интерфейсом администратора. Вам не нужно беспокоиться о встроенном редактировании, пока вы не попадете в раздел администратора , расположенный ниже. А пока удалите все ссылки на core.

Заменить на class Admin:admin.py

Удалите все ваши внутренние объявления из ваших моделей. Они ничего не сломают, если вы их оставите, но и ничего не сделают. Чтобы зарегистрировать приложения у администратора, вы переместите эти объявления в файл; см. подробности у администратора ниже.class Adminadmin.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 u'%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 Adminclass Adminadmin.site.register()admin.pyAdmin

Используйте новый встроенный синтаксис

Все новые 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 .

Упростите fieldsили используйте fieldsets

Старый fieldsсинтаксис был довольно запутанным и был упрощен. Старый синтаксис по-прежнему работает, но вам нужно будет его использовать fieldsets.

Старая версия (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'}),
    )

Смотрите также

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библиотеку и использовали рекомендованный нами importсинтаксис операторов, все, что вам нужно сделать, это изменить операторы импорта.

Старый:

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)
f['content'] f.read()
f['filename'] f.name
f['content-type'] f.content_type

Работа с полями файлов с помощью нового API

Изменилась внутренняя реализация django.db.models.FileField. Видимым результатом этого является то, что способ доступа к специальным атрибутам (URL, имя файла, размер изображения и т. Д.) Этих полей модели изменился. Вам нужно будет внести следующие изменения, если ваша модель FileFieldвызывается myfile:

Старый (0.96) Новое (1.0)
myfile.get_content_filename() myfile.content.path
myfile.get_content_url() myfile.content.url
myfile.get_content_size() myfile.content.size
myfile.save_content_file() myfile.content.save()
myfile.get_content_width() myfile.content.width
myfile.get_content_height() myfile.content.height

Обратите внимание, что атрибуты widthи heightимеют смысл только для ImageFieldполей. Более подробную информацию можно найти в документации 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.
  • Удалите любое использование опций Anonymousи Anyотправителя; их больше нет. Вы по-прежнему можете получать сигналы, отправленные любым отправителем, используя sender=None
  • Превратите любые объявленные вами пользовательские сигналы в экземпляры, django.dispatch.Signalа не в анонимные объекты.

Вот краткое описание изменений кода, которые вам необходимо внести:

Старый (0.96) Новое (1.0)
def callback(sender) def callback(sender, **kwargs)
sig = object() sig = django.dispatch.Signal()
dispatcher.connect(callback, sig) sig.connect(callback)
dispatcher.send(sig, sender) sig.send(sender)
dispatcher.connect(callback, sig, sender=Any) sig.connect(callback, sender=None)

Комментарии

Если вы использовали django.contrib.commentsприложение Django 0.96 , вам необходимо перейти на новое приложение для комментариев, представленное в версии 1.0. Подробности см. В руководстве по обновлению.

Теги шаблонов

spacelessтег

spacelessШаблон Теперь тег удаляет все пробелы между тегами HTML, а не сохранение единого пространства.

Местные ароматы

Местный колорит США

django.contrib.localflavor.usaбыл переименован в django.contrib.localflavor.us. Это изменение было внесено, чтобы соответствовать схеме именования других местных вкусов. Чтобы перенести код, все, что вам нужно сделать, это изменить импорт.

Сессии

Получение нового сеансового ключа

SessionBase.get_new_session_key()был переименован в _get_new_session_key(). get_new_session_object()более не существует.

Светильники

Загрузка строки больше не вызывает save()

Раньше при загрузке строки автоматически запускался метод модели save(). Это уже не так, поэтому любые поля (например, временные метки), которые были автоматически заполнены a, save()теперь нуждаются в явных значениях в любом приспособлении.

Настройки

Лучшие исключения

Старый EnvironmentErrorразделился на тот, ImportErrorкогда Django не может найти модуль настроек, и RuntimeErrorкогда вы пытаетесь изменить настройки после того, как их уже использовали.

LOGIN_URLпереехал

LOGIN_URLКонстанта перемещается из django.contrib.authв settingsмодуль. Вместо использования ссылки .from django.contrib.auth import LOGIN_URLsettings.LOGIN_URL

APPEND_SLASHповедение было обновлено

В версии 0.96, если URL-адрес не заканчивался косой чертой или не имел точки в последнем компоненте его пути и APPEND_SLASHбыл истинным, 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

Заметки:

  1. Важно не забыть использовать формат XML на первом этапе этого процесса. Мы используем функцию дампов XML-данных, которая позволяет переносить числа с плавающей запятой в десятичные с помощью SQLite.
  2. На втором этапе вам будет предложено подтвердить, что вы готовы потерять данные для рассматриваемых приложений. Скажи да; мы восстановим эти данные на третьем шаге.
  3. 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' in requestrequest['some_form_key']GETPOSTrequest.REQUEST

Однако настоятельно рекомендуется всегда явно искать в соответствующем словаре тип запроса, который вы ожидаете получить ( request.GETили request.POST); использование комбинированного request.REQUESTсловаря может маскировать происхождение входящих данных.

Доступ к HTTPResponseзаголовкам

django.http.HttpResponse.headersбыл переименован в _headersи HttpResponseтеперь поддерживает проверку содержания напрямую. Так что используйте вместо .if header in response:if header in response.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. Например, если у вас есть тестовый код, который вызывает flush и 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

Распространение

Feed.__init__изменилось

__init__()Метод фреймворка объединения в синдикаты в Feedклассе в настоящее время принимает HttpRequestобъект в качестве второго параметра, вместо URL фида. Это позволяет фреймворку синдикации работать без фреймворка сайтов. Это влияет только на код, который создает подклассы Feedи переопределяет __init__()метод, и код, который вызывает Feed.__init__()напрямую.

Структуры данных

SortedDictFromListушел

django.newforms.forms.SortedDictFromListбыл удален. django.utils.datastructures.SortedDictтеперь можно создать экземпляр с последовательностью кортежей.

Чтобы обновить свой код:

  1. Используйте django.utils.datastructures.SortedDictвезде, где вы использовали django.newforms.forms.SortedDictFromList.
  2. Поскольку django.utils.datastructures.SortedDict.copyне возвращает глубокую копию, как SortedDictFromList.copy()это было, вам нужно будет обновить свой код, если вы полагались на глубокую копию. Сделайте это, используя copy.deepcopyнапрямую.

Бэкэнд-функции базы данных

Бэкэнд-функции базы данных были переименованы

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

Старый (0.96) Новое (1.0)
backend.get_autoinc_sql connection.ops.autoinc_sql
backend.get_date_extract_sql connection.ops.date_extract_sql
backend.get_date_trunc_sql connection.ops.date_trunc_sql
backend.get_datetime_cast_sql connection.ops.datetime_cast_sql
backend.get_deferrable_sql connection.ops.deferrable_sql
backend.get_drop_foreignkey_sql connection.ops.drop_foreignkey_sql
backend.get_fulltext_search_sql connection.ops.fulltext_search_sql
backend.get_last_insert_id connection.ops.last_insert_id
backend.get_limit_offset_sql connection.ops.limit_offset_sql
backend.get_max_name_length connection.ops.max_name_length
backend.get_pk_default_value connection.ops.pk_default_value
backend.get_random_function_sql connection.ops.random_function_sql
backend.get_sql_flush connection.ops.sql_flush
backend.get_sql_sequence_reset connection.ops.sequence_reset_sql
backend.get_start_transaction_sql connection.ops.start_transaction_sql
backend.get_tablespace_sql connection.ops.tablespace_sql
backend.quote_name connection.ops.quote_name
backend.get_query_set_class connection.ops.query_set_class
backend.get_field_cast_sql connection.ops.field_cast_sql
backend.get_drop_sequence connection.ops.drop_sequence_sql
backend.OPERATOR_MAPPING connection.operators
backend.allows_group_by_ordinal connection.features.allows_group_by_ordinal
backend.allows_unique_and_pk connection.features.allows_unique_and_pk
backend.autoindexes_primary_keys connection.features.autoindexes_primary_keys
backend.needs_datetime_string_cast connection.features.needs_datetime_string_cast
backend.needs_upper_for_iops connection.features.needs_upper_for_iops
backend.supports_constraints connection.features.supports_constraints
backend.supports_tablespaces connection.features.supports_tablespaces
backend.uses_case_insensitive_names connection.features.uses_case_insensitive_names
backend.uses_custom_queryset connection.features.uses_custom_queryset

Copyright ©2021 All rights reserved