模型字段参考

本文档包含 Field 类的所有 API 参考,包括 字段选项字段类型

参见

若内置字段未满足需求,你可以试试 django-localflavor文档 ),它包含了针对各别国家和文件的代码。

当然,你也可以简单的 编写自定义模型字段

注解

从技术上讲,这些方法都被定义在 django.db.models.fields,但为了方便,它们被导入到 django.db.models;标准的惯例是使用 from django.db import models 并利用 models.<Foo>Field

字段选项

以下参数对所以字段类型均有效,且是可选的。

null

Field.null

如果是 True, Django 将在数据库中存储空值为 NULL。默认为 False

避免在基于字符串的字段上使用 null,如 CharFieldTextField。如果一个基于字符串的字段有 null=True,这意味着它有两种可能的“无数据”值。NULL,和空字符串。在大多数情况下,“无数据”有两种可能的值是多余的,Django 的惯例是使用空字符串,而不是 NULL。一个例外是当一个 CharField 同时设置了 unique=Trueblank=True。在这种情况下,null=True 是需要的,以避免在保存具有空白值的多个对象时违反唯一约束。

无论是基于字符串的字段还是非字符串的字段,如果希望在表单中允许空值,还需要设置 blank=True,因为 null 参数只影响数据库的存储(参见 blank )。

注解

当使用 Oracle 数据库后端时,不管这个属性是什么,都会存储 NULL 值来表示空字符串。

blank

Field.blank

如果是 True ,该字段允许为空。默认为 False

注意,这与 null 不同。 null 纯属数据库相关,而 blank 则与验证相关。如果一个字段有 blank=True,表单验证将允许输入一个空值。如果一个字段有 blank=False,则该字段为必填字段。

choices

Field.choices

一个 sequence 本身由正好两个项目的迭代项组成(例如 [(A,B),(A,B)...] ),作为该字段的选择。如果给定了选择,它们会被 模型验证 强制执行,默认的表单部件将是一个带有这些选择的选择框,而不是标准的文本字段。

每个元组中的第一个元素是要在模型上设置的实际值,第二个元素是人可读的名称。例如:

YEAR_IN_SCHOOL_CHOICES = [
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
]

一般来说,最好在模型类内部定义选择,并为每个值定义一个合适的名称的常量:

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' 选项)。

对于每一个设置了 choice 的模型字段,Django 会添加一个方法来检索字段当前值的可读名称。参见数据库 API 文档中的 get_FOO_display()

请注意,选择可以是任何序列对象——不一定是列表或元组。这让你可以动态地构造选择。但是如果你发现自己把 chips 魔改成动态的,你可能最好使用一个合适的的带有 ForeignKey 的数据库表。 chips 是用于静态数据的,如果有的话,不应该有太大的变化。

注解

每当 choices 的顺序变动时将会创建新的迁移。

除非 blank=Falsedefault 一起设置在字段上,否则包含 "---------" 的标签将与选择框一起呈现。要覆盖这种行为,可以在 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.choices,
        default=YearInSchool.FRESHMAN,
    )

    def is_upperclass(self):
        return self.year_in_school in {
            self.YearInSchool.JUNIOR,
            self.YearInSchool.SENIOR,
        }

这些工作类似于 Python 标准库中的 enum,但是做了一些修改。

  • 枚举成员值是构造具体数据类型时要使用的参数元组。Django 支持在这个元组的末尾添加一个额外作为人可读的名称的字符串值 labellabel 可以是一个惰性的可翻译字符串。因此,在大多数情况下,成员值将是一个 (value, label) 二元组。请看下面使用更复杂的数据类型 子类化选择的例子。如果没有提供元组,或者最后一项不是(惰性)字符串,label 是从成员名 自动生成
  • 在值上添加 .label 属性,以返回人类可读的名称。
  • 在枚举类中添加了一些自定义属性—— .choice.labs.values.names ——以便于访问枚举的这些单独部分的列表。在字段定义中,使用 .choice 作为一个合适的值传递给 choice
  • 强制使用 enum.unique() 是为了确保不能多次定义值。在选择一个字段时,不太可能会出现这种情况。

