将应用程序从Django 0.96移植到1.0

Django 1.0在某些区域中断了与0.96的兼容性。

本指南将帮助您将0.96项目和应用程序移植到1.0。本文档的第一部分包括运行1.0所需的常见更改。如果在完成第一部分后,代码仍然中断,请检查该部分 Less-common Changes 一系列不太常见的兼容性问题。

参见

这个 1.0 release notes . 该文档更深入地解释了1.0中的新特性;移植指南更关注于帮助您快速更新代码。

共同变化

本节介绍大多数用户需要在0.96和1.0之间进行的更改。

使用Unicode

更改字符串文本 ('foo' )到Unicode文本 (u'foo' )Django现在全部使用Unicode字符串。在大多数地方,原始字符串将继续工作,但更新为使用Unicode文本将避免一些模糊的问题。

Unicode数据 详细信息。

模型

对模型文件的常见更改:

重命名 maxlengthmax_length

重命名你的名字 maxlength 参数 max_length (已更改为与表单字段一致):

替换 __str__ 具有 __unicode__

替换您的模型 __str__ 函数与A __unicode__ 方法,并确保 use Unicode (u'foo' )用那种方法。

去除 prepopulated_from

移除 prepopulated_from 模型字段上的参数。它不再有效,已移动到 ModelAdmin 班在 admin.py . 见 the admin 有关对管理员所做更改的详细信息,请参阅下面的。

去除 core

移除 core 来自模型字段的参数。它不再是必需的,因为等效功能( inline editing )现在由管理界面以不同的方式处理。你不必担心在线编辑,直到你 the admin 下面的部分。现在,删除对 core .

替换 class Admin: 具有 admin.py

把你所有的内心 class Admin 来自模型的声明。如果你离开他们,他们不会破坏任何东西,但他们也不会做任何事。要向管理员注册应用程序,您将把这些声明移动到 admin.py 文件;参见 the admin 详情请参见下文。

例子

下面是一个例子 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) 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) 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):

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):

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"}),
    )

参见

URLs

更新你的根目录 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) 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.formsdjango.oldforms )你必须重写你的表格。一个好的起点是 forms documentation

使用新的API处理上载的文件

替换上载文件的使用--即 request.FILES --作为简单的字典 UploadedFile . 旧词典的语法不再有效。

因此,在这样的观点中:

def my_view(request):
    f = request.FILES["file_field_name"]
    ...

…您需要进行以下更改:

旧(0.96)

新(1)

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)

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

请注意 widthheight 属性只对 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 .

  • 移除任何使用 AnonymousAny 发件人选项;它们不再存在。您仍然可以使用 sender=None

  • 生成您已声明为的任何自定义信号 django.dispatch.Signal 而不是匿名对象。

下面是您需要进行的代码更改的快速摘要:

旧(0.96)

新(1)

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 0.96 django.contrib.comments 应用程序,您需要升级到1.0中引入的新评论应用程序。有关详细信息,请参阅升级指南。

模板标签

spaceless 标签

这个 spaceless 模板标记现在删除 all HTML标记之间的空格,而不是保留单个空格。

地方风味

美国本土风味

django.contrib.localflavor.usa 已重命名为 django.contrib.localflavor.us . 此更改是为了与其他本地口味的命名方案相匹配。要迁移代码,只需更改导入。

会议

获取新会话密钥

SessionBase.get_new_session_key() 已重命名为 _get_new_session_key() . get_new_session_object() 不再存在。

夹具

加载不再调用的行 save()

以前,加载行会自动运行模型的 save() 方法。这种情况已经不复存在,因此任何由自动填充的字段(例如:时间戳) save() 现在需要在任何fixture中使用显式值。

设置

更好的例外

老年人 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):

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):

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):

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() 现在需要发布请求

以前,使用了GET请求。旧的行为意味着状态(用于显示站点的区域设置)可以通过GET请求进行更改,这与HTTP规范的建议相反。调用此视图的代码必须确保现在发出了POST请求,而不是GET。这意味着您不能再使用链接访问视图,但必须使用某种形式的表单提交(例如按钮)。

_() 不再内置

_() (名为单个下划线的可调用对象)不再是MonkeyPatched内置的——也就是说,它不再能在每个模块中神奇地使用。

如果你以前依靠 _() 始终存在,现在应该显式导入 ugettextugettext_lazy ,并将其命名为 _ 你自己:

from django.utils.translation import ugettext as _

HTTP请求/响应对象

字典访问 HttpRequest

HttpRequest 对象不再直接支持字典样式的访问;以前,两者都支持 GETPOST 数据直接在 HttpRequest 对象(例如,可以使用 if 'some_form_key' in request 或通过阅读 request['some_form_key'] . 这不再受支持;如果需要访问 GETPOST 数据,使用 request.REQUEST 相反。

但是,强烈建议您始终在适当的字典中明确查找要接收的请求类型。 (request.GETrequest.POST );依靠联合体 request.REQUEST 字典可以屏蔽传入数据的来源。

访问 HTTPResponse 报头

django.http.HttpResponse.headers 已重命名为 _headersHttpResponse 现在直接支持安全壳检查。所以用 if header in response: 而不是 if header in response.headers: .

一般关系

一般关系已被移出核心

一般关系类-- GenericForeignKeyGenericRelation --已经搬进了 django.contrib.contenttypes 模块。

测试

django.test.Client.login() 已经改变

旧(0.96):

from django.test import Client

c = Client()
c.login("/path/to/login", "myuser", "mypassword")

新(1):

# ... same as above, but then:
c.login(username="myuser", password="mypassword")

管理命令

从代码中运行管理命令

django.core.management 已经被大大改造了。

调用代码中的管理服务现在需要使用 call_command . 例如,如果您有一些调用flush和load_数据的测试代码:

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.pymanage.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 直接。

数据库后端功能

数据库后端功能已重命名

几乎 all 已重命名和/或重新定位了个数据库后端级别的函数。这些都没有被记录下来,但是如果您使用这些函数中的任何一个,所有这些函数都在 django.db

旧(0.96)

新(1)

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