Ross Wan's World!

Python, Ajax, PHP and Linux.

Posts Tagged ‘porting’

Django: 将基于0.96的 Apps 迁移到 1.0

Posted by Ross Wan 于 2008/11/04

Django 1.0 发布后,其 API 基本上已经稳定下来,但它对以往的 0.9x 版本有不少的不兼容地方。这个教程就是帮助大家将基于 Django 0.96的项目或者 Apps(应用)迁移到 1.0。而且,网上大多数教程都是基于0.96的,了解0.96与1.0的兼容问题,有助于大家更好学习和利用以往的教程。

常见的变迁

这是用户从 Django 0.96迁移到1.0时最常遇到的需要作出的的变迁。

Unicode

Django 1.0已经完全使用 Unicode 字符串(如 u’foo’)。虽然在大多数情况下,使用普通的字符串(raw string)也不会出问题,但更新至 Unicode 字符串可以避免一些莫名其妙的问题。

详情参阅: Unicode data in Django

Models

maxlength 重命名为 max_length

这是为了统一字段格式。

__unicode__ 取代 __str__

将 model 里面的 __str__ 方法替换为 __unicode__ 方法,并且确保在 __unicode__ 方法内使用的字符串全部是 Unicode 字符串(如 u’foo’)。

移除 prepopulate_from 参数

移除 model 字段内的 prepopulate_from 参数,将它移到 admin.py 里的 ModelAdmin 类里面。

移除 core 参数

移除 model 字段内的 core 参数,因为 admin 接口现在已经提供相同的功能。你不必担心到影响 inline editing,可以放心的删除所有对 core 的引用。

admin.py 模块取代 Admin 类

移除所有 models 内的 Admin 内部类,因为它不起任何作用了。现在使用 admin.py 文件来注册 Apps 到 admin。当然,留着它不理也常会影响到应用的正常运行。

示例

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)

Admin

一个全新、完全重构过的 Admin 后台管理接口,这是 Django 1.0最大的变化之一。Admin 现在并不需要在 modle 里面作定义。Admin 的框架使用 Django 新的 form-handing 库重写过,变得更为具扩展性。

这意味着你必须重写 Admin 类的定义。正如上面的示例,以前 models 内的 Admin 类的定义被 admin.py 文件内的 admin.site.register() 方法替代了。下面将详细讲解如何重写一个 Admin 的定义。

另见: djangosnippets 上的一个贡献者写了一个脚本,可以自动扫描 models.py 并生成相应的 admin.py 文件。

新的 inline 语法

新的 edit_inline 参数选项移至 admin.py。示例:

旧的0.96的 model.py:

class Parent(models.Model):
...

class Child(models.Model):
    parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)

对应新的1.0的 admin.py:

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

旧的语法同样可以照常使用,使需要用 fieldsets 代替 fields。

旧的0.96的 model.py:

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的 admin.py:

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

如果需要使用 admin 来进行后台管理,你必须更新 root 下的 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

django.forms 替代 newforms

newforms 将被重命名为 forms,而 oldforms 将会被移除。如果你在应用中使用了 newforms,建议修改 import 语句:

旧的:

from django import newforms as forms

新的:

from django import forms

详情见 forms documentation

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

旧的 API 将不再有效。示例:

像这样的上传的文件:

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

你必须作如下的变迁:

Old (0.96) New (1.0)
f[‘content’] f.read()
f[‘filename’] f.name
f[‘content-type’] f.content_type

FileField

django.db.models.FileField 的内部现实已经改变了。假设一个 model 的 FileField 叫做 myfile,你必须作出如下的变迁:

Old (0.96) New (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

Templates

Autoescapeing(自动转义)

现在,模板系统将对输出变量中的 HTML 标签自动进行转义操作。说情参看 Automatic HTML escaping

如果要禁用个别变量进行自动转义(auto-escaping),可以使用 safe 过滤器(filter):

默认会进行自动转义: {{ data }}
加上 safe 过滤器后会禁止进行转义: {{ data|safe }}

如果要对模板内的一部分输出内容禁止进行转义,可以使用 autoescape 标签(tag):

{% autoescape off %}
... 这部分内容将不会进行自动转义 ...
{% endautoescape %}

不常见的变迁

如果经过上面的处理,代码依然无法正常运行。请查阅:

Advertisements

Posted in Uncategorized | Tagged: , , , , , | Leave a Comment »