请注意,使用 YearInSchool.SENIORYearInSchool['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.choices)

也可以使用 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')]

如果你需要支持 intstr 以外的具体数据类型,你可以将 Choices 和所需的具体数据类型子类化,例如 dateDateField 一起使用:

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)')
    

db_column

Field.db_column

这个字段要使用的数据库列名。如果没有给出列名,Django 将使用字段名。

如果你的数据库列名是 SQL 的保留字,或者包含了 Python 变量名中不允许的字符——特别是连字符——那也没关系。Django 会在幕后引用列名和表名。

db_index

Field.db_index

如果是 True,将为该字段创建数据库索引。

db_tablespace

Field.db_tablespace

如果这个字段有索引,那么要为这个字段的索引使用的 数据库表空间 的名称。默认是项目的 DEFAULT_INDEX_TABLESPACE 设置(如果有设置),或者是模型的 db_tablespace (如果有)。如果后端不支持索引的表空间,则忽略此选项。

default

Field.default

该字段的默认值。可以是一个值或者是个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。

默认值不能是一个可更改的对象(模型实例、listset 等),因为对该对象同一实例的引用将被用作所有新模型实例的缺省值。相反,将所需的默认值包裹在一个可调用对象中。例如,如果你想为 JSONField 指定一个默认的 dict,使用一个函数:

def contact_default():
    return {"email": "to1@example.com"}

contact_info = JSONField("ContactInfo", default=contact_default)

lambda 不能用于 default 等字段选项,因为它们不能被 迁移序列化。其他注意事项见该文档。

对于像 ForeignKey 这样映射到模型实例的字段,默认应该是它们引用的字段的值(默认是 pk 除非 to_field 被设置了),而不是模型实例。

当创建新的模型实例且没有为该字段提供值时,使用默认值。当字段是主键时,当字段设置为``None`` 时,也使用默认值。

editable

Field.editable

如果是 False,该字段将不会在管理或任何其他 ModelForm 中显示。在 模型验证 中也会跳过。默认为 True

error_messages

Field.error_messages

error_messages 参数可以让你覆盖该字段引发的默认消息。传入一个与你想覆盖的错误信息相匹配的键值的字典。

错误信息键包括 nullblankinvalidinvalid_choiceuniqueunique_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=Falseunique=True。一个对象只允许有一个主键。

主键字段是只读的。如果您改变了现有对象的主键值,然后将其保存,则会在旧对象旁边创建一个新对象。

Changed in Django 3.2:

在旧版本中,自动创建的主键字段总是 AutoField

unique

Field.unique

如果设置为 True,这个字段必须在整个表中保持值唯一。

这是在数据库级别和模型验证中强制执行的。如果你试图保存一个在 unique 字段中存在重复值的模型,模型的 save() 方法将引发 django.db.IntegrityError

除了 ManyToManyFieldOneToOneField 之外,该选项对所有字段类型有效。

请注意,当 uniqueTrue 时,你不需要指定 db_index,因为 unique 意味着创建一个索引。

unique_for_date

Field.unique_for_date

将其设置为 DateFieldDateTimeField 的名称,要求该字段的日期字段值是唯一的。

例如,如果你的字段 titleunique_for_date="pub_date",那么 Django 就不允许输入两条相同 titlepub_date 的记录。

请注意,如果将其设置为指向 DateTimeField,则只考虑该字段的日期部分。此外,当 USE_TZTrue 时,检查将在对象保存时的 当前时区 中进行。

这在模型验证过程中由 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_fordateunique_formonth

verbose_name

Field.verbose_name

字段的一个人类可读名称,如果没有给定详细名称,Django 会使用字段的属性名自动创建,并将下划线转换为空格。参见 详细字段名

validators

Field.validators

要为该字段运行的验证器列表。更多信息请参见 验证器文档

注册和获取查询

