模型实例参考

本文档描述了Model API 的详细信息。它基于模型数据库查询指南中介绍的资料,因此您可能需要阅读并理解这些文档后再阅读本文档。

在本参考中,我们将使用示例博客模型(在数据库查询指南中介绍)。

创建对象

要创建模型的新实例,请像任何其他 Python 类一样实例化它

class Model(**kwargs)[source]

关键字参数是您在模型中定义的字段的名称。请注意,实例化模型不会以任何方式触及您的数据库;为此,您需要save()

注意

您可能会倾向于通过覆盖__init__方法来定制模型。但是,如果您这样做,请注意不要更改调用签名,因为任何更改都可能阻止保存模型实例。此外,在某些情况下,在__init__中引用模型字段可能会导致无限递归错误。与其覆盖__init__,不如尝试使用以下方法之一

  1. 在模型类上添加类方法

    from django.db import models
    
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
    
        @classmethod
        def create(cls, title):
            book = cls(title=title)
            # do something with the book
            return book
    
    
    book = Book.create("Pride and Prejudice")
    
  2. 在自定义管理器上添加方法(通常更推荐)

    class BookManager(models.Manager):
        def create_book(self, title):
            book = self.create(title=title)
            # do something with the book
            return book
    
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
    
        objects = BookManager()
    
    
    book = Book.objects.create_book("Pride and Prejudice")
    

自定义模型加载

classmethod Model.from_db(db, field_names, values)[source]

from_db()方法可用于在从数据库加载时自定义模型实例创建。

db参数包含模型从中加载的数据库的数据库别名,field_names包含所有已加载字段的名称,values包含field_names中每个字段的已加载值。field_names的顺序与values相同。如果所有模型字段都存在,则values保证按__init__()期望的顺序排列。也就是说,可以通过cls(*values)创建实例。如果任何字段被延迟,它们将不会出现在field_names中。在这种情况下,为每个缺失的字段分配django.db.models.DEFERRED的值。

除了创建新的模型外,from_db()方法还必须在新实例的_state属性中设置addingdb标志。

以下是一个示例,展示如何记录从数据库加载的字段的初始值

from django.db.models import DEFERRED


@classmethod
def from_db(cls, db, field_names, values):
    # Default implementation of from_db() (subject to change and could
    # be replaced with super()).
    if len(values) != len(cls._meta.concrete_fields):
        values = list(values)
        values.reverse()
        values = [
            values.pop() if f.attname in field_names else DEFERRED
            for f in cls._meta.concrete_fields
        ]
    instance = cls(*values)
    instance._state.adding = False
    instance._state.db = db
    # customization to store the original field values on the instance
    instance._loaded_values = dict(
        zip(field_names, (value for value in values if value is not DEFERRED))
    )
    return instance


def save(self, **kwargs):
    # Check how the current values differ from ._loaded_values. For example,
    # prevent changing the creator_id of the model. (This example doesn't
    # support cases where 'creator_id' is deferred).
    if not self._state.adding and (
        self.creator_id != self._loaded_values["creator_id"]
    ):
        raise ValueError("Updating the value of creator isn't allowed")
    super().save(**kwargs)

上面的示例显示了完整的from_db()实现,以阐明如何做到这一点。在这种情况下,可以在from_db()方法中使用super()调用。

从数据库刷新对象

如果从模型实例中删除字段,则再次访问它会从数据库重新加载值

>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field  # Loads the field from the database
Model.refresh_from_db(using=None, fields=None, from_queryset=None)[source]
Model.arefresh_from_db(using=None, fields=None, from_queryset=None)

异步版本arefresh_from_db()

如果需要从数据库重新加载模型的值,可以使用refresh_from_db()方法。当此方法在没有参数的情况下调用时,将执行以下操作:

  1. 所有模型的非延迟字段都将更新为数据库中当前存在的值。

  2. 任何缓存的关系都将从重新加载的实例中清除。

仅从数据库重新加载模型的字段。其他依赖于数据库的值(例如注释)不会重新加载。任何@cached_property属性也不会清除。

重新加载发生在实例加载的数据库中,或者如果实例不是从数据库加载的,则发生在默认数据库中。using参数可用于强制用于重新加载的数据库。

可以使用fields参数强制加载字段集。

