Django documentation

当前文档仅适用于 Django SVN 版本,与上个版本有显著不同。上个版本文档请查阅: Django 1.0

Model 实例参考(Model instance reference)

该文档详细介绍 Model 的 API。它的知识点建立在 模型(model)数据库查询(database query) 两篇文章的基础之上,所以建议您读该文档之前先阅读和理解上面两篇文章。

整篇文档都将以 database query guide 中列出的 example weblog models 为例。

创建对象(Creating objects)

创建 model 的新实例和实例化其他的 Python 类一样:

class Model(**kwargs)

其中的关键字参数就是你在你的 model 中定义的字段的名称。要注意实例化一个 model 并不会操作数据库,要保存到数据库的话,你需要使用 save() 方法。

保存对象(Saving objects)

要将对象保存至数据库,就调用 save()

Model.save([force_insert=False, force_update=False])

这个方法颇有些微妙之处,请查看下面几节。

这部分是在 Django 1.0 中新增的: 请查看版本文档

save() 方法的形式与之前的版本已经有所不同(加入了 force_insertforce_update 参数)。如果你要重写该方法,就要留意这两个参数。

自增主键(Auto-incrementing primary keys)

如果你的 model 有一个 AutoField 字段,它是一个自增主键,那么在你第一次调用 save() 方法时,就会计算得出这个自增主键的值,然后做为对象的一个属性保存起来:

>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id     # Returns None, because b doesn't have an ID yet.
>>> b2.save()
>>> b2.id     # Returns the ID of your new object.

在调用 save() 之前是拿不到 ID 值的,因为这个值是要靠数据库来计算得出的,而非 Django。

