模型实例引用

本文档描述了 Model 应用程序编程接口。它建立在 modeldatabase query 指南,所以在阅读本文之前,您可能需要阅读和理解这些文档。

在本参考中,我们将使用 example blog modelsdatabase query guide

创建对象

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

class Model(**kwargs)[源代码]

关键字参数是您在模型上定义的字段的名称。请注意,实例化一个模型决不会影响到您的数据库;为此,您需要 save() .

备注

您可能会想通过重写 __init__ 方法。但是,如果这样做,请注意不要更改调用签名,因为任何更改都可能阻止保存模型实例。此外,引用内的模型字段 __init__ 在某些情况下可能会导致无限递归错误。而不是重写 __init__ ,请尝试使用以下方法之一:

  1. 在模型类上添加ClassMethod::

    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)[源代码]

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

这个 db 参数包含从中加载模型的数据库的数据库别名, field_names 包含所有加载字段的名称,以及 values 包含中每个字段的加载值 field_names . 这个 field_names 顺序与 values . 如果模型的所有字段都存在,则 values 保证一切正常 __init__() 期待他们。也就是说,可以通过 cls(*values) . 如果有任何字段被延迟,它们将不会出现在 field_names . 在这种情况下,指定一个值 django.db.models.DEFERRED 到每个丢失的字段。

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

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

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, *args, **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(*args, **kwargs)

上面的例子显示了一个完整的 from_db() 实施以澄清如何做到这一点。在这种情况下,可以使用 super() 调用 from_db() 方法。

从数据库刷新对象

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

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

Asynchronous versionarefresh_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)
Model.get_deferred_fields()[源代码]

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

正在验证对象

验证模型涉及四个步骤:

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

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

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

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

当您调用模型的 full_clean() 方法。

当你使用 ModelForm 呼唤 is_valid() 将对表单中包含的所有字段执行这些验证步骤。见 ModelForm documentation 更多信息。你只需要给模型调用 full_clean() 方法,如果计划自己处理验证错误,或者已从 ModelForm 需要验证的。

警告

包含以下内容的约束 JSONField 可能不会引发验证错误,因为键、索引和路径转换具有许多特定于数据库的警告。这 may be fully supported later

您应该始终检查没有日志消息,在 django.db.models 记录器,就像 "Got a database error calling check() on …" 以确认它是否经过了正确的验证。

Model.full_clean(exclude=None, validate_unique=True, validate_constraints=True)[源代码]

此方法调用 Model.clean_fields()Model.clean()Model.validate_unique() (如果 validate_uniqueTrue ),以及 Model.validate_constraints() (如果 validate_constraintsTrue ),并引发一个 ValidationError 它有一个 message_dict 属性,该属性包含所有四个阶段的错误。

可选的 exclude 参数可用于提供 set 可以从验证和清除中排除的字段名称的。 ModelForm 使用此参数排除表单上不存在的域,因为用户无法更正引发的任何错误。

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

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)[源代码]

此方法将验证模型上的所有字段。可选的 exclude 参数允许您提供一个 set 要从验证中排除的字段名称的。它将筹集一个 ValidationError 如果有任何字段未通过验证。

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

Model.clean()[源代码]

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

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() 一个模型 clean() 当调用模型的 save() 方法。

在上面的示例中, ValidationError 引发的异常 Model.clean() 是用字符串实例化的,因此它将存储在一个特殊的错误字典键中, 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)[源代码]

此方法类似于 clean_fields() ,但验证通过以下方式定义的唯一性约束 Field.uniqueField.unique_for_dateField.unique_for_monthField.unique_for_year ,或 Meta.unique_together 而不是单个字段值。可选的 exclude 参数允许您提供一个 set 要从验证中排除的字段名称的。它将筹集一个 ValidationError 如果有任何字段未通过验证。

UniqueConstraint S定义于 Meta.constraints 通过以下方式进行验证 Model.validate_constraints()

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

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

Model.validate_constraints(exclude=None)[源代码]

此方法验证在 Meta.constraints 。可选的 exclude 参数允许您提供一个 set 要从验证中排除的字段名称的。它将筹集一个 ValidationError 如果任何约束未通过验证。

保存对象

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

Model.save(force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)[源代码]
Model.asave(force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)[源代码]

Asynchronous versionasave()

有关使用 force_insertforce_update 参数,请参见 强制插入或更新 。有关的详细信息 update_fields 参数可以在 指定要保存的字段 一节。

如果要自定义保存行为,可以覆盖此 save() 方法。见 重写预定义的模型方法 了解更多详细信息。

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

自动递增主键

如果模型有一个 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.

在你调用之前,没有办法知道一个ID的值是多少。 save() ,因为该值是由数据库计算的,而不是由Django计算的。

为了方便起见,每个型号都有一个 AutoField 已命名 id 默认情况下,除非您明确指定 primary_key=True 在模型中的一个字段上。参见文档 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!

How Django knows to UPDATE vs. INSERT 以下是发生这种情况的原因。

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

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

当你存钱时会发生什么?

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

  1. Emit a pre-save signal. 这个 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. Emit a post-save signal. 这个 post_save 发送信号,允许监听该信号的任何函数执行某些操作。

Django如何知道更新与插入