例如,要测试update()调用是否导致了预期的更新,您可以编写类似于以下的测试

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F("val") + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

请注意,当访问延迟字段时,延迟字段值的加载将通过此方法进行。因此,可以自定义延迟加载的方式。以下示例显示了当重新加载延迟字段时,如何重新加载实例的所有字段

class ExampleModel(models.Model):
    def refresh_from_db(self, using=None, fields=None, **kwargs):
        # fields contains the name of the deferred field to be
        # loaded.
        if fields is not None:
            fields = set(fields)
            deferred_fields = self.get_deferred_fields()
            # If any deferred field is going to be loaded
            if fields.intersection(deferred_fields):
                # then load all of them
                fields = fields.union(deferred_fields)
        super().refresh_from_db(using, fields, **kwargs)

from_queryset参数允许使用与从_base_manager创建的queryset不同的queryset。它可以让您更好地控制模型的重新加载方式。例如,当您的模型使用软删除时,您可以使refresh_from_db()考虑到这一点

obj.refresh_from_db(from_queryset=MyModel.active_objects.all())

您可以缓存否则将从重新加载的实例中清除的相关对象

obj.refresh_from_db(from_queryset=MyModel.objects.select_related("related_field"))

您可以在重新加载模型的值之前,将行锁定到事务结束。

obj.refresh_from_db(from_queryset=MyModel.objects.select_for_update())
Django 5.1 中的更改

添加了from_queryset参数。

Model.get_deferred_fields()[source]

一个辅助方法,返回一个集合,该集合包含当前为此模型延迟的所有字段的属性名称。

验证对象

验证模型涉及四个步骤

  1. 验证模型字段 - Model.clean_fields()

  2. 整体验证模型 - Model.clean()

  3. 验证字段唯一性 - Model.validate_unique()

  4. 验证约束 - Model.validate_constraints()

当您调用模型的full_clean()方法时,将执行所有四个步骤。

当您使用ModelForm时,对is_valid()的调用将对表单中包含的所有字段执行这些验证步骤。有关更多信息,请参阅ModelForm 文档。只有在您计划自己处理验证错误,或者您已从ModelForm中排除了需要验证的字段时,才需要调用模型的full_clean()方法。

Model.full_clean(exclude=None, validate_unique=True, validate_constraints=True)[source]

此方法按顺序调用Model.clean_fields()Model.clean()Model.validate_unique()(如果validate_uniqueTrue)和Model.validate_constraints()(如果validate_constraintsTrue),并引发一个ValidationError,该错误具有message_dict属性,其中包含所有四个阶段的错误。

可选的exclude参数可用于提供一个set,其中包含可以从验证和清理中排除的字段名称。ModelForm使用此参数来排除表单中不存在的字段,因为任何引发的错误都无法由用户纠正。

请注意,当您调用模型的save()方法时,不会自动调用full_clean()。当您希望为自己的手动创建的模型运行一步模型验证时,需要手动调用它。例如

from django.core.exceptions import ValidationError

try:
    article.full_clean()
except ValidationError as e:
    # Do something based on the errors contained in e.message_dict.
    # Display them to a user, or handle them programmatically.
    pass

full_clean()执行的第一步是清理每个单独的字段。

Model.clean_fields(exclude=None)[source]

此方法将验证模型上的所有字段。可选的exclude参数允许您提供一个set,其中包含要从验证中排除的字段名称。如果任何字段验证失败,它将引发ValidationError

full_clean()执行的第二步是调用Model.clean()。此方法应被重写以对您的模型执行自定义验证。

Model.clean()[source]

此方法应用于提供自定义模型验证,并根据需要修改模型上的属性。例如,您可以使用它来自动为字段提供值,或执行需要访问多个字段的验证。

import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _


class Article(models.Model):
    ...

    def clean(self):
        # Don't allow draft entries to have a pub_date.
        if self.status == "draft" and self.pub_date is not None:
            raise ValidationError(_("Draft entries may not have a publication date."))
        # Set the pub_date for published items if it hasn't been set already.
        if self.status == "published" and self.pub_date is None:
            self.pub_date = datetime.date.today()

但是请注意,与Model.full_clean()一样,当您调用模型的save()方法时,不会调用模型的clean()方法。

