将你的应用从 Django 0.96 移植到 1.0 — Django 文档
将您的应用程序从 Django 0.96 移植到 1.0
Django 1.0 在某些方面打破了与 0.96 的兼容性。
本指南将帮助您将 0.96 项目和应用程序移植到 1.0。 本文档的第一部分包括运行 1.0 所需的常见更改。 如果在完成第一部分后您的代码仍然中断,请查看 不太常见的更改 部分以获取一系列不太常见的兼容性问题的列表。
常见变化
本节介绍大多数用户需要在 0.96 和 1.0 之间进行的更改。
使用 Unicode
将字符串文字 ('foo'
) 更改为 Unicode 文字 (u'foo'
)。 Django 现在自始至终都使用 Unicode 字符串。 在大多数地方,原始字符串将继续工作,但更新为使用 Unicode 文字将防止一些晦涩的问题。
有关完整详细信息,请参阅 Unicode 数据 。
型号
对模型文件的常见更改:
将 maxlength 重命名为 max_length
将 maxlength
参数重命名为 max_length
(已更改为与表单字段一致):
移除 prepopulated_from
删除模型字段上的 prepopulated_from
参数。 它不再有效并已移至 admin.py
中的 ModelAdmin
类。 有关管理员更改的更多详细信息,请参阅下面的 管理员 。
移除 core
从模型字段中删除 core
参数。 不再需要它,因为等效功能( 内联编辑 的一部分)现在由管理界面以不同方式处理。 在进入下面的 管理 部分之前,您不必担心内联编辑。 现在,删除对 core
的所有引用。
将 class Admin: 替换为 admin.py
从模型中删除所有内部 class Admin
声明。 如果你离开他们,他们不会破坏任何东西,但他们也不会做任何事情。 要向管理员注册应用程序,您需要将这些声明移动到 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
声明。 您已经在上面的 models 中看到了如何将 class Admin
替换为 admin.py
文件中的 admin.site.register()
调用。 下面是有关如何将 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'}),
)
网址
更新您的根 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 处理上传的文件
使用新的 UploadedFile 替换上传文件的使用 - 即 request.FILES
中的条目 - 作为简单字典。 旧的字典语法不再有效。
因此,在如下视图中:
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
0.96 中的 ObjectPaginator
已被移除并替换为改进版本 django.core.paginator.Paginator。
模板
学会喜欢自动转义
默认情况下,模板系统现在自动对每个变量的输出进行 HTML 转义。 要了解更多信息,请参阅 自动 HTML 转义 。
要禁用单个变量的自动转义,请使用 :tfilter:`safe` 过滤器:
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
要禁用整个模板的自动转义,请将模板(或仅模板的特定部分)包装在 :ttag:`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.localflavor.usa
已重命名为 django.contrib.localflavor.us
。 进行此更改是为了匹配其他本地风味的命名方案。 要迁移您的代码,您需要做的就是更改导入。
会话
获取新的会话密钥
SessionBase.get_new_session_key()
已重命名为 _get_new_session_key()
。 get_new_session_object()
不再存在。
灯具
加载一行不再调用 save()
以前,加载一行会自动运行模型的 save()
方法。 现在不再是这种情况,因此任何由 save()
自动填充的字段(例如:时间戳)现在都需要在任何装置中显式值。
设置
更好的例外
当 Django 无法找到设置模块时,旧的 EnvironmentError
已拆分为 ImportError
,当您尝试重新配置已使用设置后的设置时,已拆分为 RuntimeError
。
:setting:`LOGIN_URL` 已移动
:setting:`LOGIN_URL` 常量从 django.contrib.auth
移动到 settings
模块。 而不是使用from django.contrib.auth import LOGIN_URL
参考 :setting:`settings.LOGIN_URL ` .
:setting:`APPEND_SLASH` 行为已更新
在 0.96 中,如果 URL 不以斜杠结尾或在其路径的最后一部分中没有句点,并且 :setting:`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
未在 __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
注意事项:
- 请务必记住在此过程的第一步中使用 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' 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:
。
通用关系
测试
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
数据结构
SortedDictFromList不见了
django.newforms.forms.SortedDictFromList
被移除。 django.utils.datastructures.SortedDict
现在可以用元组序列实例化。
要更新您的代码:
- 在您使用
django.newforms.forms.SortedDictFromList
的任何地方使用django.utils.datastructures.SortedDict
。 - 因为
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
|
评论
如果您使用的是 Django 0.96 的
django.contrib.comments
应用程序,则需要升级到 1.0 中引入的新评论应用程序。 有关详细信息,请参阅升级指南。