您可能已经注意到Django数据库对象使用相同的 save() 用于创建和更改对象的方法。Django抽象出了使用 INSERTUPDATE SQL语句。具体来说,当您调用 save() 而对象的主键属性 not 定义一个 defaultdb_default ,Django遵循以下算法:

  • 如果对象的主键属性设置为计算结果为 True (即除 None 或空字符串),Django执行 UPDATE .

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

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

这里要注意的一点是,如果不能保证主键值是未使用的,那么在保存新对象时应该注意不要显式地指定主键值。有关此细微差别的更多信息,请参见 Explicitly specifying auto-primary-key values 上面和 Forcing an INSERT or UPDATE 下面。

在Django 1.5及更早的版本中,Django做了一个 SELECT 设置主键属性时。如果 SELECT 找到一行,然后Django做了一个 UPDATE ,否则它做了一个 INSERT . 旧算法在 UPDATE 案例。在一些罕见的情况下,即使数据库包含对象主键值的行,数据库也不会报告行已更新。PostgreSQL就是一个例子 ON UPDATE 返回的触发器 NULL . 在这种情况下,可以通过设置 select_on_save 选择权 True .

Changed in Django 5.0:

这个 Field.db_default 参数已添加。

强制插入或更新

在某些罕见的情况下,必须能够强制 save() 执行SQL的方法 INSERT 而不是回到做一个 UPDATE . 反之亦然:如果可能,更新,但不插入新行。在这些情况下,您可以通过 force_insert=Trueforce_update=True 参数到 save() 方法。传递这两个参数是错误的:不能同时插入 and 同时更新!

使用时 multi-table inheritance ,还可以提供父类的元组来 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 .

Changed in Django 5.0:

支持将父类的元组传递给 force_insert 已添加。

基于现有字段更新属性

有时,您需要对字段执行简单的算术任务,例如递增或递减当前值。实现这一点的一种方法是在Python中执行如下算术:

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

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

这一过程可以变得健壮, avoiding a race condition ,并且通过表示相对于原始字段值的更新,而不是作为新值的显式赋值来略微加快速度。Django提供 F expressions 执行这种相对更新。vbl.使用 F expressions ,上一个示例表示为:

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

有关更多详细信息,请参阅 F expressions 及其 use in update queries .

指定要保存的字段

如果 save() 在关键字参数中传递字段名称列表 update_fields ,将只更新该列表中命名的字段。如果您只想更新一个对象上的一个或几个字段,这可能是可取的。阻止在数据库中更新所有模型字段会带来轻微的性能优势。例如::

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

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

指定 update_fields 将强制更新。

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

Field.pre_save() and update_fields

如果 update_fields 是传入的,只有 pre_save() 的方法。 update_fields 都被称为。例如,这意味着日期/时间字段 auto_now=True 将不会更新,除非它们包含在 update_fields

删除对象

Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False)[源代码]
Model.adelete(using=DEFAULT_DB_ALIAS, keep_parents=False)[源代码]

Asynchronous versionadelete()

发出一条SQL DELETE 对象的。这只会删除数据库中的对象;除了设置为的主键之外,该Python实例仍将存在,并且其字段中仍将包含数据 None 。此方法返回已删除的对象数和每个对象类型的删除数词典。

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

如果要自定义删除行为,可以重写 delete() 方法。见 重写预定义的模型方法 了解更多详细信息。

有时与 multi-table inheritance 您可能只想删除子模型的数据。指定 keep_parents=True 将保留父模型的数据。

酸洗对象

当你 pickle 一个模型,它的当前状态是腌制的。当您取消拾取它时,它将包含它被pickle时的模型实例,而不是当前在数据库中的数据。

您不能在不同版本之间共享pickle

模型的pickle仅对用于生成它们的django版本有效。如果使用django版本n生成pickle,则无法保证pickle可以与django版本n+1一起读取。泡菜不应该作为长期存档策略的一部分。

由于pickle兼容性错误很难诊断,例如静默损坏的对象, RuntimeWarning 当您尝试在Django版本中取消拾取不同于其被腌制版本的模型时引发。

其他模型实例方法

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

__str__()

Model.__str__()[源代码]

这个 __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__()[源代码]

相等方法的定义是,具有相同主键值和相同具体类的实例被视为相等,但具有相同主键值的实例除外。 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__()[源代码]

这个 __hash__() 方法基于实例的主键值。它是有效的 hash(obj.pk) . 如果实例没有主键值,则 TypeError 将被提升(否则 __hash__() 方法将在保存实例之前和之后返回不同的值,但更改 __hash__() 在python中禁止实例的值。

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() 在管理应用程序中。如果一个对象定义了这个方法,那么对象编辑页面将有一个“站点视图”链接,该链接将直接跳转到对象的公共视图,如 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/' 反过来,它是一个有效的模式相关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() 让你所有其他的代码都叫那个地方。

备注

The string you return from get_absolute_url() must contain only ASCII characters (required by the URI specification, RFC 3986#section-2) and be URL-encoded, if necessary.

代码和模板调用 get_absolute_url() 应该能够直接使用结果而无需进一步处理。您可能希望使用 django.utils.encoding.iri_to_uri() 如果使用的字符串包含ASCII范围之外的字符,则函数可帮助解决此问题。

额外的实例方法

除了 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)

对于每一个 DateFieldDateTimeField 那没有 null=True ,对象将具有 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=Falsedb 设置为关联数据库的别名。