在上面的示例中,ValidationError异常是用字符串实例化的,因此它将存储在一个特殊的错误字典键NON_FIELD_ERRORS中。此键用于与整个模型而不是特定字段相关的错误。

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError

try:
    article.full_clean()
except ValidationError as e:
    non_field_errors = e.message_dict[NON_FIELD_ERRORS]

要将异常分配给特定字段,请使用字典实例化ValidationError,其中键是字段名称。我们可以更新前面的示例,将错误分配给pub_date字段。

class Article(models.Model):
    ...

    def clean(self):
        # Don't allow draft entries to have a pub_date.
        if self.status == "draft" and self.pub_date is not None:
            raise ValidationError(
                {"pub_date": _("Draft entries may not have a publication date.")}
            )
        ...

如果在Model.clean()期间检测到多个字段中的错误,您还可以传递一个字典,该字典将字段名称映射到错误。

raise ValidationError(
    {
        "title": ValidationError(_("Missing title."), code="required"),
        "pub_date": ValidationError(_("Invalid date."), code="invalid"),
    }
)

然后,full_clean()将检查模型上的唯一性约束。

如果这些字段没有出现在ModelForm中,如何引发特定于字段的验证错误

您不能在Model.clean()中为模型表单中未出现的字段引发验证错误(表单可以使用Meta.fieldsMeta.exclude限制其字段)。这样做会引发ValueError,因为验证错误将无法与被排除的字段关联。

为了解决这个问题,请改写Model.clean_fields(),因为它接收从验证中排除的字段列表。例如

class Article(models.Model):
    ...

    def clean_fields(self, exclude=None):
        super().clean_fields(exclude=exclude)
        if self.status == "draft" and self.pub_date is not None:
            if exclude and "status" in exclude:
                raise ValidationError(
                    _("Draft entries may not have a publication date.")
                )
            else:
                raise ValidationError(
                    {
                        "status": _(
                            "Set status to draft if there is not a publication date."
                        ),
                    }
                )
Model.validate_unique(exclude=None)[source]

此方法类似于clean_fields(),但会验证通过Field.uniqueField.unique_for_dateField.unique_for_monthField.unique_for_yearMeta.unique_together在模型上定义的唯一性约束,而不是单个字段值。可选的exclude参数允许您提供一个set,其中包含要从验证中排除的字段名称。如果任何字段验证失败,它将引发ValidationError

UniqueConstraintMeta.constraints中定义,由Model.validate_constraints()验证。

请注意,如果您向validate_unique()提供exclude参数,则将不会检查涉及您提供的字段之一的任何unique_together约束。

最后,full_clean()将检查模型上的任何其他约束。

Model.validate_constraints(exclude=None)[source]

此方法验证在 Meta.constraints 中定义的所有约束。可选的 exclude 参数允许您提供一个 set,其中包含要从验证中排除的字段名称。如果任何约束验证失败,它将引发 ValidationError

保存对象

要将对象保存回数据库,请调用 save()

Model.save(*, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)[source]
Model.asave(*, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)

异步版本asave()

有关使用 force_insertforce_update 参数的详细信息,请参阅 强制执行 INSERT 或 UPDATE。有关 update_fields 参数的详细信息,请参阅 指定要保存的字段 部分。

如果您想要自定义保存行为,您可以覆盖此 save() 方法。有关更多详细信息,请参阅 覆盖预定义的模型方法

模型保存过程也有一些细微之处;请参阅下面的部分。

自版本 5.1 起已弃用: 对位置参数的支持已弃用。

自动递增主键

如果模型具有 AutoField(自动递增主键),则该自动递增值将在您第一次调用 save() 时计算并作为属性保存在您的对象上。

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

在调用 save() 之前,无法确定 ID 的值,因为该值是由您的数据库计算的,而不是由 Django 计算的。

为方便起见,除非您在模型中的字段上显式指定 primary_key=True,否则每个模型默认都具有名为 idAutoField。有关更多详细信息,请参阅 AutoField 的文档。

pk 属性

Model.pk

无论您自己定义主键字段,还是让 Django 为您提供一个主键字段,每个模型都将具有一个名为 pk 的属性。它的行为类似于模型上的普通属性,但实际上是模型主键字段的别名。您可以读取和设置此值,就像处理任何其他属性一样,它将更新模型中的正确字段。