Field 实现了 查询注册 API。该 API 可用于自定义字段类的哪些查询是可用的,以及如何从字段中获取查询。

字段类型

AutoField

class AutoField(**options)

一个 IntegerField,根据可用的 ID 自动递增。你通常不需要直接使用它;如果你没有指定,主键字段会自动添加到你的模型中。参见 自动设置主键

BigAutoField

class BigAutoField(**options)

一个 64 位整数,与 AutoField 很相似,但保证适合 19223372036854775807 的数字。

BigIntegerField

class BigIntegerField(**options)

一个 64 位的整数,和 IntegerField 很像,只是它保证适合从 -92233720368547758089223372036854775807 的数字。该字段的默认表单部件是一个 NumberInput

BinaryField

class BinaryField(max_length=None, **options)

一个用于存储原始二进制数据的字段。可以指定为 bytesbytearraymemoryview

默认情况下,BinaryFieldediditable` 设置为 False,在这种情况下,它不能被包含在 ModelForm 中。

BinaryField 有一个额外的可选参数:

BinaryField.max_length

The maximum length (in bytes) of the field. The maximum length is enforced in Django's validation using 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

注解

如果你编写的应用程序必须可移植到多个数据库后端,你应该意识到,有些后端对 max_length 有限制。详情请参考 数据库后端注释

CharField.db_collation
New in Django 3.2.

可选的。该字段的数据库字符序名称。

注解

字符序名称是不标准化的。因此,这将无法在多个数据库后端之间进行移植。

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

该字段的默认表单部件是一个 DateInput。管理中增加了一个 JavaScript 日历,以及“今天”的快捷方式。包含一个额外的 invalid_date 错误信息键。

auto_now_addauto_nowdefault 选项是相互排斥的。这些选项的任何组合都会导致错误。

注解

目前,将 auto_nowauto_now_add 设置为 True,将导致该字段设置为 editable=Falseblank=True

注解

auto_nowauto_now_add 选项将始终使用创建或更新时 默认时区 的日期。如果你需要一些不同的东西,你可能需要考虑使用你自己的可调用的默认值,或者覆盖 save() 而不是使用 auto_nowauto_now_add ;或者使用 DateTimeField 而不是 DateField,并决定如何在显示时间处理从日期时间到日期的转换。

DateTimeField

class DateTimeField(auto_now=False, auto_now_add=False, **options)

一个日期和时间,在 Python 中用一个 datetime.datetime 实例表示。与 DateField 一样,使用相同的额外参数。

该字段的默认表单部件是一个单独的 DateTimeInput。管理中使用两个单独的 TextInput 部件,并使用 JavaScript 快捷方式。

DecimalField

class DecimalField(max_digits=None, decimal_places=None, **options)

一个固定精度的十进制数,在 Python 中用一个 Decimal 实例来表示。它使用 DecimalValidator 验证输入。

有两个 必要的 参数:

DecimalField.max_digits

数字中允许的最大位数。请注意,这个数字必须大于或等于 decimal_places

DecimalField.decimal_places

与数字一起存储的小数位数。

例如,如果要存储精度为小数点后两位的 999 的数字,你可以使用:

models.DecimalField(..., max_digits=5, decimal_places=2)

并以 10 位小数的精度来存储最多约 10 亿的数字:

models.DecimalField(..., max_digits=19, decimal_places=10)

localizeFalse 时是 NumberInput 否则,该字段的默认表单部件是 TextInput

注解

关于 FloatFieldDecimalField 类之间差异的更多信息,请参见 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=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

定义 FileField 的模型实例。更具体地说,这是附加当前文件的特定实例。

在大多数情况下,这个对象还没有被保存到数据库,所以如果它使用默认的 AutoField它的主键字段可能还没有一个值

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

一个存储对象,或是一个返回存储对象的可调用对象。它处理你的文件的存储和检索。参见 管理文件,了解如何提供这个对象。

Changed in Django 3.1:

增加了提供可调用对象的能力。

该字段的默认表单部件是一个 ClearableFileInput

在模型中使用 FileFieldImageField (见下文)需要几个步骤:

  1. 在你的配置文件中,你需要定义 MEDIA_ROOT 作为你希望 Django 存储上传文件的目录的完整路径。(为了保证性能,这些文件不存储在数据库中。)定义 MEDIA_URL 作为该目录的基本公共 URL。确保这个目录是 Web 服务器的用户账号可以写的。
  2. FileFieldImageField 添加到你的模型中,定义 upload_to 选项,指定 MEDIA_ROOT 的子目录,用于上传文件。
  3. 所有这些将被存储在你的数据库中的是一个文件的路径(相对于 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 目录下。

如果你想检索上传文件的盘上文件名,或者文件的大小,可以分别使用 namesize 属性;关于可用属性和方法的更多信息,请参见 File 类参考和 管理文件 主题指南。

注解

文件在数据库中作为保存模型的一部分,因此在模型被保存之前,不能依赖磁盘上使用的实际文件名。

上传的文件的相对 URL 可以通过 url 属性获得。内部调用底层 Storage 类的 store() 方法。

需要注意的是,无论何时处理上传的文件,你都应该密切关注你上传的文件在哪里,是什么类型的文件,以避免安全漏洞。对所有上传的文件进行验证,这样你才能确定文件是你认为的那样。例如,如果你盲目地让别人上传文件,不经过验证,就上传文件到你的 Web 服务器的文档根目录下,那么有人就可以上传一个 CGI 或 PHP 脚本,并通过访问它的 URL 在你的网站上执行该脚本。不要允许这种情况发生。

另外要注意的是,即使是上传的 HTML 文件,由于可以被浏览器执行(虽然不能被服务器执行),也会造成相当于 XSS 或 CSRF 攻击的安全威胁。

FileField 实例在数据库中被创建为 varchar 列,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。

FileFieldFieldFile

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.txtfoo23.png

FilePathField.recursive

可选。TrueFalse。默认为 False。指定是否包含 path 的所有子目录。

FilePathField.allow_files

可选。 TrueFalse。 默认值是 True。 指定是否应该包含指定位置的文件。 这个或 allow_folders 必须是 True

FilePathField.allow_folders

可选。 TrueFalse。 默认为 False。 指定是否应该包含指定位置的文件夹。 这个或 allow_files 必须是 True

一个潜在的问题是 match 适用于基本文件名,而不是完整的路径。所以,这个例子:

FilePathField(path="/home/images", match="foo.*", recursive=True)

...将匹配 /home/images/foo.png,但不匹配 /home/images/foo/bar.png,因为 match 适用于基本文件名( foo.pngbar.png )。

FilePathField 实例在数据库中作为 varchar 列创建,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。

FloatField

class FloatField(**options)

在 Python 中用一个 float 实例表示的浮点数。

localizeFalse 时是 NumberInput 否则,该字段的默认表单部件是 TextInput

FloatField vs. DecimalField

FloatField 类有时会与 DecimalField 类混淆。虽然它们都表示实数,但它们表示的方式不同。FloatField 内部使用 Python 的 float 类型,而 DecimalField 则使用 Python 的 Decimal 类型。关于两者之间的区别,请参见 Python 的 decimal 模块的文档。

ImageField

class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)

继承 FileField 的所有属性和方法,但也验证上传的对象是有效的图像。

除了 FileField 的特殊属性外, ImageField 也有 heightwidth 属性。

为了方便查询这些属性,ImageField 有两个额外的可选参数。

ImageField.height_field

模型字段的名称,每次保存模型实例时将自动填充图像的高度。

ImageField.width_field

模型字段的名称,每次保存模型实例时将自动填充图像的宽度。

需要 Pillow 库。

ImageField 实例在数据库中创建为 varchar 列,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。

该字段的默认表单部件是一个 ClearableFileInput

IntegerField

class IntegerField(**options)

一个整数。从 -21474836482147483647 的值在 Django 支持的所有数据库中都是安全的。

它使用 MinValueValidatorMaxValueValidator 根据默认数据库支持的值来验证输入。

localizeFalse 时是 NumberInput 否则,该字段的默认表单部件是 TextInput

GenericIPAddressField

class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options)

IPv4 或 IPv6 地址,字符串格式(如 192.0.2.302a02: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。

JSONField

class JSONField(encoder=None, decoder=None, **options)
New in Django 3.1.

一个用于存储 JSON 编码数据的字段。在 Python 中,数据以其 Python 本地格式表示:字典、列表、字符串、数字、布尔值和 None

JSONField 在 MariaDB 10.2.7+、MySQL 5.7.8+、Oracle、PostgreSQL 和 SQLite(在 JSON1 扩展被启用的情况下)都支持。

JSONField.encoder

一个可选的 json.JSONEncoder 子类,用于序列化标准 JSON 序列化器不支持的数据类型(例如 datetime.datetimeUUID )。例如,你可以使用 DjangoJSONEncoder 类。

默认为 json.JSONEncoder

JSONField.decoder

一个可选的 json.JSONDecoder 子类,用于反序列化从数据库中获取的值。该值将采用自定义编码器选择的格式(通常是字符串)。你的反序列化可能需要考虑到你无法确定输入类型的事实。例如,你有可能返回一个 datetime,实际上是一个字符串,而这个字符串恰好与 datetime 选择的格式相同。

默认为 json.JSONDecoder

如果你给字段一个 default,确保它是一个不可变的对象,比如 str,或者是一个每次返回一个新的可变对象的可调用对象,比如 dict 或一个函数。提供一个像 default={}default=[] 这样的可改变的默认对象,在所有模型实例之间共享一个对象。

要在数据库中查询 JSONField,请看 查询 JSONField

索引

IndexField.db_index 都创建了一个 B 树索引,在查询 JSONField 的时候并不是特别有用。仅在 PostgreSQL 上,可以使用 GinIndex 比较适合。

PostgreSQL 用户

PostgreSQL 有两种基于 JSON 的原生数据类型: jsonjsonbjsonjsonb。它们之间的主要区别在于它们的存储方式和查询方式。PostgreSQL 的 json 字段是作为 JSON 的原始字符串表示来存储的,当根据键来查询时,必须同时进行解码。jsonb 字段是基于 JSON 的实际结构存储的,它允许索引。这样做的代价是在写入 jsonb 字段时增加了一点成本。JSONField 使用 jsonb

Oracle 用户

Oracle 数据库不支持存储 JSON 标量值。只支持 JSON 对象和数组(在 Python 中使用 dictlist 表示)。

NullBooleanField

class NullBooleanField(**options)

就像 BooleanFieldnull=True

3.1 版后已移除: NullBooleanField 已被废弃,改为 BooleanField(null=True)

PositiveBigIntegerField

class PositiveBigIntegerField(**options)
New in Django 3.1.

就像一个 PositiveIntegerField,但只允许在某一特定点下的值(依赖于数据库)。09223372036854775807 的值在 Django 支持的所有数据库中都是安全的。

PositiveIntegerField

class PositiveIntegerField(**options)

就像 IntegerField 一样,但必须是正值或零( 0 )。从 02147483647 的值在 Django 支持的所有数据库中都是安全的。出于向后兼容的原因,接受 0 的值。

PositiveSmallIntegerField

class PositiveSmallIntegerField(**options)

就像一个 PositiveIntegerField,但只允许在某一特定(数据库依赖的)点下取值。032767 的值在 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_slugvalidate_unicode_slug 进行验证。

SlugField.allow_unicode

如果是 True,该字段除了接受 ASCII 字母外,还接受 Unicode 字母。默认值为 False

SmallAutoField

class SmallAutoField(**options)

就像一个 AutoField,但只允许值在一定(依赖于数据库)的限制下。132767 的值在 Django 支持的所有数据库中都是安全的。

SmallIntegerField

class SmallIntegerField(**options)

就像一个 IntegerField,但只允许在某一特定(依赖于数据库的)点下取值。从 -3276832767 的值在 Django 支持的所有数据库中都是安全的。

TextField

class TextField(**options)

一个大的文本字段。该字段的默认表单部件是一个 Textarea

如果你指定了 max_length 属性,它将反映在自动生成的表单字段的 Textarea 部件中。但是,它并没有在模型或数据库层面被强制执行。使用一个 CharField 来实现。

TextField.db_collation
New in Django 3.2.

该字段的数据库字符序名称。

注解

字符序名称是不标准化的。因此,这将无法在多个数据库后端之间进行移植。

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 上使用时,它存储在一个 uuid 的数据类型中,否则存储在一个 char(32) 中。

通用唯一标识符是 primary_keyAutoField 的一个很好的替代方案。数据库不会为你生成 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 上查找

在 PostgreSQL 上使用 iexactcontainsicontainsstartswithistartswithendswithiendswith 在 PostgreSQL 上查找没有连字符的值是行不通的,因为 PostgreSQL 将它们存储在一个连字符的 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_indexFalse 来禁用它。 如果你创建外键是为了保持一致性,而不是为了连接,或者你将创建一个替代性的索引,如部分索引或多列索引,你可能希望避免索引的开销。

数据库表现

在幕后,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_deletepost_delete 信号是为所有被删除的对象发送的。

  • PROTECT

    通过引发 ProtectedError,即 django.db.IntegrityError 的子类,防止删除被引用对象。

  • RESTRICT
    New in Django 3.1.

    通过引发 RestrictedErrordjango.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 为空;只有当 nullTrue 时,才有可能。

  • 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=TrueUsers。这在 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_namedefault_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 相同。

limit_choices_to 在使用 through 参数指定自定义中间表的 ManyToManyField 上使用时没有效果。

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>_idManyToManyField 指向的模型的 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)

MembershipPerson两个 外键( personinviter ),这就使得两者的关系变得模糊不清,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_constraintthrough 会引发错误。

ManyToManyField.swappable

控制迁移框架的反应,如果这个 ManyToManyField 指向一个可交换的模型。如果它是 True ——默认值——那么如果 ManyToManyField 指向的模型与 settings.AUTH_USER_MODEL 的当前值相匹配(或其他可交换模型配置),关系将被存储在迁移中,使用对配置的引用,而不是直接对模型的引用。

只有当你确定你的模型应该始终指向交换的模型——例如,如果它是一个专门为你的自定义用户模型设计的配置文件模型,你才希望将此覆盖为 False

如果不确定,就保留它在默认为 True 的状态。

ManyToManyField 不支持 validators

null 没有效果,因为没有办法在数据库层面要求建立关系。

OneToOneField

class OneToOneField(to, on_delete, parent_link=False, **options)

一对一的关系。概念上,这类似于 ForeignKeyunique=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 指定的主管:

>>> user.supervisor_of
Traceback (most recent call last):
    ...
RelatedObjectDoesNotExist: User has no supervisor_of.

此外,OneToOneField 接受 ForeignKey 接受的所有额外参数,外加一个额外参数:

True 并用于从另一个 concrete model 继承的模型中时,表示该字段应被用作回到父类的链接,而不是通常通过子类隐含创建的额外 OneToOneField

参见 一对一关系,了解 OneToOneField 的使用实例。

字段 API 参考

class Field

Field 是一个抽象的类,表示一个数据库表的列。Django 使用字段来创建数据库表( db_type() ),将 Python 类型映射到数据库( get_prep_value() ),反之亦然( from_db_value() )。

因此,一个字段在不同的 Django API 中是一个基本的部分,特别是 modelsquerysets

在模型中中,字段被实例化为一个类属性,并代表一个特定的表列,见 模型。它的属性有 nullunique,以及 Django 用来将字段值映射到数据库特定值的方法。

FieldRegisterLookupMixin 的子类,因此 TransformLookup 都可以在它上面注册,以便在 QuerySet 中使用(例如: field_name__exact="foo" )。所有 内置查找 都是默认注册的。

所有 Django 的内置字段,如 CharField,都是 Field 的特殊实现。如果你需要一个自定义的字段,你可以对任何一个内置字段进行子类化,或者从头开始写一个 Field。无论哪种情况,请参见 编写自定义模型字段(model fields)

description

字段的详细描述,例如: django.contrib.admindocs 应用程序。

描述的形式可以是:

description = _("String (up to %(max_length)s)")

其中的参数是从字段的 __dict__ 中插入的。

descriptor_class

一个实现 描述符协议 的类,它被实例化并分配给模型实例属性。构造函数必须接受一个参数,即 Field 实例。覆盖该类属性可以自定义获取和设置行为。

为了将一个 Field 映射到数据库的特定类型,Django 提供了一些方法:

get_internal_type()

返回一个字符串,用于命名这个字段,以满足后台的特定目的。默认情况下,它返回的是类名。

参见 仿造内置字段类型 在自定义字段中的用法。

db_type(connection)

返回 Field 的数据库列数据类型,并考虑 connection

参见 自定义数据库类型 在自定义字段中的用法。

rel_db_type(connection)

返回指向 FieldForeignKeyOneToOneField 等字段的数据库列数据类型,并考虑 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。默认情况下,如果 prepared=True,它将返回 value,而如果是 False,它将返回 get_prep_value()

使用方法参见 将查询值转为数据库值

加载数据时,使用 from_db_value()

from_db_value(value, expression, connection)

将数据库返回的值转换为 Python 对象。与 get_prep_value() 相反。

这个方法不用于大多数内置字段,因为数据库后端已经返回了正确的 Python 类型,或者后端自己进行了转换。

expressionself 相同。

使用方法参见 将值转为 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.FieldModelForm

默认情况下,如果 form_classchoices_form_class 都是 None,则使用 CharField。如果字段有 chips,且 choices_form_class 没有指定,则使用 TypedChoiceField

使用方法参见 为模型字段指定表单字段

deconstruct()

返回一个包含足够信息的四元元组来重新创建字段。

  1. 模型上的字段名称。
  2. 字段的导入路径(例如 "django.db.models.IntegerField" )。这应该是最可移植版本,所以不那么具体可能更好。
  3. 一个位置参数的列表。
  4. 一个关键字参数的字典。

这个方法必须添加到 1.7 之前的字段中,才能使用 迁移 迁移其数据。

字段属性参考

每个 Field 实例都包含几个属性,允许对其行为进行内省。当你需要编写依赖于字段功能的代码时,可以使用这些属性来代替 isinstance 检查。这些属性可以与 Model._meta API 一起使用,以缩小对特定字段类型的搜索范围。自定义模型字段应该实现这些标志。

字段的属性

Field.auto_created

表示是否自动创建字段的布尔标志,如模型继承使用的 OneToOneField

Field.concrete

布尔值标志,表示该字段是否有与之相关的数据库列。

Field.hidden

布尔值标志,表示一个字段是否用于支持另一个非隐藏字段的功能(例如,组成 GenericForeignKeycontent_typeobject_id 字段)。hidden 标志用于区分构成模型上公共字段子集的内容和模型上所有字段。

注解

Options.get_fields() 默认情况下不包括隐藏字段。传入 include_hidden=True 在结果中返回隐藏字段。

Field.is_relation

布尔值标志,表示一个字段是否包含对一个或多个其他模型的功能引用(如 ForeignKeyManyToManyFieldOneToOneField 等)。

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

如果该字段有一对多关系,如 GenericRelationForeignKey 的反向关系,则为 True ;否则为 False

Field.one_to_one

如果字段有一对一的关系,如 OneToOneField,则为 True ;否则为 False

Field.related_model

指向该字段所涉及的模型。例如,ForeignKey(Author, on_delete=models.CASCADE) 中的 AuthorGenericForeignKeyrelated_model 总是 None

Back to Top