本文档描述了 Model
应用程序编程接口。它建立在 model 和 database query 指南,所以在阅读本文之前,您可能需要阅读和理解这些文档。
在本参考中,我们将使用 example blog models 在 database query guide 。
要创建模型的新实例,请像任何其他Python类一样实例化它:
关键字参数是您在模型上定义的字段的名称。请注意,实例化模型绝不会影响您的数据库;为此,您需要 save()
。
备注
您可能会想通过重写 __init__
方法。但是,如果这样做,请注意不要更改调用签名,因为任何更改都可能阻止保存模型实例。此外,引用内的模型字段 __init__
在某些情况下可能会导致无限递归错误。而不是重写 __init__
,请尝试使用以下方法之一:
在模型类上添加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")
在自定义管理器上添加方法(通常首选)::
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")
这个 from_db()
方法可用于从数据库加载时自定义模型实例创建。
这个 db
参数包含从中加载模型的数据库的数据库别名, field_names
包含所有加载字段的名称,以及 values
包含中每个字段的加载值 field_names
. 这个 field_names
顺序与 values
. 如果模型的所有字段都存在,则 values
保证一切正常 __init__()
期待他们。也就是说,可以通过 cls(*values)
. 如果有任何字段被延迟,它们将不会出现在 field_names
. 在这种情况下,指定一个值 django.db.models.DEFERRED
到每个丢失的字段。
除了创建新模型外, from_db()
方法必须设置 adding
和 db
新实例中的标志 _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, **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()
实现以澄清如何完成这一操作。在这种情况下,可以使用 super()
电话 from_db()
方法。
如果从模型实例中删除某个字段,则再次访问它会从数据库中重新加载值:
>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field # Loads the field from the database
Asynchronous version : arefresh_from_db()
如果需要从数据库重新加载模型的值,可以使用 refresh_from_db()
方法。当不带参数调用此方法时,将完成以下操作:
模型的所有非延迟字段都将更新为数据库中当前存在的值。
从重新加载的实例中清除所有缓存的关系。
只有模型的字段才从数据库中重新加载。其他与数据库相关的值(如注释)不会重新加载。任何 @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
。它使您可以更好地控制模型的重新加载方式。例如,当您的模型使用软删除时,您可以 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())
这个 from_queryset
添加了参数。
一个helper方法,它返回一个集合,该集合包含当前为此模型延迟的所有字段的属性名。
验证模型涉及四个步骤:
验证模型字段- Model.clean_fields()
整体验证模型- Model.clean()
验证字段唯一性- Model.validate_unique()
验证约束条件- Model.validate_constraints()
当您调用模型的 full_clean()
方法。
当你使用 ModelForm
呼唤 is_valid()
将对表单中包含的所有字段执行这些验证步骤。见 ModelForm documentation 更多信息。你只需要给模型调用 full_clean()
方法,如果计划自己处理验证错误,或者已从 ModelForm
需要验证的。
此方法调用 Model.clean_fields()
, Model.clean()
, Model.validate_unique()
(如果 validate_unique
是 True
),以及 Model.validate_constraints()
(如果 validate_constraints
是 True
),并引发一个 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()
执行是清理每个字段。
此方法将验证模型上的所有字段。可选的 exclude
参数允许您提供一个 set
要从验证中排除的字段名称的。它将筹集一个 ValidationError
如果有任何字段未通过验证。
第二步 full_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.fields
或 Meta.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."
),
}
)
此方法类似于 clean_fields()
,但验证通过以下方式定义的唯一性约束 Field.unique
, Field.unique_for_date
, Field.unique_for_month
, Field.unique_for_year
,或 Meta.unique_together
而不是单个字段值。可选的 exclude
参数允许您提供一个 set
要从验证中排除的字段名称的。它将筹集一个 ValidationError
如果有任何字段未通过验证。
UniqueConstraint
S定义于 Meta.constraints
通过以下方式进行验证 Model.validate_constraints()
。
请注意,如果您提供 exclude
参数 validate_unique()
任何 unique_together
将不检查涉及您提供的某个字段的约束。
最后, full_clean()
将检查模型上的任何其他约束。
此方法验证在 Meta.constraints
。可选的 exclude
参数允许您提供一个 set
要从验证中排除的字段名称的。它将筹集一个 ValidationError
如果任何约束未通过验证。
要将对象保存回数据库,请调用 save()
:
Asynchronous version : asave()
有关使用 force_insert
和 force_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.
在你调用之前,没有办法知道一个ID的值是多少。 save()
,因为该值是由数据库计算的,而不是由Django计算的。
为了方便起见,每个型号都有一个 AutoField
已命名 id
默认情况下,除非您明确指定 primary_key=True
在模型中的一个字段上。参见文档 AutoField
了解更多详细信息。
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执行以下步骤:
Emit a pre-save signal. 这个 pre_save
发送信号,允许监听该信号的任何函数执行某些操作。
预处理数据。 每个字段的 pre_save()
调用方法来执行所需的任何自动数据修改。例如,日期/时间字段将覆盖 pre_save()
实施 auto_now_add
和 auto_now
.
为数据库准备数据。 每个字段的 get_db_prep_save()
方法被要求以可以写入数据库的数据类型提供其当前值。
大多数字段不需要准备数据。简单的数据类型,如整数和字符串,都可以作为Python对象“准备好写入”。但是,更复杂的数据类型通常需要进行一些修改。
例如, DateField
字段使用python datetime
存储数据的对象。数据库不存储 datetime
对象,因此必须将字段值转换为符合ISO的日期字符串才能插入数据库。
将数据插入数据库。 预处理的、准备好的数据组成一个SQL语句,以便插入到数据库中。
Emit a post-save signal. 这个 post_save
发送信号,允许监听该信号的任何函数执行某些操作。
您可能已经注意到Django数据库对象使用相同的 save()
用于创建和更改对象的方法。Django抽象出了使用 INSERT
或 UPDATE
SQL语句。具体来说,当您调用 save()
而对象的主键属性 not 定义一个 default
或 db_default
,Django遵循以下算法:
如果对象的主键属性设置为计算结果为 True
(即除 None
或空字符串),Django执行 UPDATE
.
如果对象的主键属性为 not 设置或如果 UPDATE
没有更新任何内容(例如,如果主键设置为数据库中不存在的值),Django将执行 INSERT
.
如果对象的主键属性定义了 default
或 db_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
.
在某些极少数情况下,有必要能够强制 save()
执行SQL的方法 INSERT
而不是回到做一个 UPDATE
.反之亦然:如果可能的话,更新,但不插入新行。在这些情况下,您可以通过 force_insert=True
或 force_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
.
有时,您需要对字段执行简单的算术任务,例如递增或递减当前值。实现这一点的一种方法是在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
。
Asynchronous version : adelete()
发出一条SQL DELETE
对象的。这只会删除数据库中的对象;除了设置为的主键之外,该Python实例仍将存在,并且其字段中仍将包含数据 None
。此方法返回已删除的对象数和每个对象类型的删除数词典。
有关更多详细信息,包括如何批量删除对象,请参见 删除对象 .
如果要自定义删除行为,可以重写 delete()
方法。见 重写预定义的模型方法 了解更多详细信息。
有时与 multi-table inheritance 您可能只想删除子模型的数据。指定 keep_parents=True
将保留父模型的数据。
当你 pickle
一个模型,它的当前状态是腌制的。当您取消拾取它时,它将包含它被pickle时的模型实例,而不是当前在数据库中的数据。
一些对象方法有特殊的用途。
__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__()
¶相等方法的定义是,具有相同主键值和相同具体类的实例被视为相等,但具有相同主键值的实例除外。 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__()
¶这个 __hash__()
方法基于实例的主键值。它是有效的 hash(obj.pk)
. 如果实例没有主键值,则 TypeError
将被提升(否则 __hash__()
方法将在保存实例之前和之后返回不同的值,但更改 __hash__()
在python中禁止实例的值。
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()
,模型对象可能具有以下某些方法:
每一个领域 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'
对于每一个 DateField
和 DateTimeField
那没有 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
¶这个 _state
属性指的是 ModelState
跟踪模型实例生命周期的对象。
这个 ModelState
对象有两个属性: adding
,一面旗帜, True
如果模型尚未保存到数据库,并且 db
,一个字符串,引用实例加载或保存到的数据库别名。
新实例化的实例已经 adding=True
和 db=None
,因为他们尚未被拯救。从一个 QuerySet
会有 adding=False
和 db
设置为关联数据库的别名。
7月 22, 2024