显式指定自动主键值

如果模型具有 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 如何知道是 UPDATE 还是 INSERT,了解发生这种情况的原因。

显式指定自动主键值主要用于批量保存对象,当您确信不会发生主键冲突时。

如果您使用的是 PostgreSQL,则可能需要更新与主键关联的序列;请参阅 手动指定自动递增主键的值

保存时会发生什么?

保存对象时,Django 将执行以下步骤:

  1. 发出预保存信号。将发送 pre_save 信号,允许任何侦听该信号的函数执行某些操作。

  2. 预处理数据。将调用每个字段的 pre_save() 方法,以执行所需的任何自动数据修改。例如,日期/时间字段覆盖 pre_save() 以实现 auto_now_addauto_now

  3. 准备数据库数据。将要求每个字段的 get_db_prep_save() 方法以数据库可写入的数据类型提供其当前值。

    大多数字段不需要数据准备。简单的类型,例如整数和字符串,作为 Python 对象“准备好写入”。但是,更复杂的数据类型通常需要一些修改。

    例如,DateField 字段使用 Python datetime 对象来存储数据。数据库不存储 datetime 对象,因此必须将字段值转换为符合 ISO 标准的日期字符串,以便插入数据库。

  4. 将数据插入数据库。预处理的准备数据将构成 SQL 语句,以便插入数据库。

  5. 发出保存后信号。将发送 post_save 信号,允许任何侦听该信号的函数执行某些操作。

Django 如何知道是 UPDATE 还是 INSERT

您可能已经注意到,Django 数据库对象使用相同的 save() 方法来创建和更改对象。Django 避免了使用 INSERTUPDATE SQL 语句的需要。具体来说,当您调用 save() 并且对象的primaryKey属性**没有**定义 defaultdb_default 时,Django 将遵循以下算法:

  • 如果对象的primaryKey属性设置为计算结果为 True 的值(即,非 None 或空字符串的值),则 Django 将执行 UPDATE

  • 如果对象的主键属性设置,或者UPDATE没有更新任何内容(例如,如果主键设置为数据库中不存在的值),Django 将执行INSERT操作。

如果对象的主键属性定义了defaultdb_default,那么如果它是一个已存在的模型实例并且主键设置为数据库中存在的值,Django 将执行UPDATE操作。否则,Django 将执行INSERT操作。

这里需要注意的是,如果无法保证主键值未使用,则在保存新对象时不应显式指定主键值。有关此细微差别的更多信息,请参见上文的显式指定自动主键值和下文的强制执行 INSERT 或 UPDATE

在 Django 1.5 及更早版本中,当主键属性设置时,Django 会执行SELECT操作。如果SELECT找到一行,则 Django 执行UPDATE操作,否则执行INSERT操作。旧算法在UPDATE情况下会导致多一个查询。在某些罕见情况下,即使数据库包含对象主键值的记录,数据库也不会报告已更新记录。一个例子是 PostgreSQL 的ON UPDATE触发器,它返回NULL。在这种情况下,可以通过将select_on_save选项设置为True来恢复旧算法。

Django 5.0 中的更改

添加了Field.db_default参数。

强制执行 INSERT 或 UPDATE

在某些罕见情况下,需要强制save()方法执行 SQL INSERT操作,而不是回退到执行UPDATE操作。反之亦然:如果可能,则更新,但不插入新行。在这些情况下,可以将force_insert=Trueforce_update=True参数传递给save()方法。同时传递这两个参数是错误的:不能同时执行插入和更新!

使用多表继承时,还可以为force_insert提供一个父类元组,以便为每个基类强制执行INSERT语句。例如

Restaurant(pk=1, name="Bob's Cafe").save(force_insert=(Place,))

Restaurant(pk=1, name="Bob's Cafe", rating=4).save(force_insert=(Place, Rating))

可以传递force_insert=(models.Model,)来强制为所有父类执行INSERT语句。默认情况下,force_insert=True仅强制为当前模型插入新行。

很少需要使用这些参数。Django 几乎总是会做正确的事情,尝试覆盖它会导致难以追踪的错误。此功能仅供高级用户使用。

使用update_fields将类似于force_update强制执行更新。

Django 5.0 中的更改

