Перенос ваших приложений с 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 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 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 Admin 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 .

Упростите 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_URL settings.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 теперь это правильный float

Старая версия (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 request request['some_form_key'] GET POST request.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 не возвращает deepcopy, как SortedDictFromList.copy() это было, вам нужно будет обновить свой код, если вы полагались на deepcopy. Сделайте это, используя 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 ©2020 All rights reserved