- 模型字段参考
- 字段选项
- 字段类型
AutoField
BigAutoField
BigIntegerField
BinaryField
BooleanField
CharField
DateField
DateTimeField
DecimalField
DurationField
EmailField
FileField
FilePathField
FloatField
GeneratedField
GenericIPAddressField
ImageField
IntegerField
JSONField
PositiveBigIntegerField
PositiveIntegerField
PositiveSmallIntegerField
SlugField
SmallAutoField
SmallIntegerField
TextField
TimeField
URLField
UUIDField
- 关系字段
- 字段 API 参考
- 注册和获取查询
- 字段属性参考
模型字段参考
本文档包含 Field 类的所有 API 参考,包括 字段选项 和 字段类型。
参见
If the built-in fields don’t do the trick, you can try django-localflavor (documentation), which contains assorted pieces of code that are useful for particular countries and cultures.
当然,你也可以简单的 编写自定义模型字段。
备注
从技术上讲,这些方法都被定义在 django.db.models.fields,但为了方便,它们被导入到 django.db.models;标准的惯例是使用 from django.db import models
并利用 models.<Foo>Field
。
字段选项
以下参数对所以字段类型均有效,且是可选的。
null
Field.null
如果是 True
, Django 将在数据库中存储空值为 NULL
。默认为 False
。
避免在基于字符串的字段上使用 null,如 CharField 和 TextField。如果一个基于字符串的字段有 null=True
,这意味着它有两种可能的“无数据”值。NULL
,和空字符串。在大多数情况下,“无数据”有两种可能的值是多余的,Django 的惯例是使用空字符串,而不是 NULL
。一个例外是当一个 CharField 同时设置了 unique=True
和 blank=True
。在这种情况下,null=True
是需要的,以避免在保存具有空白值的多个对象时违反唯一约束。
无论是基于字符串的字段还是非字符串的字段,如果希望在表单中允许空值,还需要设置 blank=True
,因为 null 参数只影响数据库的存储(参见 blank )。
备注
当使用 Oracle 数据库后端时,不管这个属性是什么,都会存储 NULL
值来表示空字符串。
blank
Field.blank
如果是 True
,该字段允许为空。默认为 False
。
注意,这与 null 不同。 null 纯属数据库相关,而 blank 则与验证相关。如果一个字段有 blank=True
,表单验证将允许输入一个空值。如果一个字段有 blank=False
,则该字段为必填字段。
提供缺失值
blank=True
可以用于 null=False
的字段,但这需要在模型上实现 clean(),以便以编程方式提供任何缺失值。
choices
Field.choices
[源代码]
一个以下述格式的映射或可迭代对象,用作该字段的选项。如果提供了选项,它们将被 模型验证 强制执行,并且默认的表单小部件将是一个选择框,其中包含这些选项,而不是标准的文本字段。
如果提供了映射,键元素是要设置在模型上的实际值,第二个元素是可读的人类名称。例如:
YEAR_IN_SCHOOL_CHOICES = {
"FR": "Freshman",
"SO": "Sophomore",
"JR": "Junior",
"SR": "Senior",
"GR": "Graduate",
}
你还可以传递一个包含自身由两个项目的可迭代对象的 序列 (例如,[(A1, B1), (A2, B2), …]
)。每个元组中的第一个元素是要设置在模型上的实际值,第二个元素是可读的人类名称。例如:
YEAR_IN_SCHOOL_CHOICES = [
("FR", "Freshman"),
("SO", "Sophomore"),
("JR", "Junior"),
("SR", "Senior"),
("GR", "Graduate"),
]
choices
也可以定义为一个可调用对象,它不需要参数并返回上述任何格式之一。例如:
def get_currencies():
return {i: i for i in settings.CURRENCIES}
class Expense(models.Model):
amount = models.DecimalField(max_digits=10, decimal_places=2)
currency = models.CharField(max_length=3, choices=get_currencies)
当选项是以下情况时,将可调用对象传递给 choices
可以特别方便:
- 将可调用对象传递给
choices
尤其方便的情况是,它可以用于处理 I/O 绑定的操作结果(这些结果可能会被缓存),比如查询同一数据库或外部数据库中的表,或者从静态文件中获取选项。 - 一个大部分稳定但在不同时间或项目之间可能会有变化的列表。这种情况下的示例包括使用第三方应用程序,这些应用程序提供了已知的值清单,如货币、国家、语言、时区等。
Changed in Django 5.0:
添加了对映射和可调用对象的支持。
一般来说,最好在模型类内部定义选择,并为每个值定义一个合适的名称的常量:
from django.db import models
class Student(models.Model):
FRESHMAN = "FR"
SOPHOMORE = "SO"
JUNIOR = "JR"
SENIOR = "SR"
GRADUATE = "GR"
YEAR_IN_SCHOOL_CHOICES = {
FRESHMAN: "Freshman",
SOPHOMORE: "Sophomore",
JUNIOR: "Junior",
SENIOR: "Senior",
GRADUATE: "Graduate",
}
year_in_school = models.CharField(
max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in {self.JUNIOR, self.SENIOR}
虽然你可以在模型类之外定义一个选择列表,然后引用它,但在模型类内定义选择和每个选择的名称,可以将所有这些信息保留在使用它的类中,并帮助引用这些选择(例如,Student.SOPHOMORE
将在导入 Student
模型的任何地方工作)。
你还可以将你的可用选择收集到可用于组织目的的命名组中:
MEDIA_CHOICES = {
"Audio": {
"vinyl": "Vinyl",
"cd": "CD",
},
"Video": {
"vhs": "VHS Tape",
"dvd": "DVD",
},
"unknown": "Unknown",
}
映射的键是要应用于组的名称,值是该组内的选项,包括字段值和一个可读的选项名称。在单个映射内,可以将分组选项与非分组选项组合在一起(例如,此示例中的 "unknown"
选项)。
你还可以使用一个序列,例如,一个包含 2 元组的列表:
MEDIA_CHOICES = [
(
"Audio",
(
("vinyl", "Vinyl"),
("cd", "CD"),
),
),
(
"Video",
(
("vhs", "VHS Tape"),
("dvd", "DVD"),
),
),
("unknown", "Unknown"),
]
请注意,选择可以是任何序列对象——不一定是列表或元组。这让你可以动态地构造选择。但是如果你发现自己把 chips
魔改成动态的,你可能最好使用一个合适的的带有 ForeignKey 的数据库表。 chips
是用于静态数据的,如果有的话,不应该有太大的变化。
备注
每当 choices
的顺序变动时将会创建新的迁移。
对于每个具有 choices 设置的模型字段,Django 将规范化选择项为一个 2-元组的列表,并添加一个方法来获取字段当前值的可读名称。请参阅数据库 API 文档中的 get_FOO_display()。
除非 blank=False 与 default 一起设置在字段上,否则包含 "---------"
的标签将与选择框一起呈现。要覆盖这种行为,可以在 choices
中添加一个包含 None
的元组,例如 (None, 'Your String For Display')
。另外,你也可以在有意义的地方使用一个空字符串来代替 None
——比如在 CharField。
枚举类型
此外,Django 还提供了枚举类型,你可以通过将其子类化来简洁地定义选择:
from django.utils.translation import gettext_lazy as _
class Student(models.Model):
class YearInSchool(models.TextChoices):
FRESHMAN = "FR", _("Freshman")
SOPHOMORE = "SO", _("Sophomore")
JUNIOR = "JR", _("Junior")
SENIOR = "SR", _("Senior")
GRADUATE = "GR", _("Graduate")
year_in_school = models.CharField(
max_length=2,
choices=YearInSchool,
default=YearInSchool.FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in {
self.YearInSchool.JUNIOR,
self.YearInSchool.SENIOR,
}
这些工作类似于 Python 标准库中的 enum,但是做了一些修改。
枚举成员的值是用于构造具体数据类型的参数元组。Django 支持在此元组的末尾添加额外的字符串值,用作可读名称或
label
。这个label
可以是懒惰可翻译的字符串。因此,在大多数情况下,成员值将是一个(value, label)
的 2-元组。请参阅下面的示例,了解使用更复杂的数据类型来进行选择的 子类化选择项的示例。如果未提供元组,或者最后一项不是(懒惰)字符串,则从成员名称中 自动生成label
。在值上添加
.label
属性,以返回人类可读的名称。一些自定义属性被添加到枚举类中——
.choices
、.labels
、.values
和.names
——以便更容易访问这些枚举的各个部分的列表。警告
这些属性名称不能作为成员名称使用,因为它们会发生冲突。
强制使用 enum.unique() 是为了确保不能多次定义值。在选择一个字段时,不太可能会出现这种情况。
请注意,使用 YearInSchool.SENIOR
、YearInSchool['SENIOR']
或 YearInSchool('SR')
来访问或查找枚举成员,与成员上的 .name
和 .value
属性一样,都能正常工作。
如果你不需要将可读的名称翻译成其他语言,你可以从成员名称中推断出它们(将下划线替换为空格,并使用标题大小写):
>>> class Vehicle(models.TextChoices):
... CAR = "C"
... TRUCK = "T"
... JET_SKI = "J"
...
>>> Vehicle.JET_SKI.label
'Jet Ski'
由于枚举值需要为整数的情况极为常见,Django 提供了一个 IntegerChoices
类。例如:
class Card(models.Model):
class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4
suit = models.IntegerField(choices=Suit)
还可以利用 Enum Functional API,但需要注意自动生成的标签如上所示:
>>> MedalType = models.TextChoices("MedalType", "GOLD SILVER BRONZE")
>>> MedalType.choices
[('GOLD', 'Gold'), ('SILVER', 'Silver'), ('BRONZE', 'Bronze')]
>>> Place = models.IntegerChoices("Place", "FIRST SECOND THIRD")
>>> Place.choices
[(1, 'First'), (2, 'Second'), (3, 'Third')]
如果你需要支持 int
或 str
以外的具体数据类型,你可以将 Choices
和所需的具体数据类型子类化,例如 date 与 DateField 一起使用:
class MoonLandings(datetime.date, models.Choices):
APOLLO_11 = 1969, 7, 20, "Apollo 11 (Eagle)"
APOLLO_12 = 1969, 11, 19, "Apollo 12 (Intrepid)"
APOLLO_14 = 1971, 2, 5, "Apollo 14 (Antares)"
APOLLO_15 = 1971, 7, 30, "Apollo 15 (Falcon)"
APOLLO_16 = 1972, 4, 21, "Apollo 16 (Orion)"
APOLLO_17 = 1972, 12, 11, "Apollo 17 (Challenger)"
还有一些注意事项需要注意:
枚举类型不支持 命名组。
因为具有具体数据类型的枚举要求所有值都与类型相匹配,所以不能通过创建一个值为
None
的成员来覆盖 空白标签。相反,在类上设置__empty__
属性:class Answer(models.IntegerChoices):
NO = 0, _("No")
YES = 1, _("Yes")
__empty__ = _("(Unknown)")
Changed in Django 5.0:
db_column
Field.db_column
这个字段要使用的数据库列名。如果没有给出列名,Django 将使用字段名。
如果你的数据库列名是 SQL 的保留字,或者包含了 Python 变量名中不允许的字符——特别是连字符——那也没关系。Django 会在幕后引用列名和表名。
db_comment
Field.db_comment
用于此字段的数据库列的注释。对于具有直接数据库访问权限但可能不查看您的 Django 代码的人来说,这非常有用。例如:
pub_date = models.DateTimeField(
db_comment="Date and time when the article was published",
)
db_default
New in Django 5.0.
Field.db_default
这个字段的默认值是数据库计算的。这可以是一个字面值或者一个数据库函数,比如: Now:
created = models.DateTimeField(db_default=Now())
更复杂的表达式也可以使用,只要它们由字面值和数据库函数构成:
month_due = models.DateField(
db_default=TruncMonth(
Now() + timedelta(days=90),
output_field=models.DateField(),
)
)
数据库默认值不能引用其他字段或模型。例如,这是无效的:
end = models.IntegerField(db_default=F("start") + 50)
如果同时设置了 db_default
和 Field.default,在 Python 代码中创建实例时 default
会优先生效。db_default
仍然会在数据库级别设置,并且在使用 ORM 之外插入行或在迁移中添加新字段时仍然会使用它。
db_index
Field.db_index
如果是 True
,将为该字段创建数据库索引。
使用 indexes 选项代替。
在可能的情况下,使用 Meta.indexes 选项。在几乎所有情况下,indexes 提供比 db_index
更多的功能。db_index
未来可能会被弃用。
db_tablespace
Field.db_tablespace
[源代码]
如果这个字段有索引,那么要为这个字段的索引使用的 数据库表空间 的名称。默认是项目的 DEFAULT_INDEX_TABLESPACE 设置(如果有设置),或者是模型的 db_tablespace (如果有)。如果后端不支持索引的表空间,则忽略此选项。
default
Field.default
该字段的默认值。可以是一个值或者是个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。
默认值不能是一个可更改的对象(模型实例、list
、set
等),因为对该对象同一实例的引用将被用作所有新模型实例的缺省值。相反,将所需的默认值包裹在一个可调用对象中。例如,如果你想为 JSONField 指定一个默认的 dict
,使用一个函数:
def contact_default():
return {"email": "to1@example.com"}
contact_info = JSONField("ContactInfo", default=contact_default)
lambda
不能用于 default
等字段选项,因为它们不能被 迁移序列化。其他注意事项见该文档。
对于像 ForeignKey 这样映射到模型实例的字段,默认应该是它们引用的字段的值(默认是 pk
除非 to_field 被设置了),而不是模型实例。
当创建新的模型实例且没有为该字段提供值时,使用默认值。当字段是主键时,当字段设置为``None`` 时,也使用默认值。
默认值也可以在数据库级别使用 Field.db_default 来设置。
editable
Field.editable
如果是 False
,该字段将不会在管理或任何其他 ModelForm 中显示。在 模型验证 中也会跳过。默认为 True
。
error_messages
Field.error_messages
[源代码]
error_messages
参数可以让你覆盖该字段引发的默认消息。传入一个与你想覆盖的错误信息相匹配的键值的字典。
错误信息键包括 null
、blank
、invalid
、invalid_choice
、unique
和 unique_for_date
。在下面的 字段类型 一节中为每个字段指定了额外的错误信息键。
这些错误信息通常不会传播到表单中。参见 有关模型的 error_messages 的注意事项。
help_text
Field.help_text
额外的“帮助”文本,随表单控件一同显示。即便你的字段未用于表单,它对于生成文档也是很有用的。
请注意,在自动生成的表格中,这个值 不是 HTML 转义的。如果你愿意的话,你可以在 help_text 中加入 HTML。例如:
help_text = "Please use the following format: <em>YYYY-MM-DD</em>."
或者你可以使用纯文本和 django.utils.html.escape() 来转义任何 HTML 特殊字符。确保你转义任何可能来自不受信任的用户的帮助文本,以避免跨站脚本攻击。
primary_key
Field.primary_key
如果设置为 True
,将该字段设置为该模型的主键。
如果你没有为模型中的任何字段指定 primary_key=True
,Django 会自动添加一个字段来保存主键,所以你不需要在任何字段上设置 primary_key=True,除非你想覆盖默认主键行为。自动创建的主键字段的类型可以在 AppConfig.default_auto_field 中为每个应用程序指定,或者在 DEFAULT_AUTO_FIELD 配置中全局指定。更多信息,请参阅 自动设置主键。
primary_key=True
意味着 null=False 和 unique=True。一个对象只允许有一个主键。
主键字段是只读的。如果您改变了现有对象的主键值,然后将其保存,则会在旧对象旁边创建一个新对象。
主键字段在 deleting 对象时设置为 None
。
unique
Field.unique
[源代码]
如果设置为 True
,这个字段必须在整个表中保持值唯一。
这是在数据库级别和模型验证中强制执行的。如果你试图保存一个在 unique 字段中存在重复值的模型,模型的 save() 方法将引发 django.db.IntegrityError。
除了 ManyToManyField 和 OneToOneField 之外,该选项对所有字段类型有效。
请注意,当 unique
为 True
时,你不需要指定 db_index,因为 unique
意味着创建一个索引。
unique_for_date
Field.unique_for_date
将其设置为 DateField 或 DateTimeField 的名称,要求该字段的日期字段值是唯一的。
例如,如果你的字段 title
有 unique_for_date="pub_date"
,那么 Django 就不允许输入两条相同 title
和 pub_date
的记录。
请注意,如果将其设置为指向 DateTimeField,则只考虑该字段的日期部分。此外,当 USE_TZ 为 True
时,检查将在对象保存时的 当前时区 中进行。
这在模型验证过程中由 Model.validate_unique() 强制执行,但在数据库级别上不执行。如果任何 unique_for_date 约束涉及的字段不属于 ModelForm (例如,如果其中一个字段被列在``exclude``中,或者有 editable=False ), Model.validate_unique() 将跳过对该特定约束的验证。
unique_for_month
Field.unique_for_month
像 unique_for_date 一样,但要求字段对月份是唯一的。
unique_for_year
Field.unique_for_year
如 unique_fordate
和 unique_formonth
。
verbose_name
Field.verbose_name
字段的一个人类可读名称,如果没有给定详细名称,Django 会使用字段的属性名自动创建,并将下划线转换为空格。参见 详细字段名。
validators
Field.validators
[源代码]
要为该字段运行的验证器列表。更多信息请参见 验证器文档。
字段类型
AutoField
class AutoField
(**options)[源代码]
一个 IntegerField,根据可用的 ID 自动递增。你通常不需要直接使用它;如果你没有指定,主键字段会自动添加到你的模型中。参见 自动设置主键。
BigAutoField
class BigAutoField
(**options)[源代码]
一个 64 位整数,与 AutoField 很相似,但保证适合 1
到 9223372036854775807
的数字。
BigIntegerField
class BigIntegerField
(**options)[源代码]
一个 64 位的整数,和 IntegerField 很像,只是它保证适合从 -9223372036854775808
到 9223372036854775807
的数字。该字段的默认表单部件是一个 NumberInput。
BinaryField
class BinaryField
(max_length=None, **options)[源代码]
一个用于存储原始二进制数据的字段。可以指定为 bytes、bytearray 或 memoryview。
默认情况下,BinaryField
将 ediditable`
设置为 False
,在这种情况下,它不能被包含在 ModelForm 中。
BinaryField.max_length
可选项。字段的最大长度(以字节为单位)。Django 在验证时使用 MaxLengthValidator 来强制执行最大长度。
滥用 BinaryField
虽然你可能会想到在数据库中存储文件,但考虑到这在99%的情况下是糟糕的设计。这个字段 不能 代替正确的 静态文件 处理。
BooleanField
class BooleanField
(**options)[源代码]
一个 true/false 字段。
该字段的默认表单部件是 CheckboxInput,或者如果 null=True 则是 NullBooleanSelect。
当 Field.default 没有定义时,BooleanField
的默认值是 None
。
CharField
class CharField
(max_length=None, **options)[源代码]
一个字符串字段,适用于小到大的字符串。
对于大量的文本,使用 TextField。
该字段的默认表单部件是一个 TextInput。
CharField 具有以下额外参数:
CharField.max_length
字段的最大长度(以字符为单位)。max_length
在数据库级别和在 Django 的验证中使用 MaxLengthValidator 来强制执行。除了 PostgreSQL 支持无限``VARCHAR``列外,它对于 Django 包含的所有数据库后端都是必需的。
备注
如果你编写的应用程序必须可移植到多个数据库后端,你应该意识到,有些后端对 max_length
有限制。详情请参考 数据库后端注释。
CharField.db_collation
可选的。该字段的数据库字符序名称。
备注
字符序名称是不标准化的。因此,这将无法在多个数据库后端之间进行移植。
Oracle
Oracle 只有在 MAX_STRING_SIZE
数据库初始化参数被设置为 EXTENDED
时,才支持字符序。
DateField
class DateField
(auto_now=False, auto_now_add=False, **options)[源代码]
一个日期,在 Python 中用一个 datetime.date
实例表示。有一些额外的、可选的参数。
DateField.auto_now
每次保存对象时,自动将该字段设置为现在。对于“最后修改”的时间戳很有用。请注意,当前日期 总是 被使用,而不仅仅是一个你可以覆盖的默认值。
只有在调用 Model.save() 时,该字段才会自动更新。当以其他方式对其他字段进行更新时,如 QuerySet.update(),该字段不会被更新,尽管你可以在这样的更新中为该字段指定一个自定义值。
DateField.auto_now_add
当第一次创建对象时,自动将该字段设置为现在。对创建时间戳很有用。请注意,当前日期是 始终 使用的;它不是一个你可以覆盖的默认值。因此,即使你在创建对象时为该字段设置了一个值,它也会被忽略。如果你想修改这个字段,可以设置以下内容来代替 auto_now_add=True
:
- 对于 DateField:
default=date.today
——来自 datetime.date.today() - 对于 DateTimeField:
default=timezone.now
——来自 django.utils.timezone.now()
该字段的默认表单部件是一个 DateInput。管理中增加了一个 JavaScript 日历,以及“今天”的快捷方式。包含一个额外的 invalid_date
错误信息键。
auto_now_add
、auto_now
和 default
选项是相互排斥的。这些选项的任何组合都会导致错误。
备注
目前,将 auto_now
或 auto_now_add
设置为 True
,将导致该字段设置为 editable=False
和 blank=True
。
备注
auto_now
和 auto_now_add
选项将始终使用创建或更新时 默认时区 的日期。如果你需要一些不同的东西,你可能需要考虑使用你自己的可调用的默认值,或者覆盖 save()
而不是使用 auto_now
或 auto_now_add
;或者使用 DateTimeField
而不是 DateField
,并决定如何在显示时间处理从日期时间到日期的转换。
警告
Always use DateField with a datetime.date
instance.
If you have a datetime.datetime
instance, it’s recommended to convert it to a datetime.date
first. If you don’t, DateField will localize the datetime.datetime
to the default timezone and convert it to a datetime.date
instance, removing its time component. This is true for both storage and comparison.
DateTimeField
class DateTimeField
(auto_now=False, auto_now_add=False, **options)[源代码]
一个日期和时间,在 Python 中用一个 datetime.datetime
实例表示。与 DateField 一样,使用相同的额外参数。
该字段的默认表单部件是一个单独的 DateTimeInput。管理中使用两个单独的 TextInput 部件,并使用 JavaScript 快捷方式。
警告
Always use DateTimeField with a datetime.datetime
instance.
If you have a datetime.date
instance, it’s recommended to convert it to a datetime.datetime
first. If you don’t, DateTimeField will use midnight in the default timezone for the time component. This is true for both storage and comparison. To compare the date portion of a DateTimeField with a datetime.date
instance, use the date lookup.
DecimalField
class DecimalField
(max_digits=None, decimal_places=None, **options)[源代码]
一个固定精度的十进制数,在 Python 中用一个 Decimal 实例来表示。它使用 DecimalValidator 验证输入。
有以下 必需 参数:
DecimalField.max_digits
数字中允许的最大位数。请注意,这个数字必须大于或等于 decimal_places
。
DecimalField.decimal_places
与数字一起存储的小数位数。
例如,要存储最高为 999.99
的数字,精度为小数点后 2 位,你可以使用:
models.DecimalField(..., max_digits=5, decimal_places=2)
并以 10 位小数的精度来存储最多约 10 亿的数字:
models.DecimalField(..., max_digits=19, decimal_places=10)
当 localize 为 False
时是 NumberInput 否则,该字段的默认表单部件是 TextInput。
备注
关于 FloatField 和 DecimalField 类之间差异的更多信息,请参见 FloatField vs. DecimalField。你还应该注意小数字段的 SQLite 限制。
DurationField
class DurationField
(**options)[源代码]
一个用于存储时间段的字段——在 Python 中用 timedelta 建模。当在 PostgreSQL 上使用时,使用的数据类型是 interval
,在 Oracle 上使用的数据类型是 INTERVAL DAY(9) TO SECOND(6)
。否则使用微秒的 bigint
。
备注
DurationField
的算术在大多数情况下是可行的。但在 PostgreSQL 以外的所有数据库中,将 DurationField
的值与 DateTimeField
实例上的算术进行比较,将无法达到预期的效果。
EmailField
class EmailField
(max_length=254, **options)[源代码]
一个 CharField,使用 EmailValidator 来检查该值是否为有效的电子邮件地址。
FileField
class FileField
(upload_to=’’, storage=None, max_length=100, **options)[源代码]
一个文件上传字段
备注
primary_key
参数不支持,如果使用,会引起错误。
具有以下可选参数:
FileField.upload_to
这个属性提供了一种设置上传目录和文件名的方式,可以有两种设置方式。在这两种情况下,值都会传递给 Storage.save() 方法。
如果你指定一个字符串值或一个 Path,它可能包含 strftime() 格式,它将被文件上传的日期/时间所代替(这样上传的文件就不会填满指定的目录)。例如:
class MyModel(models.Model):
# file will be uploaded to MEDIA_ROOT/uploads
upload = models.FileField(upload_to="uploads/")
# or...
# file will be saved to MEDIA_ROOT/uploads/2015/01/30
upload = models.FileField(upload_to="uploads/%Y/%m/%d/")
如果你使用的是默认的 FileSystemStorage,这个字符串的值将被附加到你的 MEDIA_ROOT 路径后面,形成本地文件系统中上传文件的存储位置。如果你使用的是不同的存储系统,请检查该存储系统的文档,看看它是如何处理 upload_to
的。
upload_to
也可以是一个可调用对象,如函数。这个函数将被调用以获得上传路径,包括文件名。这个可调用对象必须接受两个参数,并返回一个 Unix 风格的路径(带斜线),以便传给存储系统。这两个参数是:
参数 | 描述 |
---|---|
instance | 定义 在大多数情况下,这个对象还没有被保存到数据库,所以如果它使用默认的 |
filename | 最初给文件的文件名。在确定最终目标路径时,可能会考虑到,也可能不会考虑到。 |
例子:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return "user_{0}/{1}".format(instance.user.id, filename)
class MyModel(models.Model):
upload = models.FileField(upload_to=user_directory_path)
FileField.storage
一个存储对象,或是一个返回存储对象的可调用对象。它处理你的文件的存储和检索。参见 管理文件,了解如何提供这个对象。
该字段的默认表单部件是一个 ClearableFileInput。
在模型中使用 FileField 或 ImageField (见下文)需要几个步骤:
- 在你的配置文件中,你需要将 MEDIA_ROOT 定义为你希望 Django 存储上传文件的目录的完整路径。(为了提高性能,这些文件不会存储在数据库中。)将 MEDIA_URL 定义为该目录的基本公共 URL。确保这个目录是可以被网络服务器的用户账户写入的。
- 将 FileField 或 ImageField 添加到你的模型中,定义 upload_to 选项,指定 MEDIA_ROOT 的子目录,用于上传文件。
- 所有这些将被存储在你的数据库中的是一个文件的路径(相对于 MEDIA_ROOT )。你很可能要使用 Django 提供的方便的 url 属性。例如,如果你的 ImageField 叫做
mug_shot
,你可以在模板中使用{{ object.mug_shot.url }}
获取图片的绝对路径。
例如,你的 MEDIA_ROOT 设置为 '/home/media'
, upload_to 设置为 'photos/%Y/%m/%d'
。upload_to 中的 '%Y/%m/%d'
部分是 strftime() 格式化,'%Y'
是四位数的年,'%m'
是两位数的月,'%d'
是两位数的日。如果你在 2007 年 1 月 15 日上传了一个文件,它将被保存在 /home/media/photos/2007/01/15
目录下。
如果你想检索上传文件的盘上文件名,或者文件的大小,可以分别使用 name 和 size 属性;关于可用属性和方法的更多信息,请参见 File 类参考和 管理文件 主题指南。
备注
文件在数据库中作为保存模型的一部分,因此在模型被保存之前,不能依赖磁盘上使用的实际文件名。
上传的文件的相对 URL 可以通过 url
属性获得。内部调用底层 Storage 类的 store()
方法。
请注意,无论何时你处理上传的文件,你都应该密切注意你在哪里上传文件以及它们是什么类型的文件,以避免安全漏洞。 验证所有上传的文件 ,这样你就能确定文件是你认为的那样。例如,如果你盲目地让别人上传文件,而不进行验证,到你的网站服务器的文件根目录中,那么有人就可以上传 CGI 或 PHP 脚本,并通过访问你网站上的 URL 来执行该脚本。不要允许这样做。
另外要注意的是,即使是上传的 HTML 文件,由于可以被浏览器执行(虽然不能被服务器执行),也会造成相当于 XSS 或 CSRF 攻击的安全威胁。
FileField 实例在数据库中被创建为 varchar
列,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。
FileField
和 FieldFile
class FieldFile
[源代码]
当你访问一个模型上的 FileField 时,你会得到一个 FieldFile 的实例作为访问底层文件的代理。
FieldFile 的 API 与 File 的 API 相同,但有一个关键的区别。该类所封装的对象不一定是 Python 内置文件对象的封装 相反,它是 Storage.open()
方法结果的封装,该方法可能是 File 对象,也可能是自定义存储对 File API 的实现。
除了从 File 继承的 API,如 read()
和 write()
之外,FieldFile 还包括一些可以用来与底层文件交互的方法:
警告
该类的两个方法 save() 和 delete(),默认为将与相关 FieldFile
的模型对象保存在数据库中。
FieldFile.name
文件名,包括从关联的 Storage 的根部开始的相对路径 FileField。
FieldFile.path
[源代码]
一个只读属性,通过调用底层的 path() 方法,访问文件的本地文件系统路径。
FieldFile.size
[源代码]
底层 Storage.size() 方法的结果。
FieldFile.url
[源代码]
一个只读属性,通过调用底层 Storage 类的 Storage() 方法来访问文件的相对 URL。
FieldFile.open
(mode=’rb’)[源代码]
以指定的 mode
打开或重新打开与该实例相关的文件。与标准的 Python open()
方法不同,它不返回一个文件描述符。
因为在访问底层文件时,底层文件是隐式打开的,所以除了重置底层文件的指针或改变 mode
之外,可能没有必要调用这个方法。
FieldFile.close
()[源代码]
类似于标准的 Python file.close()
方法,关闭与该实例相关的文件。
FieldFile.save
(name, content, save=True)[源代码]
这个方法接收一个文件名和文件内容,并将它们传递给字段的存储类,然后将存储的文件与模型字段关联。如果你想手动将文件数据与模型上的 FileField 实例关联起来,那么 save()
方法用来持久化该文件数据。
取两个必要的参数。name
是文件的名称,content
是包含文件内容的对象。 可选的 save
参数控制在与该字段相关联的文件被更改后是否保存模型实例。默认为 True
。
注意 content
参数应该是 django.core.files.File 的实例,而不是 Python 内置的文件对象。你可以从现有的 Python 文件对象构造一个 File,像这样:
from django.core.files import File
# Open an existing file using Python's built-in open()
f = open("/path/to/hello.world")
myfile = File(f)
或者你可以从 Python 字符串中构建一个像这样的字符串:
from django.core.files.base import ContentFile
myfile = ContentFile("hello world")
更多信息,请参见 管理文件。
FieldFile.delete
(save=True)[源代码]
删除与此实例相关的文件,并清除字段的所有属性。注意:如果在调用 delete()
时,文件恰好被打开,本方法将关闭该文件。
可选的 save
参数控制在删除与该字段相关的文件后是否保存模型实例。默认值为 True
。
请注意,当一个模型被删除时,相关文件不会被删除。如果你需要清理遗留文件,你需要自己处理(例如,使用自定义管理命令,可以手动运行或通过例如 cron 定期运行)。
FilePathField
class FilePathField
(path=’’, match=None, recursive=False, allow_files=True, allow_folders=False, max_length=100, **options)[源代码]
一个 CharField,其选择仅限于文件系统中某个目录下的文件名。有一些特殊的参数,其中第一个参数是 必须的。
FilePathField.path
必须的。一个目录的绝对文件系统路径,这个 FilePathField 应从该目录中获取其选择。例如:"/home/images"
。
path
也可以是一个可调用对象,可以是在运行时动态设置路径的函数。例如:
import os
from django.conf import settings
from django.db import models
def images_path():
return os.path.join(settings.LOCAL_FILE_DIR, "images")
class MyModel(models.Model):
file = models.FilePathField(path=images_path)
FilePathField.match
可选。一个正则表达式,作为一个字符串, FilePathField 将用于过滤文件名。请注意,正则表达式将被应用于基本文件名,而不是完整的路径。例如:"foo.*.txt$"
,它将匹配名为 foo23.txt
的文件,但不匹配 bar.txt
或 foo23.png
。
FilePathField.recursive
可选。True
或 False
。默认为 False
。指定是否包含 path 的所有子目录。
FilePathField.allow_files
可选。 True
或 False
。 默认值是 True
。 指定是否应该包含指定位置的文件。 这个或 allow_folders 必须是 True
。
FilePathField.allow_folders
可选。 True
或 False
。 默认为 False
。 指定是否应该包含指定位置的文件夹。 这个或 allow_files 必须是 True
。
一个潜在的问题是 match 适用于基本文件名,而不是完整的路径。所以,这个例子:
FilePathField(path="/home/images", match="foo.*", recursive=True)
…将匹配 /home/images/foo.png
,但不匹配 /home/images/foo/bar.png
,因为 match 适用于基本文件名( foo.png
和 bar.png
)。
FilePathField 实例在数据库中作为 varchar
列创建,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。
FloatField
class FloatField
(**options)[源代码]
在 Python 中用一个 float
实例表示的浮点数。
当 localize 为 False
时是 NumberInput 否则,该字段的默认表单部件是 TextInput。
FloatField
vs. DecimalField
FloatField 类有时会与 DecimalField 类混淆。虽然它们都表示实数,但它们表示的方式不同。FloatField
内部使用 Python 的 float
类型,而 DecimalField
则使用 Python 的 Decimal
类型。关于两者之间的区别,请参见 Python 的 decimal 模块的文档。
GeneratedField
New in Django 5.0.
class GeneratedField
(expression, output_field, db_persist=None, **kwargs)[源代码]
这是一个根据模型中的其他字段始终计算的字段。该字段由数据库自身进行管理和更新。使用 GENERATED ALWAYS
SQL 语法。
有两种类型的生成列:存储的和虚拟的。存储的生成列在写入(插入或更新)时进行计算,并占用存储空间,就像是普通列一样。虚拟生成列不占用存储空间,在读取时进行计算。因此,虚拟生成列类似于视图,而存储的生成列类似于物化视图。
GeneratedField.expression
数据库使用的 Expression 在每次模型更改时自动设置字段值。
这些表达式应该是确定性的,并且只引用模型内部(同一数据库表)的字段。生成的字段不能引用其他生成的字段。数据库后端可以强加更多的限制。
GeneratedField.output_field
一个模型字段实例,用于定义字段的数据类型。
GeneratedField.db_persist
确定数据库列是否应该占用存储空间,就像是一个真实的列一样。如果为 False
,则该列将作为虚拟列,不会占用数据库存储空间。
PostgreSQL 仅支持持久列。Oracle 仅支持虚拟列。
刷新数据
由于数据库始终计算该值,在 save() 之后,必须重新加载对象以访问新值,例如,通过使用 refresh_from_db()。
数据库限制
Django 并不验证生成字段上的许多特定于数据库的限制,数据库可能会引发错误,例如,PostgreSQL 要求在生成列中引用的函数和操作符必须标记为 IMMUTABLE
。
你应该始终检查你的数据库是否支持 expression
。请查看 MariaDB、MySQL、Oracle、PostgreSQL 或 SQLite 文档。
GenericIPAddressField
class GenericIPAddressField
(protocol=’both’, unpack_ipv4=False, **options)[源代码]
IPv4 或 IPv6 地址,字符串格式(如 192.0.2.30
或 2a02:42fe::4
)。该字段的默认表单部件是一个 TextInput。
IPv6 地址规范化遵循 RFC 4291#section-2.2 第 2.2 节,包括使用该节第 3 段建议的 IPv4 格式,如 ::fffff:192.0.2.0
。例如,2001:0::0:01
将被标准化为 2001::1
,::fffff:0a0a:0a0a
将被标准化为 ::fffff:10.10.10.10
。所有字符都转换为小写。
GenericIPAddressField.protocol
将有效输入限制为指定协议。接受的值是 'both'
(默认)、'IPv4'
或 'IPv6'
。匹配是不分大小写的。
GenericIPAddressField.unpack_ipv4
解压 IPv4 映射地址,如 ::fffff:192.0.2.1
。如果启用该选项,该地址将被解压为 192.0.2.1
。默认为禁用。只有当 protocol
设置为 'both'
时才会启用。
如果允许空值,就必须允许 null 值,因为空值会被存储为 null。
ImageField
class ImageField
(upload_to=None, height_field=None, width_field=None, max_length=100, **options)[源代码]
继承 FileField 的所有属性和方法,但也验证上传的对象是有效的图像。
除了 FileField 的特殊属性外, ImageField 也有 height
和 width
属性。
为了方便对这些属性进行查询,ImageField 具有以下可选参数:
ImageField.height_field
Name of a model field which is auto-populated with the height of the image each time an image object is set.
ImageField.width_field
Name of a model field which is auto-populated with the width of the image each time an image object is set.
Requires the pillow library.
ImageField 实例在数据库中创建为 varchar
列,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。
该字段的默认表单部件是一个 ClearableFileInput。
IntegerField
class IntegerField
(**options)[源代码]
一个整数。从 -2147483648
到 2147483647
的值在 Django 支持的所有数据库中都是安全的。
它使用 MinValueValidator 和 MaxValueValidator 根据默认数据库支持的值来验证输入。
当 localize 为 False
时是 NumberInput 否则,该字段的默认表单部件是 TextInput。
JSONField
class JSONField
(encoder=None, decoder=None, **options)[源代码]
一个用于存储 JSON 编码数据的字段。在 Python 中,数据以其 Python 本地格式表示:字典、列表、字符串、数字、布尔值和 None
。
JSONField
在 MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite(启用了 JSON1 扩展)上都得到了支持。
JSONField.encoder
一个可选的 json.JSONEncoder 子类,用于序列化标准 JSON 序列化器不支持的数据类型(例如 datetime.datetime
或 UUID )。例如,你可以使用 DjangoJSONEncoder 类。
默认为 json.JSONEncoder
。
JSONField.decoder
一个可选的 json.JSONDecoder 子类,用于反序列化从数据库中获取的值。该值将采用自定义编码器选择的格式(通常是字符串)。你的反序列化可能需要考虑到你无法确定输入类型的事实。例如,你有可能返回一个 datetime
,实际上是一个字符串,而这个字符串恰好与 datetime
选择的格式相同。
默认为 json.JSONDecoder
。
要在数据库中查询 JSONField
,请看 查询 JSONField。
默认值
如果你给字段一个 default,确保它是一个可调用对象,例如 dict 类或一个每次返回新对象的函数。不正确地使用可变对象,比如 default={}
或 default=[]
,会创建一个在所有实例之间共享的可变默认值。
索引
Index 和 Field.db_index 都创建了一个 B 树索引,在查询 JSONField
的时候并不是特别有用。仅在 PostgreSQL 上,可以使用 GinIndex 比较适合。
PostgreSQL 用户
PostgreSQL 有两种基于 JSON 的原生数据类型: json
和 jsonb
。它们之间的主要区别在于它们的存储方式和查询方式。PostgreSQL 的 json
字段是作为 JSON 的原始字符串表示来存储的,当根据键来查询时,必须同时进行解码。jsonb
字段是基于 JSON 的实际结构存储的,它允许索引。这样做的代价是在写入 jsonb
字段时增加了一点成本。JSONField
使用 jsonb
。
Oracle 用户
Oracle 数据库不支持存储 JSON 标量值。只支持 JSON 对象和数组(在 Python 中使用 dict 和 list 表示)。
PositiveBigIntegerField
class PositiveBigIntegerField
(**options)[源代码]
就像一个 PositiveIntegerField,但只允许在某一特定点下的值(依赖于数据库)。0
到 9223372036854775807
的值在 Django 支持的所有数据库中都是安全的。
PositiveIntegerField
class PositiveIntegerField
(**options)[源代码]
就像 IntegerField 一样,但必须是正值或零( 0
)。从 0
到 2147483647
的值在 Django 支持的所有数据库中都是安全的。出于向后兼容的原因,接受 0
的值。
PositiveSmallIntegerField
class PositiveSmallIntegerField
(**options)[源代码]
就像一个 PositiveIntegerField,但只允许在某一特定(数据库依赖的)点下取值。0
到 32767
的值在 Django 支持的所有数据库中都是安全的。
SlugField
class SlugField
(max_length=50, **options)[源代码]
Slug 是一个报纸术语。slug 是一个简短的标签,只包含字母、数字、下划线或连字符。它们一般用于 URL 中。
像 CharField 一样,你可以指定 max_length (也请阅读那一节中关于数据库可移植性和 max_length 的说明)。如果没有指定 max_length,Django 将使用默认长度 50。
意味着将 Field.db_index 设置为 True
。
基于其他值的值自动预填充一个 SlugField 通常是很有用的。 你可以在管理中使用 prepopulated_fields 来自动完成。
它使用 validate_slug 或 validate_unicode_slug 进行验证。
SlugField.allow_unicode
如果是 True
,该字段除了接受 ASCII 字母外,还接受 Unicode 字母。默认值为 False
。
SmallAutoField
class SmallAutoField
(**options)[源代码]
就像一个 AutoField,但只允许值在一定(依赖于数据库)的限制下。1
到 32767
的值在 Django 支持的所有数据库中都是安全的。
SmallIntegerField
class SmallIntegerField
(**options)[源代码]
就像一个 IntegerField,但只允许在某一特定(依赖于数据库的)点下取值。从 -32768
到 32767
的值在 Django 支持的所有数据库中都是安全的。
TextField
class TextField
(**options)[源代码]
一个大的文本字段。该字段的默认表单部件是一个 Textarea。
如果你指定了 max_length
属性,它将反映在自动生成的表单字段的 Textarea 部件中。但是,它并没有在模型或数据库层面被强制执行。使用一个 CharField 来实现。
TextField.db_collation
可选的。该字段的数据库字符序名称。
备注
字符序名称是不标准化的。因此,这将无法在多个数据库后端之间进行移植。
Oracle
Oracle 不支持 TextField
的字符序。
TimeField
class TimeField
(auto_now=False, auto_now_add=False, **options)[源代码]
一个时间,在 Python 中用 datetime.time
实例表示。接受与 DateField 相同的自动填充选项。
该字段默认的表单部件t是一个 TimeInput。管理中添加了一些 JavaScript 快捷方式。
URLField
class URLField
(max_length=200, **options)[源代码]
URL 的 CharField,由 URLValidator 验证。
该字段的默认表单部件是一个 URLInput。
像所有的 CharField 子类一样, URLField 接受可选的 max_length 参数。如果你没有指定 max_length 参数,则使用默认的 200。
UUIDField
class UUIDField
(**options)[源代码]
用于存储通用唯一标识符的字段。使用 Python 的 UUID 类。在 PostgreSQL 和 MariaDB 10.7+ 上使用时,将存储在 uuid
数据类型中,否则存储在 char(32)
中。
通用唯一标识符是 primary_key 的 AutoField 的一个很好的替代方案。数据库不会为你生成 UUID,所以建议使用 default :
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# other fields
请注意,一个可调用对象(省略括号)被传递给 default
,而不是 UUID
的实例。
PostgreSQL 和 MariaDB 10.7+ 上的查找
在 PostgreSQL 上使用 iexact、contains、icontains、startswith、istartswith、endswith 或 iendswith 查找对于没有连字符的值不起作用,因为 PostgreSQL 和 MariaDB 10.7+ 将它们存储在带连字符的 uuid 数据类型中。
关系字段
Django 还定义了一组表示关系的字段。
ForeignKey
class ForeignKey
(to, on_delete, **options)[源代码]
一个多对一的关系。需要两个位置参数:模型相关的类和 on_delete 选项。
要创建一个递归关系——一个与自己有多对一关系的对象——使用 models.ForeignKey('self', on_delete=models.CASCADE)
。
如果你需要在一个尚未定义的模型上创建关系,你可以使用模型的名称,而不是模型对象本身:
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
"Manufacturer",
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
在 抽象模型 上以这种方式定义的关系在模型被子类化为具体模型时得到解析,与抽象模型的 app_label
不是相关的:
products/models.py
from django.db import models
class AbstractCar(models.Model):
manufacturer = models.ForeignKey("Manufacturer", on_delete=models.CASCADE)
class Meta:
abstract = True
production/models.py
from django.db import models
from products.models import AbstractCar
class Manufacturer(models.Model):
pass
class Car(AbstractCar):
pass
# Car.manufacturer will point to `production.Manufacturer` here.
要引用定义在另一个应用程序中的模型,你可以明确地用完整的应用程序标签指定一个模型。例如,如果上面的 Manufacturer
模型是在另一个叫做 production
的应用程序中定义的,你需要使用:
class Car(models.Model):
manufacturer = models.ForeignKey(
"production.Manufacturer",
on_delete=models.CASCADE,
)
这种被称为懒惰关系的引用,在解决两个应用程序之间的循环导入依赖关系时很有用。
在 ForeignKey
上会自动创建一个数据库索引。你可以通过设置 db_index 为 False
来禁用它。 如果你创建外键是为了保持一致性,而不是为了连接,或者你将创建一个替代性的索引,如部分索引或多列索引,你可能希望避免索引的开销。
数据库表现
在幕后,Django 在字段名后附加 "_id"
来创建数据库列名。在上面的例子中,Car
模型的数据库表将有一个 manufacturer_id
列。(你可以通过指定 db_column 来显式地改变这一点)然而,你的代码应该永远不需要处理数据库列名,除非你编写自定义 SQL。你将总是处理你的模型对象的字段名。
参数
ForeignKey 接受其他定义关系工作细节的参数。
ForeignKey.on_delete
当一个由 ForeignKey 引用的对象被删除时,Django 将模拟 on_delete 参数所指定的 SQL 约束的行为。例如,如果你有一个可空的 ForeignKey,并且你希望当被引用的对象被删除时,它被设置为空:
user = models.ForeignKey(
User,
models.SET_NULL,
blank=True,
null=True,
)
on_delete
不会在数据库中创建 SQL 约束。支持数据库级联选项 可能会在以后实施。
on_delete 的可能值可以在 django.db.models 中找到。
CASCADE
[源代码]级联删除。Django 模拟了 SQL 约束 ON DELETE CASCADE 的行为,也删除了包含 ForeignKey 的对象。
Model.delete() 在相关的模型上没有被调用,但是
pre_delete
和post_delete
信号是为所有被删除的对象发送的。PROTECT
[源代码]通过引发 ProtectedError,即 django.db.IntegrityError 的子类,防止删除被引用对象。
RESTRICT
[源代码]通过引发 RestrictedError ( django.db.IntegrityError 的一个子类)来防止删除被引用的对象。与 PROTECT 不同的是,如果被引用的对象也引用了一个在同一操作中被删除的不同对象,但通过 CASCADE 关系,则允许删除被引用的对象。
思考下下面这组模型:
``` class Artist(models.Model):
name = models.CharField(max_length=10)
class Album(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
class Song(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
album = models.ForeignKey(Album, on_delete=models.RESTRICT)
```
`Artist` 可以被删除,即使这意味着删除一个被 `Song` 引用的 `Album`,因为 `Song` 也通过级联关系引用了 `Artist` 本身。例如:
```
>>> artist_one = Artist.objects.create(name="artist one")
>>> artist_two = Artist.objects.create(name="artist two")
>>> album_one = Album.objects.create(artist=artist_one)
>>> album_two = Album.objects.create(artist=artist_two)
>>> song_one = Song.objects.create(artist=artist_one, album=album_one)
>>> song_two = Song.objects.create(artist=artist_one, album=album_two)
>>> album_one.delete()
# Raises RestrictedError.
>>> artist_two.delete()
# Raises RestrictedError.
>>> artist_one.delete()
(4, {'Song': 2, 'Album': 1, 'Artist': 1})
```
SET_NULL
[源代码]设置 ForeignKey 为空;只有当 null 为
True
时,才有可能。SET_DEFAULT
[源代码]将 ForeignKey 设置为默认值,必须为 ForeignKey 设置一个默认值。
SET
()[源代码]将 ForeignKey 设置为传递给 SET() 的值,或者如果传递的是可调用对象,则调用它的结果。在大多数情况下,传递可调用对象将是必要的,以避免在导入
models.py
时执行查询:``` from django.conf import settings from django.contrib.auth import get_user_model from django.db import models
def get_sentinel_user():
return get_user_model().objects.get_or_create(username="deleted")[0]
class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
```
DO_NOTHING
[源代码]不采取任何行动。如果你的数据库后端强制执行引用完整性,这将导致一个 IntegrityError 除非你手动添加一个 SQL
ON DELETE
约束条件到数据库字段。
ForeignKey.limit_choices_to
当使用 ModelForm
或管理中渲染该字段时,设置该字段的可用选择限制(默认情况下,查询集中的所有对象都可以选择)。可以使用字典、 Q 对象,或者返回字典或 Q 对象的可调用对象。
例子:
staff_member = models.ForeignKey(
User,
on_delete=models.CASCADE,
limit_choices_to={"is_staff": True},
)
导致 ModelForm
上的对应字段只列出有 is_staff=True
的 Users
。这在 Django 管理中可能会有帮助。
例如,当与 Python datetime
模块一起使用时,可调用对象可以很有帮助,通过日期范围限制选择。例如:
def limit_pub_date_choices():
return {"pub_date__lte": datetime.date.today()}
limit_choices_to = limit_pub_date_choices
如果 limit_choices_to
是或返回一个 Q对象,这对 复杂的查询 很有用,那么只有当该字段没有在 ModelAdmin
中的 raw_id_fields 中列出时,它才会对管理中可用的选择产生影响。
备注
如果 limit_choices_to
使用了可调用对象,那么每次实例化一个新的表单时,都会调用该功能。它也可以在模型被验证时被调用,例如由管理命令或管理中调用。管理中构建查询集来多次验证各种边缘情况下的表单输入,所以你的可调用对象有可能会被多次调用。
ForeignKey.related_name
用于从相关对象到这个对象的关系的名称。这也是 related_query_name 的默认值(用于从目标模型反向过滤名称的名称)。请参阅 关联对象文档 以获得完整的解释和示例。请注意,当你在 抽象模型 是可用的。
如果你不希望 Django 创建一个反向关系,可以将 related_name
设置为 '+'
或者以 '+'
结束。例如,这将确保 User
模型不会与这个模型有反向关系:
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="+",
)
ForeignKey.related_query_name
目标模型中反向过滤器的名称。如果设置了,它默认为 related_name 或 default_related_name 的值,否则默认为模型的名称:
# Declare the ForeignKey with related_query_name
class Tag(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name="tags",
related_query_name="tag",
)
name = models.CharField(max_length=255)
# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")
和 related_name 一样,related_query_name
通过 一些特殊的语法 支持应用标签和类的插值。
ForeignKey.to_field
关联对象的字段。默认情况下,Django 使用相关对象的主键。如果你引用了一个不同的字段,这个字段必须有 unique=True
。
ForeignKey.db_constraint
控制是否应该在数据库中为这个外键创建一个约束。默认值是 True
,这几乎是你想要的;将其设置为 False
对数据完整性非常不利。话虽如此,下面是一些你可能想要这样做的情况:
- 你有无效的冗余数据
- 你正在共享你的数据库
如果将此设置为 False
,访问一个不存在的相关对象将引发 DoesNotExist
异常。
ForeignKey.swappable
控制迁移框架的反应,如果这个 ForeignKey 指向一个可交换的模型。如果它是 True
——默认值-——那么如果 ForeignKey 指向的模型与 settings.AUTH_USER_MODEL
的当前值相匹配(或其他可互换模型配置),则关系将在迁移中使用对配置的引用而不是直接对模型进行存储。
只有当你确定你的模型应该总是指向换入的模型时,你才想把它覆盖为 False
,例如,如果它是一个专门为你的自定义用户模型设计的配置文件模型。
将它设置为 False
并不意味着你可以引用一个可交换的模型,即使它被交换了—— False
意味着用这个外键进行的迁移将始终引用你指定的确切模型(所以如果用户试图用你不支持的 User 模型运行,它将失败,例如)。
如果不确定,就保留它在默认为 True
的状态。
ManyToManyField
class ManyToManyField
(to, **options)[源代码]
一个多对多的关系。需要一个位置参数:模型相关的类,它的工作原理与 ForeignKey 完全相同,包括 递归 和 惰性 关系。
可以通过字段的 RelatedManager
来添加、删除或创建相关对象。
数据库表现
在幕后,Django 创建了一个中间连接表来表示多对多的关系。默认情况下,这个表名是使用多对多字段的名称和包含它的模型的表名生成的。由于有些数据库不支持超过一定长度的表名,这些表名将被自动截断,并使用唯一性哈希,例如 author_books_9cdf
。你可以使用 db_table 选项手动提供连接表的名称。
参数
ManyToManyField 接受一组额外的参数——都是可选的——控制关系如何运作。
ManyToManyField.related_name
与 ForeignKey.related_name 相同。
ManyToManyField.related_query_name
与 ForeignKey.related_query_name 相同。
ManyToManyField.limit_choices_to
与 ForeignKey.limit_choices_to 相同。
ManyToManyField.symmetrical
仅在自身上定义多对多字段关系时。考虑以下模型
from django.db import models
class Person(models.Model):
friends = models.ManyToManyField("self")
当 Django 处理这个模型时,它识别出它本身有一个 ManyToManyField,因此,它没有给 Person
类添加 person_set
属性。相反, ManyToManyField 被认为是对称的,也就是说,如果我是你的朋友,那么你就是我的朋友。
如果你不想让 self
的多对多关系对称,可以将 symmetrical 设置为 False
。这样会强制 Django 添加反向关系的描述符,允许 ManyToManyField 关系是非对称的。
ManyToManyField.through
Django 会自动生成一个表来管理多对多关系。但是,如果你想手动指定中间表,你可以使用 through 选项来指定代表你要使用的中间表的 Django 模型。
这个选项最常见的用法是当你想把 额外的数据与多对多关系 联系起来。
备注
如果你不想让同一个实例之间有多个关联,可以添加一个 UniqueConstraint,包括 from 和 to 字段。Django 自动生成的多对多表就包含了这样的约束。
备注
使用代理模型的递归关系不能确定反向访问器的名称,因为它们会是相同的。你需要设置一个 related_name 到其中至少一个。如果你希望 Django 不创建反向关系,请将 related_name
设置为 '+'
。
如果你没有指定一个显式的 through
模型,你仍然可以使用一个隐式的 through
模型类来直接访问为保持关联而创建的表。它有三个字段来链接模型。
如果源模型和目标模型不同,则会生成以下字段:
id
:关系的主键。<containing_model>_id
:声明ManyToManyField
的模型的id
。<other_model>_id
:ManyToManyField
指向的模型的id
。
如果 ManyToManyField
指向的来源和目标是相同的模型, 下面的字段会生成:
id
:关系的主键。from_<model>_id
:指向模型的实例(即源实例)的id
。to_<model>_id
:关系所指向的实例(即目标模型实例)的id
。
这个类可以像普通模型一样,用于查询给定模型实例的关联记录:
Model.m2mfield.through.objects.all()
ManyToManyField.through_fields
只有当指定了一个自定义的中间模型时才会使用,Django 通常会决定使用中介模型的哪些字段来自动建立多对多的关系。然而,考虑以下模型:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through="Membership",
through_fields=("group", "person"),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
Membership
对 Person
有 两个 外键( person
和 inviter
),这就使得两者的关系变得模糊不清,Django 无法知道应该使用哪个外键。在这种情况下,你必须使用 through_fields
明确指定 Django 应该使用哪个外键,就像上面的例子一样。
through_fields
接受一个二元元组 ('field1', 'field2')
,其中 field1
是定义在 ManyToManyField 上的模型(本例中为 group
)的外键名称,field2
是目标模型(本例中为 person
)的外键名称。
当你在中间模型上有一个以上的外键到任何一个(甚至两个)参与多对多关系的模型时,你 必须 指定 through_fields
。这也适用于 递归关系,当使用一个中间模型,并且该模型有两个以上的外键,或者你想明确指定 Django 应该使用哪两个外键。
ManyToManyField.db_table
要创建的用于存储多对多数据的表的名称。如果没有提供这个表名,Django 将根据以下表名创建一个默认表名:定义关系的模型表和字段本身的名称。
ManyToManyField.db_constraint
控制是否应该在数据库中为中间表的外键创建约束。默认值是 True
,这几乎是你想要的;将其设置为 False
对数据完整性非常不利。话说回来,下面是一些你可能想要这样做的情况:
- 你有无效的冗余数据
- 你正在共享你的数据库
同时传递 db_constraint
和 through
会引发错误。
ManyToManyField.swappable
控制迁移框架的反应,如果这个 ManyToManyField 指向一个可交换的模型。如果它是 True
——默认值——那么如果 ManyToManyField 指向的模型与 settings.AUTH_USER_MODEL
的当前值相匹配(或其他可交换模型配置),关系将被存储在迁移中,使用对配置的引用,而不是直接对模型的引用。
只有当你确定你的模型应该总是指向换入的模型时,你才想把它覆盖为 False
,例如,如果它是一个专门为你的自定义用户模型设计的配置文件模型。
如果不确定,就保留它在默认为 True
的状态。
ManyToManyField 不支持 validators。
null 没有效果,因为没有办法在数据库层面要求建立关系。
OneToOneField
class OneToOneField
(to, on_delete, parent_link=False, **options)[源代码]
一对一的关系。概念上,这类似于 ForeignKey 与 unique=True,但关系的“反向”将直接返回一个单一对象。
最有用的是作为某种方式“扩展”另一个模型的主键;多表继承 是通过添加一个从子模型到父模型的隐式一对一关系来实现的,例如:
需要一个位置参数:模型将与之相关的类。这与 ForeignKey 的工作原理完全相同,包括关于 递归 和 惰性 关系的所有选项。
如果没有为 OneToOneField
指定 related_name 参数,Django 将使用当前模型的小写名作为默认值。
举例如下:
from django.conf import settings
from django.db import models
class MySpecialUser(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
supervisor = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="supervisor_of",
)
你的最终 User
模型将具有以下属性:
>>> user = User.objects.get(pk=1)
>>> hasattr(user, "myspecialuser")
True
>>> hasattr(user, "supervisor_of")
True
在访问反向关系时,如果相关表中的条目不存在,将引发 RelatedObjectDoesNotExist
异常。这是目标模型的 Model.DoesNotExist 异常的子类,可以作为反向访问器的属性访问。例如,如果用户没有由 MySpecialUser
指定的主管:
try:
user.supervisor_of
except User.supervisor_of.RelatedObjectDoesNotExist:
pass
此外,OneToOneField
接受 ForeignKey 接受的所有额外参数,外加一个额外参数:
OneToOneField.parent_link
当 True
并用于从另一个 concrete model 继承的模型中时,表示该字段应被用作回到父类的链接,而不是通常通过子类隐含创建的额外 OneToOneField
。
参见 一对一关系,了解 OneToOneField
的使用实例。
字段 API 参考
class Field
[源代码]
Field
是一个抽象的类,表示一个数据库表的列。Django 使用字段来创建数据库表( db_type() ),将 Python 类型映射到数据库( get_prep_value() ),反之亦然( from_db_value() )。
因此,一个字段在不同的 Django API 中是一个基本的部分,特别是 models 和 querysets。
在模型中,字段被实例化为一个类属性,并代表一个特定的表列,见 模型。它的属性有 null 和 unique,以及 Django 用来将字段值映射到数据库特定值的方法。
Field
是 RegisterLookupMixin 的子类,因此 Transform 和 Lookup 都可以在它上面注册,以便在 QuerySet
中使用(例如: field_name__exact="foo"
)。所有 内置查找 都是默认注册的。
所有 Django 的内置字段,如 CharField,都是 Field
的特殊实现。如果你需要一个自定义的字段,你可以对任何一个内置字段进行子类化,或者从头开始写一个 Field
。无论哪种情况,请参见 编写自定义模型字段。
description
字段的详细描述,例如: django.contrib.admindocs 应用程序。
描述的形式可以是:
description = _("String (up to %(max_length)s)")
其中的参数是从字段的
__dict__
中插入的。descriptor_class
一个实现 描述符协议 的类,它被实例化并分配给模型实例属性。构造函数必须接受一个参数,即
Field
实例。覆盖该类属性可以自定义获取和设置行为。
为了将一个 Field
映射到数据库的特定类型,Django 提供了一些方法:
get_internal_type
()[源代码]返回一个字符串,用于命名这个字段,以满足后台的特定目的。默认情况下,它返回的是类名。
参见 仿造内置字段类型 在自定义字段中的用法。
db_type
(connection)[源代码]根据
connection
, 返回 Field 的数据库列数据类型。参见 自定义数据库类型 在自定义字段中的用法。
rel_db_type
(connection)[源代码]返回指向 Field 的
ForeignKey
和OneToOneField
等字段的数据库列数据类型,并考虑connection
。参见 自定义数据库类型 在自定义字段中的用法。
Django 主要有三种情况需要与数据库后台和字段进行交互。
- 当它查询数据库时(Python 值 -> 数据库后台值)
- 当它从数据库中加载数据时(数据库后台值 -> Python 值)
- 当它保存到数据库时(Python 值 -> 数据库后端值)
查询时,使用 get_db_prep_value() 和 get_prep_value()。
get_prep_value
(value)[源代码]value
是模型属性的当前值,该方法应以准备作为查询参数的格式返回数据。见 将 Python 转为查询值 的用法。
get_db_prep_value
(value, connection, prepared=False)[源代码]将
value
转换为后台特定的值,默认情况下,如果prepared=True
,它将返回value
。而如果是False
,它将返回 get_prep_value() 。使用方法参见 将查询值转为数据库值。
加载数据时,使用 from_db_value()。
from_db_value
(value, expression, connection)将数据库返回的值转换为 Python 对象。与 get_prep_value() 相反。
这个方法不用于大多数内置字段,因为数据库后端已经返回了正确的 Python 类型,或者后端自己进行了转换。
expression
与self
相同。使用方法参见 将值转为 Python 对象。
备注
由于性能原因,
from_db_value
并没有在不需要它的字段上实现 no-op(所有 Django 字段)。因此,你不能在定义中调用super
。
保存时,使用 pre_save() 和 get_db_prep_save() :
get_db_prep_save
(value, connection)[源代码]与 get_db_prep_value() 相同,但当字段值必须 保存 到数据库中时,会被调用。默认情况下返回 get_db_prep_value()。
pre_save
(model_instance, add)[源代码]在 get_db_prep_save() 之前调用的方法,在保存前准备好值(例如 DateField.auto_now )。
model_instance
是该字段所属的实例,add
是该实例是否第一次被保存到数据库中。它应该从
model_instance
中返回这个字段的适当属性的值。属性名在self.attname
中(这是由 Field 设置的)。使用方法参见 在保存前预处理数值。
字段经常以不同的类型接收它们的值,要么来自序列化,要么来自表单。
to_python
(value)[源代码]将值转换为正确的 Python 对象。它的作用与 value_to_string() 相反,并且在 clean() 中也被调用。
使用方法参见 将值转为 Python 对象。
除了保存到数据库,字段还需要知道如何将其值序列化。
value_from_object
(obj)[源代码]返回给定模型实例的字段值。
这个方法经常被 value_to_string() 使用。
value_to_string
(obj)[源代码]将
obj
转换为字符串。用于序列化字段的值。使用方法参见 为序列化转换字段数据。
当使用 model forms 时,Field
需要知道它应该由哪个表单字段来表示。
formfield
(form_class=None, choices_form_class=None, **kwargs)[源代码]返回该字段默认的 django.forms.Field 给 ModelForm。
默认情况下,如果
form_class
和choices_form_class
都是None
,则使用 CharField。如果字段有chips
,且choices_form_class
没有指定,则使用 TypedChoiceField。使用方法参见 为模型字段指定表单字段。
deconstruct
()[源代码]返回一个包含足够信息的四元元组来重新创建字段。
- 模型上的字段名称。
- 字段的导入路径(例如
"django.db.models.IntegerField"
)。这应该是最可移植版本,所以不那么具体可能更好。 - 一个位置参数的列表。
- 一个关键字参数的字典。
这个方法必须添加到 1.7 之前的字段中,才能使用 迁移 迁移其数据。
注册和获取查询
Field
实现了 查找注册 API。该 API 可以用于自定义哪些查找适用于字段类及其实例,以及如何从字段中获取查找。
字段属性参考
每个 Field
实例都包含几个属性,允许对其行为进行内省。当你需要编写依赖于字段功能的代码时,可以使用这些属性来代替 isinstance
检查。这些属性可以与 Model._meta API 一起使用,以缩小对特定字段类型的搜索范围。自定义模型字段应该实现这些标志。
字段的属性
Field.auto_created
表示是否自动创建字段的布尔标志,如模型继承使用的 OneToOneField
。
Field.concrete
布尔值标志,表示该字段是否有与之相关的数据库列。
Field.hidden
布尔标志,指示字段是否隐藏,并且默认情况下不应由 Options.get_fields() 返回。一个示例是对于一个以 '+'
开头的 related_name
的 ForeignKey 的反向字段。
Field.is_relation
布尔值标志,表示一个字段是否包含对一个或多个其他模型的功能引用(如 ForeignKey
、ManyToManyField
、OneToOneField
等)。
Field.model
返回定义字段的模型。如果一个字段定义在一个模型的超类上,model
将指的是超类,而不是实例的类。
有关系的字段的属性
这些属性用于查询关系的基数和其他细节。这些属性在所有字段上都存在;但是,如果字段是关系类型( Field.is_relation=True ),它们只有布尔值(而不是 None
)。
Field.many_to_many
如果字段有多对多关系,则为 True
,否则为 False
。Django 中唯一一个是 True
的字段是 ManyToManyField
。
Field.many_to_one
如果字段有多对一关系,如 ForeignKey
,则为 True
;否则为 False
。
Field.one_to_many
如果该字段有一对多关系,如 GenericRelation
或 ForeignKey
的反向关系,则为 True
;否则为 False
。
Field.one_to_one
如果字段有一对一的关系,如 OneToOneField
,则为 True
;否则为 False
。
Field.related_model
指向该字段所涉及的模型。例如,ForeignKey(Author, on_delete=models.CASCADE)
中的 Author
。GenericForeignKey
的 related_model
总是 None
。