添加了向force_insert传递父类元组的支持。

基于现有字段更新属性

有时需要对字段执行简单的算术运算,例如递增或递减当前值。实现此目的的一种方法是在 Python 中进行算术运算,例如

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

如果从数据库检索到的旧number_sold值为 10,则值 11 将被写回数据库。

可以通过表达相对于原始字段值的更新(而不是显式赋值新值)来提高此过程的健壮性,避免竞争条件,并使其速度略快。Django 提供了F 表达式来执行这种相对更新。使用F 表达式,前面的示例表示为

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

有关更多详细信息,请参阅有关F 表达式及其在更新查询中的使用的文档。

指定要保存的字段

如果向save()方法的关键字参数update_fields传递字段名称列表,则只更新该列表中命名的字段。如果只想更新对象的一个或几个字段,这可能很有用。通过阻止更新数据库中的所有模型字段,可以稍微提高性能。例如

product.name = "Name changed again"
product.save(update_fields=["name"])

update_fields参数可以是包含字符串的任何可迭代对象。空update_fields可迭代对象将跳过保存操作。值为None将对所有字段执行更新。

指定update_fields将强制执行更新。

保存通过延迟模型加载(only()defer())获取的模型时,只有从数据库加载的字段才会被更新。实际上,在这种情况下会自动使用update_fields。如果赋值或更改任何延迟字段的值,该字段将添加到已更新字段中。

Field.pre_save()update_fields

如果传递了update_fields,则只调用update_fieldspre_save()方法。例如,这意味着除非将auto_now=True的日期/时间字段包含在update_fields中,否则它们不会被更新。

删除对象

Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False)[source]
Model.adelete(using=DEFAULT_DB_ALIAS, keep_parents=False)

异步版本adelete()

为对象发出 SQL DELETE命令。这只会删除数据库中的对象;Python 实例仍然存在,其字段中仍然包含数据,但主键将设置为None。此方法返回已删除的对象数量以及包含每个对象类型删除数量的字典。

有关更多详细信息(包括如何批量删除对象),请参见删除对象

如果需要自定义删除行为,可以覆盖delete()方法。有关更多详细信息,请参见覆盖预定义模型方法

使用多表继承时,有时可能只想删除子模型的数据。指定keep_parents=True将保留父模型的数据。

对象的序列化

pickle模型时,将对其当前状态进行序列化。取消序列化时,它将包含序列化时的模型实例,而不是数据库中当前的数据。

不能在不同版本之间共享序列化数据

模型的序列化数据仅对用于生成它们的 Django 版本有效。如果使用 Django N 版本生成序列化数据,则不能保证该序列化数据可以使用 Django N+1 版本读取。序列化数据不应作为长期存档策略的一部分使用。

由于pickle兼容性错误难以诊断,例如对象静默损坏,因此当您尝试在与pickle模型版本不同的Django版本中解pickle模型时,会引发RuntimeWarning

其他模型实例方法

一些对象方法具有特殊用途。

__str__()

Model.__str__()[source]

当您对对象调用str()时,会调用__str__()方法。Django在许多地方使用str(obj)。最值得注意的是,在Django管理站点中显示对象,以及在显示对象时将其值插入模板中。因此,您应该始终从__str__()方法返回一个清晰易懂的模型表示。

例如

from django.db import models


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

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

__eq__()

Model.__eq__()[source]

相等方法的定义是这样的:具有相同主键值和相同具体类的实例被认为是相等的,但主键值为None的实例只与其自身相等。对于代理模型,具体类定义为模型的第一个非代理父类;对于所有其他模型,它只是模型的类。

例如

from django.db import models


class MyModel(models.Model):
    id = models.AutoField(primary_key=True)


class MyProxyModel(MyModel):
    class Meta:
        proxy = True


class MultitableInherited(MyModel):
    pass


# Primary keys compared
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) != MyModel(id=2)
# Primary keys are None
MyModel(id=None) != MyModel(id=None)
# Same instance
instance = MyModel(id=None)
instance == instance
# Proxy model
MyModel(id=1) == MyProxyModel(id=1)
# Multi-table inheritance
MyModel(id=1) != MultitableInherited(id=1)

__hash__()

Model.__hash__()[source]

