Django 1.0在某些方面打破了与0.96的兼容性。
本指南将帮助您将0.96项目和应用程序移植到1.0。本文档的第一部分包括使用1.0运行所需的常见更改。如果在查看第一部分之后,您的代码仍然中断,请查看低通用更改部分,以获取一堆不太常见的兼容性问题的列表。
也可以看看
1.0 release notes。该文档更深入地解释了1.0的新特性;移植指南更关心帮助您快速更新代码。
本节介绍大多数用户需要进行的0.96和1.0之间的更改。
将字符串字面值('foo')更改为Unicode文字(u'foo')。Django现在使用Unicode字符串。在大多数地方,原始字符串将继续工作,但更新以使用Unicode字面值将防止一些模糊的问题。
有关详细信息,请参见Unicode data。
模型文件的常见更改:
将maxlength参数重命名为max_length(这已更改为与表单字段一致):
从模型字段中删除prepopulated_from参数。它不再有效,已移至admin.py中的ModelAdmin类。有关管理员更改的详细信息,请参阅下面的管理员。
从模型字段中删除core参数。由于等效功能(inline editing)现在由管理界面以不同方式处理,因此不再需要。您不必担心在线编辑,直到您访问管理部分,如下。现在,请删除对core的所有引用。
从您的模型中删除您所有的内部类 管理声明。如果你离开他们,他们不会打破任何东西,但他们也不会做任何事情。要向管理员注册应用,您需要将这些声明移动到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的新的形式处理库,并重新设计了可扩展性和定制。
实际上,这意味着您需要重写所有的类 管理声明。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声明重写为新语法的一些详细信息。
新的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。
旧的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。
旧(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.newforms替换为django.forms - Django 1.0将newforms模块(在0.96中引入)重命名为旧的formsoldforms模块也被删除。
如果您已经在使用newforms库,并且使用我们建议的import语句语法,您只需更改import语句。
旧:
from django import newforms as forms
新:
from django import forms
如果您使用的是旧表单系统(以前称为django.forms和django.oldforms),则必须重写表单。开始的好地方是forms documentation
将上传文件(即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 |
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字段。有关详细信息,请参阅model API文档。
在0.96中的ObjectPaginator已被删除,并替换为改进的版本django.core.paginator.Paginator。
默认情况下,模板系统现在自动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 %}
以下更改是更小,更局部的更改。它们应该只影响更高级的用户,但是它可能值得阅读列表,并检查你的代码这些事情。
以下是您需要进行的代码更改的快速摘要:
旧(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) |
如果您使用的是Django 0.96的django.contrib.comments应用程式,您必须升级至1.0中新推出的评论应用程式。有关详细信息,请参阅升级指南。
django.contrib.localflavor.usa已重命名为django.contrib.localflavor.us。此更改是为了匹配其他本地风味的命名方案。要迁移代码,您只需要更改导入。
SessionBase.get_new_session_key()已重命名为_get_new_session_key()。get_new_session_object()不再存在。
以前,加载一行会自动运行模型的save()方法。这不再是这种情况,因此由save()自动填充的任何字段(例如:时间戳)现在需要任何fixture中的显式值。
当Django无法找到设置模块时,旧的EnvironmentError已分裂为ImportError,而在尝试使用后重新配置设置时,RuntimeError他们。
LOGIN_URL常数从django.contrib.auth移到settings模块中。Instead of using from django.contrib.auth import LOGIN_URL refer to settings.LOGIN_URL.
在0.96中,如果网址没有以斜杠结尾或在路径的最后一个组件中有句点,且APPEND_SLASH为True,Django会重定向到相同的网址,但附加斜杠到最后。现在,Django会检查没有尾部斜线的模式是否会被网址格式中的某些内容匹配。如果是这样,不会发生重定向,因为假设您故意想要捕获该模式。
对于大多数人,这不需要任何更改。但有些人的网址格式看起来像这样:
r'/some_prefix/(.*)$'
以前,这些模式将被重定向为具有尾部斜杠。如果您在此类网址上始终需要斜杠,请将模式重写为:
r'/some_prefix/(.*/)$'
管理员现在返回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的实例可以替换为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)
旧(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
笔记:
如果在上述过程中出现问题,只需将备份的数据库文件复制到原始文件上,然后重新启动即可。
以前,使用了GET请求。旧的行为意味着状态(用于显示站点的区域设置)可以通过GET请求更改,这违反了HTTP规范的建议。调用此视图的代码必须确保现在发出POST请求,而不是GET。这意味着您无法再使用链接访问视图,但必须使用某种形式的提交(例如,一个按钮)。
_()(名称为单个下划线的可调对象)不再被内嵌到内部 - 也就是说,它在每个模块中不再可用。
如果您以前依赖于_()始终存在,则应立即显式导入ugettext或ugettext_lazy(如果适用),并将其别名_您自己:
from django.utils.translation import ugettext as _
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']. 这不再支持;如果您需要访问组合的GET和POST数据,请改用request.REQUEST。
然而,强烈建议您始终明确地查找您期望接收的请求类型(request.GET或request.POST)的相应字典;依赖于组合的request.REQUEST字典可以屏蔽传入数据的来源。
django.http.HttpResponse.headers已重命名为_headers和HttpResponse现在直接支持包含检查。So use if header in response: instead of if header in response.headers:.
通用关系类 - GenericForeignKey和GenericRelation已移动到django.contrib.contenttypes模块中。
旧(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__()方法现在将HttpRequest对象作为其第二个参数,而不是Feed的网址。这允许联合框架工作,而不需要sites框架。这只影响子类Feed的代码,并覆盖__init__()方法以及直接调用Feed.__init__()的代码。
django.newforms.forms.SortedDictFromList已删除。django.utils.datastructures.SortedDict现在可以使用元组序列实例化。
要更新您的代码:
几乎所有的数据库后端级函数已重命名和/或重定位。这些都没有记录,但如果您使用以下任何函数,则需要更改代码: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 |
2015年5月13日