Porting your apps from Django 0.96 to 1.0

Django 1.0在某些方面打破了与0.96的兼容性。

本指南将帮助您将0.96项目和应用程序移植到1.0。本文档的第一部分包括使用1.0运行所需的常见更改。如果在查看第一部分之后,您的代码仍然中断,请查看低通用更改部分,以获取一堆不太常见的兼容性问题的列表。

也可以看看

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

Common changes

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

Use Unicode

将字符串字面值('foo')更改为Unicode文字(u'foo')。Django现在使用Unicode字符串。在大多数地方,原始字符串将继续工作,但更新以使用Unicode字面值将防止一些模糊的问题。

有关详细信息,请参见Unicode data

Models

模型文件的常见更改:

Rename maxlength to max_length

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

Replace __str__ with __unicode__

使用__unicode__方法替换模型的__str__函数,并确保使用Unicodeu'foo')在该方法中。

Remove prepopulated_from

从模型字段中删除prepopulated_from参数。它不再有效,已移至admin.py中的ModelAdmin类。有关管理员更改的详细信息,请参阅下面的管理员

Remove core

从模型字段中删除core参数。由于等效功能(inline editing)现在由管理界面以不同方式处理,因此不再需要。您不必担心在线编辑,直到您访问管理部分,如下。现在,请删除对core的所有引用。

Replace class Admin: with admin.py

从您的模型中删除您所有的内部 管理声明。如果你离开他们,他们不会打破任何东西,但他们也不会做任何事情。要向管理员注册应用,您需要将这些声明移动到admin.py文件;有关详细信息,请参阅下面的管理

也可以看看

djangosnippets的贡献者撰写了一个脚本,该脚本将扫描您的models.py并生成相应的admin.py

Example

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

The Admin

1.0中最大的变化之一是新的管理员。Django管理界面(django.contrib.admin)已完全重构;管理定义现在完全脱离了模型定义,框架已被重写为使用Django的新的形式处理库,并重新设计了可扩展性和定制。

实际上,这意味着您需要重写所有的 管理声明。You’ve already seen in models above how to replace your class Admin with a admin.site.register() call in an admin.py file. 以下是有关如何将Admin声明重写为新语法的一些详细信息。

Use new inline syntax

新的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 objects

Simplify fields, or use 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'}),
    )

也可以看看

URLs

Update your root 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 ...
)

Views

Use django.forms instead of newforms

django.newforms替换为django.forms - Django 1.0将newforms模块(在0.96中引入)重命名为旧的formsoldforms模块也被删除。

如果您已经在使用newforms库,并且使用我们建议的import语句语法,您只需更改import语句。

旧:

from django import newforms as forms

新:

from django import forms

如果您使用的是旧表单系统(以前称为django.formsdjango.oldforms),则必须重写表单。开始的好地方是forms documentation

Handle uploaded files using the new 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

Work with file fields using the new 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

请注意,widthheight属性仅适用于ImageField字段。有关详细信息,请参阅model API文档。

Use Paginator instead of ObjectPaginator

在0.96中的ObjectPaginator已被删除,并替换为改进的版本django.core.paginator.Paginator

Templates

Learn to love autoescaping

默认情况下,模板系统现在自动HTML转义每个变量的输出。要了解详情,请参阅Automatic HTML escaping

要禁用单个变量的自动转义,请使用safe过滤器:

This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}

要为整个模板停用自动转义,请在autoescape标记中包含模板(或只是模板的特定部分):

{% autoescape off %}
   ... unescaped template content here ...
{% endautoescape %}

Less-common changes

以下更改是更小,更局部的更改。它们应该只影响更高级的用户,但是它可能值得阅读列表,并检查你的代码这些事情。

Signals

  • **kwargs添加到任何注册的信号处理程序。
  • 通过Signal对象上的方法,而不是通过django.dispatch.dispatcher中的模块方法,通过方法连接,断开和发送信号。
  • 删除AnonymousAny发件人选项的任何使用;他们不再存在。您仍然可以使用sender=None接收任何发件人发送的信号
  • 将您宣布为django.dispatch.Signal的自定义信号替换为匿名对象。

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

旧(0.96)新(1.0)
def 回呼(发件人)def 回拨(寄件者, ** kwargs)
sig = 对象()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)

Comments

如果您使用的是Django 0.96的django.contrib.comments应用程式,您必须升级至1.0中新推出的评论应用程式。有关详细信息,请参阅升级指南。

Template tags

spaceless tag

无空间模板标签现在除去HTML标记之间的所有 T0>空格,而不是保留单个空格。

Local flavors

U.S. local flavor

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

Sessions

Getting a new session key

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

Fixtures

Loading a row no longer calls save()

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

Settings

Better exceptions

当Django无法找到设置模块时,旧的EnvironmentError已分裂为ImportError,而在尝试使用后重新配置设置时,RuntimeError他们。

LOGIN_URL has moved

LOGIN_URL常数从django.contrib.auth移到settings模块中。Instead of using from django.contrib.auth import LOGIN_URL refer to settings.LOGIN_URL.

APPEND_SLASH behavior has been updated

在0.96中,如果网址没有以斜杠结尾或在路径的最后一个组件中有句点,且APPEND_SLASH为True,Django会重定向到相同的网址,但附加斜杠到最后。现在,Django会检查没有尾部斜线的模式是否会被网址格式中的某些内容匹配。如果是这样,不会发生重定向,因为假设您故意想要捕获该模式。

对于大多数人,这不需要任何更改。但有些人的网址格式看起来像这样:

r'/some_prefix/(.*)$'

以前,这些模式将被重定向为具有尾部斜杠。如果您在此类网址上始终需要斜杠,请将模式重写为:

r'/some_prefix/(.*/)$'

Smaller model changes

Different exception from 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 has been fired

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 is new, and FloatField is now a proper 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__init__中未采用max_digits属性的错误,因为新的FloatField不接收与精度相关的参数。

如果您使用MySQL或PostgreSQL,则不需要进一步更改。DecimalField的数据库列类型与旧的FloatField相同。

如果您使用SQLite,您需要强制数据库将适当的列作为十进制类型而不是浮点数来查看。为此,您需要重新加载数据。在您更改代码中使用DecimalField并更新Django代码后,请执行此操作。

警告

先备份您的数据库!

对于SQLite,这意味着创建存储数据库的单个文件的副本(该文件的名称是您的settings.py文件中的DATABASE_NAME)。

要升级每个应用程序以使用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模型执行此过程。

如果在上述过程中出现问题,只需将备份的数据库文件复制到原始文件上,然后重新启动即可。

Internationalization

django.views.i18n.set_language() now requires a POST request

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

_() is no longer in builtins

_()(名称为单个下划线的可调对象)不再被内嵌到内部 - 也就是说,它在每个模块中不再可用。

如果您以前依赖于_()始终存在,则应立即显式导入ugettextugettext_lazy(如果适用),并将其别名_您自己:

from django.utils.translation import ugettext as _

HTTP request/response objects

Dictionary access to HttpRequest

HttpRequest objects no longer directly support dictionary-style access; previously, both GET and POST data were directly available on the HttpRequest object (e.g., you could check for a piece of form data by using if 'some_form_key' in request or by reading request['some_form_key']. 这不再支持;如果您需要访问组合的GETPOST数据,请改用request.REQUEST

然而,强烈建议您始终明确地查找您期望接收的请求类型(request.GETrequest.POST)的相应字典;依赖于组合的request.REQUEST字典可以屏蔽传入数据的来源。

Accessing HTTPResponse headers

django.http.HttpResponse.headers已重命名为_headersHttpResponse现在直接支持包含检查。So use if header in response: instead of if header in response.headers:.

Generic relations

Generic relations have been moved out of core

通用关系类 - GenericForeignKeyGenericRelation已移动到django.contrib.contenttypes模块中。

Testing

django.test.Client.login() has changed

旧(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')

Management commands

Running management commands from your code

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)

Subcommands must now precede options

django-admin.pymanage.py现在需要子命令位于选项之前。所以:

$ django-admin.py --settings=foo.bar runserver

...不再工作,应更改为:

$ django-admin.py runserver --settings=foo.bar

Syndication

Feed.__init__ has changed

联合框架的Feed类的__init__()方法现在将HttpRequest对象作为其第二个参数,而不是Feed的网址。这允许联合框架工作,而不需要sites框架。这只影响子类Feed的代码,并覆盖__init__()方法以及直接调用Feed.__init__()的代码。

Data structures

SortedDictFromList is gone

django.newforms.forms.SortedDictFromList已删除。django.utils.datastructures.SortedDict现在可以使用元组序列实例化。

要更新您的代码:

  1. 无论您使用django.newforms.forms.SortedDictFromList,请使用django.utils.datastructures.SortedDict
  2. 因为django.utils.datastructures.SortedDict.copy不会返回deepcopy,因为SortedDictFromList.copy()没有,您需要更新您的代码,如果你依赖深层复制。请直接使用copy.deepcopy执行此操作。

Database backend functions

Database backend functions have been renamed

几乎所有的数据库后端级函数已重命名和/或重定位。这些都没有记录,但如果您使用以下任何函数,则需要更改代码:django.db

旧(0.96)新(1.0)
backend.get_autoinc_sqlconnection.ops.autoinc_sql
backend.get_date_extract_sqlconnection.ops.date_extract_sql
backend.get_date_trunc_sqlconnection.ops.date_trunc_sql
backend.get_datetime_cast_sqlconnection.ops.datetime_cast_sql
backend.get_deferrable_sqlconnection.ops.deferrable_sql
backend.get_drop_foreignkey_sqlconnection.ops.drop_foreignkey_sql
backend.get_fulltext_search_sqlconnection.ops.fulltext_search_sql
backend.get_last_insert_idconnection.ops.last_insert_id
backend.get_limit_offset_sqlconnection.ops.limit_offset_sql
backend.get_max_name_lengthconnection.ops.max_name_length
backend.get_pk_default_valueconnection.ops.pk_default_value
backend.get_random_function_sqlconnection.ops.random_function_sql
backend.get_sql_flushconnection.ops.sql_flush
backend.get_sql_sequence_resetconnection.ops.sequence_reset_sql
backend.get_start_transaction_sqlconnection.ops.start_transaction_sql
backend.get_tablespace_sqlconnection.ops.tablespace_sql
backend.quote_nameconnection.ops.quote_name
backend.get_query_set_classconnection.ops.query_set_class
backend.get_field_cast_sqlconnection.ops.field_cast_sql
backend.get_drop_sequenceconnection.ops.drop_sequence_sql
backend.OPERATOR_MAPPINGconnection.operators
backend.allows_group_by_ordinalconnection.features.allows_group_by_ordinal
backend.allows_unique_and_pkconnection.features.allows_unique_and_pk
backend.autoindexes_primary_keysconnection.features.autoindexes_primary_keys
backend.needs_datetime_string_castconnection.features.needs_datetime_string_cast
backend.needs_upper_for_iopsconnection.features.needs_upper_for_iops
backend.supports_constraintsconnection.features.supports_constraints
backend.supports_tablespacesconnection.features.supports_tablespaces
backend.uses_case_insensitive_namesconnection.features.uses_case_insensitive_names
backend.uses_custom_querysetconnection.features.uses_custom_queryset