(为使用方便,每个 model 默认都有一个 AutoField 自增字段,它的名称是 id。不过你可以在某个字段上指定 primary_key=True,从而将这个字段变成主键字段。详情请查看 AutoField

pk 属性 (The pk property)

这部分是在 Django 1.0 中新增的: 请查看版本文档
Model.pk

无论是你自己定义了主键,还是使用 Django 默认提供的主键,每个 model 都有一个指向主键的属性,叫做 pk。它看上去只是是一个属性,其实它是主键字段的一个别名。你可以象使用其他属性一样,获取或是设置它的值,它会自动对主键字段的值进行更改。

显式指定自增主键的值(Explicitly specifying auto-primary-key values)

如果一个 model 中含有一个 AutoField 自增字段,但是你在保存对象,并不想使用自动分配的 ID 值,而想显示地定义新对象的 ID 值,那么只要在保存之时显式的定义即可:

>>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b3.id     # Returns 3.
>>> b3.save()
>>> b3.id     # Returns 3.

如果你手动指定了自增主键的值,请事先确认主键的值并未在数据库中出现过;否则,如果你创建新对象时,显式指定的自增主键的值,却已存在于数据库中,那么 Django 就不会认为你是想创建对象,而是认为你想更改某个已存在的记录。

以上面所给的 'Cheddar Talk' 博客为例,下面的代码将覆盖数据库中原来的记录:

b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save()  # Overrides the previous blog with ID=3!

要了解为什么会覆盖掉记录,请查看下面的 Django 如何判断是更新还是创建(How Django knows to UPDATE vs. INSERT) 一节。

如果你能确实主键值不发生冲突,那么对于大量保存对象而言,指定自增主键的值是非常有用的。

在保存对象时都发生了什么(What happens when you save?)

在你保存对象时,Django 会执行下面的步骤:

  1. 发出预保存信号(Emit a pre-save signal)。 发出 django.db.models.signals.pre_save 信号(signal),然后监听该信号的函式就会执行某些定制操作。

  2. 预处理数据(Pre-process the data)。 对角中的每个字段都根据字段所需的数据格式,对数据自动进行调整。

    大多数字段是不需要预处理数据的,它们保持不变,只有那些有特殊行为的字段才需要预处理数据。例如,如果你的 model 中含有一个 DateField 字段,并且它指定了 auto_now=True,在预处理数据这个阶段,就会修改该字段的数据,使其包含当前时间戳(我们的文档还没有将这些有“特殊行为”的字段完整地列出来)。

  3. 根据数据库进行数据转换(Prepare the data for the database)。 每个字段都要根据当前数据库所要求的数据格式对当前值进行转换。

    大多数字段无须转换,它们多是简单的数据类型,比如整数,字符串,都是随时可写的 Python 对象。但是,有更多的复杂数据类型需要对数据进行转换和调整。

    例如,DateFields 字段使用的是一个 datetime 对象,这是一个 Python 类的实例,因为数据库并不直接保存 datetime 对象,所以字段值必须被转换成符合 ISO 标准的(ISO-compliant)的日期字符串,这样数据库才能识别。

  4. 将数据添加到数据库中(Insert the data into the database)。 经过预处理和转换的数据被组合成一条用以插入数据的 SQL 语句,从而完成对数据的添加。

  5. 发出已保存信号(Emit a post-save signal)。 发出 django.db.models.signals.post_save 信号,监听该信号的函式们会执行某些既定的操作。

(Django 是如何判别更新还是创建的How Django knows to UPDATE vs. INSERT)

你可能已注意到,Django 的数据对象无论是创建对象还是保存修改过的对象,都是使用同样的 save() 方法,因为 Django 已经对使用 INSERTUPDATE SQL 语句的需求进行了抽象。因此,在你调用 save() 方法时,Django 会按照下列算法进行处理:

  • 如果对象的主键属性是被赋与一个真值(True)时,(例如,即不是 None,也不是空字符串),Django 会执行一个 SELECT 查询以判定与主键相绑定的记录是否存在。
  • 如果该记录存在,Django 就会执行另一个 UPDATE 查询query。
  • 如果未设置对象的主键属性,或者如果虽然设置了主键,但是与其绑定的记录却不存在,那么 Django 不会执行一个 INSERT 操作。

有一点要注意的是:如果你不能保证主键值并被用过,那么在保存新对象时,要注意不要显式指定主键的值。想在这个细节上有更多了解,请查看上面的 显示指定自增变量的值(Explicitly specifying auto-primary-key values) 和下面的 强制添加或更新(Forcing an INSERT or UPDATE)

强制新增或更新(Forcing an INSERT or UPDATE)

这部分是在 Django 1.0 中新增的: Please, see the release notes

在一些少见的场合中,运行 save() 方法时要求强制运行一条 SQL INSERT 语句,而非 UPDATE 语句。同理在某些情况下又强迫 UPDATE 而非 INSERT。在这种情况下,你可以通过设置 force_insert=Trueforce_update=True 参数的方式运行 save() 方法。同时提供两个参数会抛开错误,因为 Django 不知道该 INSERT 还是 UPDATE

需要使用这两个参数的用例是很少见的。一般来说,Django 的默认操作大多是正确的,如果使用了这两个参数,如果出现错误,会使得调试跟踪变得困难,所以这个特性仅适用于高级应用。

根据已存在的字段更新属性(Updating attributes based on existing fields)

有些时候,你需要对某个字段做简单的运算,比如对当前值递增或递减,可以用下面的方法达到这个目的:

>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold += 1
>>> product.save()

从数据库中得到旧的 number_sold 值是 10,然后再将 11 写回到数据库中。

根据某个字段进行赋值,要好于直接地显式赋值。Django 提供了 F()表达式(F() expressions) 来解决根据字段赋值的问题。使用 F() 可以将上面的例子改写为:

>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()

这种方式并不是一开始就从数据库中取出原始值,而是在执行 <>save()<> 操作的时候才根据取值字段从数据库中取出原始值。

一旦对象被保存,你必须马上重新得到对象,这样才能得到你刚才得赋的字段值:

>>> product = Products.objects.get(pk=product.pk)
>>> print product.number_sold
42

详情请查看 use in update queries 文档中 F() expressions这一节

对象删除(Deleting objects)

Model.delete()

对当前对象执行一条 DELETE SQL 语句。删除操作仅仅作用于数据库,Python 的实例对象依然存在,它所包含的字段同样也存在。.

要了解更多细节,比如如何一次性删除多个对象,请查看 对象删除(Deleting objects).

其他的 model 实例方法(Other model instance methods)

有一部分方法有另外的特殊作用。

__str__

Model.__str__()

__str__() 是一个 Python 式的 "魔术方法" ,它定义了在你调用了对象的 str() 方法时,返回值的内容。Django 在很多场合使用 str(obj) (或是相关的其他的函式,比如下面提到的 unicode(obj) ),最常见的就是在 Django 管理后台中做为对象的显示值;或是用来在模板中显示对象。因此,你应该总是为 __str__ 返回一个友好且易读的字符串。这样做虽然不是必须的,不过我们仍建议您这样做。不过在您到处狂写 __str__ 之前,请继续阅读下面所讲的 __unicode__ 方法。

例如:

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        # Note use of django.utils.encoding.smart_str() here because
        # first_name and last_name will be unicode strings.
        return smart_str('%s %s' % (self.first_name, self.last_name))

__unicode__

Model.__unicode__()

在你使用对象的 unicode() 方法时,就会调用 __unicode__() 。因为你的 model 中的字段从数据库中得到的是 Unicode 字符串,所以一般情况下你要为你的 model 写一个 __unicode__() 方法。上面的例子可以简单地改写为:

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

如果你在 model 上只定义了 __unicode__() 方法却并没有定义 __str__() 方法,Django 将自动提供一个会在内部调用 __unicode__()__str__() 方法,并且将返回值自动转换成 UTF-8 字符串。对此,在开发时有如下建议:只定义 __unicode__() 方法,让 Django 在必要时自动做字符串转换。

get_absolute_url

Model.get_absolute_url()

定义 get_absolute_url() 方法会让 Django 知道如何计算得到当前对象对应的网址 URL,例如:

def get_absolute_url(self):
    return "/people/%i/" % self.id

Django 在管理后台使用该方法。如果某个对象定义了 get_absolute_url() 方法,在它的对象修改页就会出现一个 "View on site" 链接,它会弹出一个与当前对象相关的网页,网站就是 get_absolute_url() 返回的 URL

此外,Django 有些其他部分,也用到了 get_absolute_url() ,比如 RSS种子(syndication feed framework)get_absolute_url() 是一个对实际应用中很有用的快捷方法。

在模板中使用 get_absolute_url() 比直接在拼合网址要更好。例如,这种模板代码就不是很好:

<a href="/people/{{ object.id }}/">{{ object.name }}</a>

但这种写法就很好:

<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>

注意

get_absolute_url() 返回的 URL 只能包含 ASCII 字符串 (这是 URI 的规则所要求的,详见 RFC 2396) ,所以在必要的时候,会进行重编码 URL-encoded,而在代码和模板中 get_absolute_url() 时,会直接输出结果而不会进行网址重编码。如果你有大量的 Unicode 网址要进行重编码,可以使用 django.utils.encoding.iri_to_uri() 函式来处理。

其他的实例方法(Extra instance methods)

除了 save(), delete() 之外,一个 model 对象可能还有下列方法:

Model.get_FOO_display()

如果 model 有字段设置了 choices ,对象就会提供 get_FOO_display() 方法,这里的 FOO 就是字段的名称。这个方法返回给用户看的那个可读性好的值,例如:

GENDER_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female'),
)
class Person(models.Model):
    name = models.CharField(max_length=20)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

...每个 Person 实例都有一个 get_gender_display() 方法。例如:

>>> p = Person(name='John', gender='M')
>>> p.save()
>>> p.gender
'M'
>>> p.get_gender_display()
'Male'
Model.get_next_by_FOO(**kwargs)
Model.get_previous_by_FOO(**kwargs)

如果 model 中的 DateField 字段和 DateTimeField 字段没有设置 null=True,那么对象就会提供 get_next_by_FOO() 方法和 get_previous_by_FOO() 方法。这里的 FOO 就是时间字段的名称。它根据当时时间字段的值返回下一个或是前一个对象。如果没有找到就会抛开 DoesNotExist 异常。

这两个方法的参数都是可选的,这些参数在 字段筛选条件(Field lookups) 中有详细介绍。

要注意:如果在使用这两个方法时遇到了相同的时间,那么它们就会将 ID 值做为第二条件,这样才能保证记录没有重复或遗漏。

Questions/Feedback

Having trouble? We'd like to help!