__hash__()方法基于实例的主键值。它实际上是hash(obj.pk)。如果实例没有主键值,则会引发TypeError(否则__hash__()方法在实例保存前后将返回不同的值,但在Python中禁止更改实例的__hash__()值)。

get_absolute_url()

Model.get_absolute_url()

定义一个get_absolute_url()方法来告诉Django如何计算对象的规范URL。对于调用者来说,此方法应该返回一个字符串,该字符串可用于通过HTTP引用对象。

例如

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

虽然此代码正确且简单,但它可能不是编写此类方法最便携的方式。reverse()函数通常是最佳方法。

例如

def get_absolute_url(self):
    from django.urls import reverse

    return reverse("people-detail", kwargs={"pk": self.pk})

Django使用get_absolute_url()的一个地方是在admin应用程序中。如果对象定义了此方法,则对象编辑页面将具有一个“在站点上查看”链接,该链接将直接跳转到对象的公共视图,如get_absolute_url()所示。

类似地,Django的一些其他部分,例如syndication feed framework,在定义时使用get_absolute_url()。如果您的模型实例各自具有唯一的URL是有意义的,则应定义get_absolute_url()

警告

您应该避免从未验证的用户输入构建URL,以减少链接或重定向中毒的可能性。

def get_absolute_url(self):
    return "/%s/" % self.name

如果self.name'/example.com',则返回'//example.com/',这反过来是一个有效的schema相对URL,但不是预期的'/%2Fexample.com/'

最好在模板中使用get_absolute_url(),而不是硬编码对象的URL。例如,这段模板代码很糟糕

<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>

这段模板代码要好得多

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

这里的逻辑是,如果您更改对象的URL结构,即使是像纠正拼写错误这样的小事情,您也不希望必须跟踪可能创建URL的每个位置。在get_absolute_url()中指定一次,让所有其他代码调用该位置。

注意

您从get_absolute_url()返回的字符串**必须**仅包含ASCII字符(URI规范要求,RFC 3986 Section 2),如有必要,则应进行URL编码。

调用get_absolute_url()的代码和模板应该能够直接使用结果,无需任何进一步的处理。如果您使用包含ASCII范围之外的字符的字符串,可以使用django.utils.encoding.iri_to_uri()函数来帮助完成此操作。

额外的实例方法

除了save()delete()之外,模型对象可能还有一些以下方法

Model.get_FOO_display()

对于每个已设置choices的字段,对象将具有get_FOO_display()方法,其中FOO是字段的名称。此方法返回字段的“人类可读”值。

例如

from django.db import models


class Person(models.Model):
    SHIRT_SIZES = {
        "S": "Small",
        "M": "Medium",
        "L": "Large",
    }
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
Model.get_next_by_FOO(**kwargs)
Model.get_previous_by_FOO(**kwargs)

对于每个未设置null=TrueDateFieldDateTimeField,对象将具有get_next_by_FOO()get_previous_by_FOO()方法,其中FOO是字段的名称。这将返回关于日期字段的下一个和上一个对象,并在适当的时候引发DoesNotExist异常。

这两种方法都将使用模型的默认管理器执行其查询。如果您需要模拟自定义管理器使用的筛选,或者想要执行一次性自定义筛选,这两种方法也接受可选的关键字参数,这些参数的格式应如Field lookups中所述。

请注意,在日期值相同的情况下,这些方法将使用主键作为决胜符。这保证不会跳过或重复任何记录。这也意味着您不能在未保存的对象上使用这些方法。

覆盖额外的实例方法

在大多数情况下,覆盖或继承get_FOO_display()get_next_by_FOO()get_previous_by_FOO()应该按预期工作。但是,由于它们是由元类添加的,因此无法考虑所有可能的继承结构。在更复杂的情况下,您应该覆盖Field.contribute_to_class()来设置您需要的 方法。

其他属性

_state

Model._state

_state属性指的是一个ModelState对象,该对象跟踪模型实例的生命周期。

ModelState对象有两个属性:adding,一个标志,如果模型尚未保存到数据库中,则为True;以及db,一个字符串,指的是实例从中加载或保存到的数据库别名。

新实例化的实例具有adding=Truedb=None,因为它们尚未保存。从QuerySet获取的实例将具有adding=False,并且db设置为关联数据库的别名。

返回顶部