django教程—model篇

2021年04月19日 未雨晴空 0评论 1064阅读 1喜欢

字段

字段选项

选项 运用
name 字段名,不设置则是默认的属性名,映射时优先级:db_column>name>属性名
verbose_name 为字段设置一个人类可读,更加直观的别名
null null=True 则django将NULL在数据库中存储空值。默认值为False
blank blank=True 如果为True,则该字段允许为空白。默认值为False。需要注意的是这与null完全不同,``null与数据库完全相关,而 blank与验证相关。如果字段包含blank=True],则表单验证将允许输入一个空字符串。如果字段包含blank=False则将需要该字段。
choice 限制此字段必须从choice中选择
db_column 该参数用于定义当前字段在数据表内的列名。如果未指定,django将使用字段名作为列名。
db_index True则表示该字段的数据库索引将会被创建
db_tablespace 用于字段索引的数据库表空间的名字,前提是当前字段设置了索引。默认值为工程的DEFAULT_INDEX_TABLESPACE设置。如果使用的数据库不支持表空间,该参数会被忽略。
default 字段的默认值,可以是值或者一个可调用对象。如果是可调用对象,那么每次创建新对象时都会调用。设置的默认值不能是一个可变对象,比如列表、集合等等。lambda匿名函数也不可用于default的调用对象,因为匿名函数不能被migrations序列化。
editable 如果设为False,那么当前字段将不会在admin后台或者其它的ModelForm表单中显示,同时还会被模型验证功能跳过。参数默认值为True。
primary_key True则表示将该字段设置为主键,如果你没有给模型的任何字段设置这个参数为True,django将自动创建一个AutoField自增字段,名为‘id’,并设置为主键。也就是id = models.AutoField(primary_key=True)。如果你为某个字段设置了primary_key=True,则当前字段变为主键,并关闭Django自动生成id主键的功能。
unique 设为True时,在整个数据表内该字段的数据不可重复。注意:1.对于ManyToManyField和OneToOneField关系类型,该参数无效。2.当unique=True时,db_index参数无须设置,因为unqiue隐含了索引。
help_text 额外显示在表单部件上的帮助文本。即便你的字段未用于表单,它对于生成文档也是很有用的。
choices 在一个范围内选择出一项,注意这个选项与ForeignKey的区别,数据库只保存内部元祖的第一个值,后面的值保存在内存中;好处体现在:1、django admin中显示下拉框;2、避免连表查询,TYPE_CHOICES = ((0, ‘无效’), (1, ‘有效’),)
validators 运行在该字段上的验证器的列表。
unique_for_date 日期唯一。可能不太好理解。举个栗子,如果你有一个名叫title的字段,并设置了参数unique_for_date="pub_date",那么jango将不允许有两个模型对象具备同样的title和pub_date。有点类似联合约束。
unique_for_month 同上,只是月份唯一。
unique_for_year 同上,只是年份唯一。
serialize 默认为True,可以序列化
max_length 最大长度
error_messages 用于自定义错误信息。参数接收字典类型的值。字典的键可以是nullblankinvalidinvalid_choiceuniqueunique_for_date其中的一个。

基本字段

字段 描述
AutoField 基于IntegerField来实现可用ID自动递增,但是存在最大值
SmallAutoField 类似于AutoField,但仅允许值在[1,32767]内
BigAutoField 一个64位整数,非常类似于AutoField,但是不同之处在于它的值在[1,9223372036854775807]
BigIntegerField 一个64位整数,非常类似于IntegerField,但是不同之处在于它保证可以匹配从[-9223372036854775808,9223372036854775807]
BinaryField 一个用于存储原始二进制数据的字段。它可以分配[bytesbytearraymemoryviewBinaryField 有一个额外的可选参数:max_length字段的最大长度(以字符为单位)。但是官方不建议用该字段来存储文件。
BooleanField 一个表示真/假字段。默认值当default没有定义BooleanFieldNone
NullBooleanField NullBooleanField本质上是BooleanField设置null=true属性,在django3NullBooleanField已经不推荐使用了。
CharField 小文本字段,必填参数max_length
TextField 大文本字段
DurationField 一个用于存储时间差的字段
EmailField 基于CharField增加验证电子邮件的规则
IntegerField 一个整数。从-2147483648到的值2147483647在Django支持的所有数据库中都是安全的。
URLField 基于CharField增加验证URL的规则可选max_length
PositiveBigIntegerField Django 3.1的新功能。类似于PositiveIntegerField但仅允许在特定点(与数据库有关)下的值。从0到的值2^64-1=9223372036854775807在Django支持的所有数据库中都是安全的。
PositiveIntegerField 类似于IntegerField,但必须为正数或零(0)。int为4个字节,一个字节8位则表示32位从0到的值2^31-1=2147483647在Django支持的所有数据库中都是安全的。0出于向后兼容的原因而接受该值。
PositiveSmallIntegerField 类似于PositiveIntegerField,但仅允许在特定点(与数据库有关)下的值。从0到的值32767在Django支持的所有数据库中都是安全的。
SmallIntegerField 类似于IntegerField,但仅允许值在[-32768,32767]内
FloatField 在Python中由float实例表示的浮点数。FloatFieldfloat 内部使用Python的类型,而在内部DecimalField使用Python的Decimal类型。

复杂字段

SlugField

Slug是一个报纸术语。表示某事物的简短标签,仅包含字母,数字,下划线或连字符。它们通常在URL中使用,默认设置[db_index=True]开启索引。

参数 解释
max_length 如果max_length未指定,则Django将使用默认长度50。
allow_unicode 如果为True,则该字段除了接受ASCII字母外,还接受Unicode字母。默认为False

TimeField、DateField、DateTimeField

分别是时间字段、日期字段,、日期和时间字段

参数 解释
auto_now 每次保存对象时自动将字段设置为当前日期,也可以手动覆盖值。该参数通常用在更新时间字段上。请注意,该字段仅在调用时自动更新Model.save()以及User.objects.create(**kwargs),但是如QuerySet.update()对其他字段进行更新时,该字段不会更新,如果想要实现值,必须要自己手动指定自定义值
auto_now_add 首次创建对象时,不要你手动指定字段的值,django将字段自动设置为当前日期。即使您在创建对象时为此字段设置了一个值,也会将其忽略。该参数通常用在创建时间字段上。如果您希望能够修改此字段,请按照以下内容设置:
from datetime import date
update_time=models.DateField(default=date.today)
或
from django.utils import timezone
update_time=models.DateField(default=timezone.now)
def __init__(self, verbose_name=None, name=None, auto_now=False,
             auto_now_add=False, **kwargs):
    self.auto_now, self.auto_now_add = auto_now, auto_now_add
    if auto_now or auto_now_add:
        kwargs['editable'] = False
        kwargs['blank'] = True
        super().__init__(verbose_name, name, **kwargs)

通过看初始化源码可以知道如果设置auto_nowauto_now_addTrue会导致该字段默认拥有editable=Falseblank=True 属性

auto_nowauto_now_add选项将始终使用的日期默认时区在创建或更新的时刻。如果您需要其他内容,则可能要考虑使用自己的可调用默认值或替代值。

DecimalField

固定精度的十进制数字,在Python中由 [Decimal]。有两个必需的参数:

参数 解释
max_digits 数字中允许的最大位数。请注意,此数字必须大于或等于decimal_places
decimal_places 与数字一起存储的小数位数。
# 表示存储最大位数为5位的,小数点后两位。如999.20,但是9999.20就不行
number=models.DecimalField(max_digits=5, decimal_places=2)

FileField和ImageField

需要注意的是primary_key不支持该参数,如果使用该参数将引发错误。FileField和ImageField实例在数据库中的类型是varchar ,默认最大长度为100个字符。与其他字段一样,您可以使用max_length参数更改最大长度。但是ImageField多了heightwidth属性。

参数 解释
upload_to 此属性提供了一种设置上传目录和文件名的方法,并且可以通过两种方法进行设置。在两种情况下,该值都将传递给该Storage.save()方法。如果值包括strftime格式,该格式将被文件上传时的日期和时间替换。如下面的代码
storage 自定义存储对象或返回存储对象的可调用对象
# 文件将保存在MEDIA_ROOT/uploads目录下
file = models.FileField(upload_to='uploads/')
# 文件将保存在MEDIA_ROOT/uploads/2015/01/30目录下
file = models.FileField(upload_to='uploads/%Y/%m/%d/')
参数 描述
%Y 四位数的年份
%m 两位数的月份
%d 两位数的日期

upload_to也可以是可调用的,例如函数。该可调用函数必须接受两个参数,并返回存储路径。这两个参数如下:

参数 描述
instance 简单点说就是当前FileField所在的model实例
filename 文件原始的文件名
def file_directory_path(instance, filename):
    # 通过实现自定义上传路径,可以保证每个用户上传的文件都在自己编号的文件目录下
    return 'user_{0}/{1}'.format(instance.user.id, filename)

class SysFile(models.Model):
    user=models.ForeignKey(to=User, on_delete=models.CASCADE)
    file = models.FileField(upload_to=user_directory_path)

注意点

  • MEDIA_ROOT表示系统文件存储的根目录,同时定义 MEDIA_URL为该目录的基本公共URL

  • upload_to(是表示位于MEDIA_ROOT下子目录

  • 存储在数据库中的所有文件都是该文件的路径(相对于MEDIA_ROOT

    例如设置MEDIA_ROOT='/home/media'以及upload_to='photos/%Y/%m/%d',文件名为test.txt如果上传时间为2021年04月01日,则该文件将保存在目录中/home/media/photos/2007/01/15/test.txt下,同时保存到数据库的是photos/2007/01/15/test.txt

FilePathField

FilePathField实例在数据库中创建为varchar 列,默认最大长度为100个字符。与其他字段一样,您可以使用max_length参数更改最大长度。选择仅限于文件系统上某个目录中的文件名。有一些特殊的参数,其中第一个是 必需的

参数 解释
path 参数必需的且目录是绝对文件系统路径,从中可以[FilePathField]选择该目录 。如:"/home/images"
match 可选的。一段字符串的正则表达式将用于过滤文件名。请注意,正则表达式将应用于基本文件名,而不是完整路径。
recursive 可选的。指定上面的path路径是否应包含的所有子目录,默认值为False
allow_files 可选的。无论是TrueFalse。默认值为True。指定是否应包含指定位置的文件。要么allow_folders必须是,要么 必须是True
allow_folders 可选的。无论是TrueFalse。默认值为False。指定是否应包含指定位置的文件夹。要么allow_files必须是,要么必须是True
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 SysFile(models.Model):
    file = models.FilePathField(path=images_path)

GenericIPAddressField

字符串格式的IPv4或IPv6地址(例如192.0.2.30)。

参数 解释
protocol 将有效输入限制为指定的协议。可接受的值为both(默认值)IPv4IPv6。匹配不区分大小写。
unpack_ipv4 解压缩IPv4映射的地址,如果启用此选项,则该地址将被解压缩到 192.0.2.1。默认设置为禁用。只能在protocol设置为both

JSONField

Django 3.1的新功能。用于存储JSON编码数据的字段。在Python中,数据以其Python本机格式表示:字典,列表,字符串,数字,布尔值和 NoneJSONFieldMariaDB 10.2.7 +,MySQL 5.7.8 +,Oracle,PostgreSQL和SQLite 3.9.0+受支持。

参数 解释
encoder 一个可选的[json.JSONEncoder]子类,用于序列化标准JSON序列化器(例如datetime.datetimeUUID)不支持的数据类型。例如,您可以使用DjangoJSONEncoder该类。默认为json.JSONEncoder
decoder 一个可选的json.JSONDecoder)子类,用于反序列化从数据库检索的值。该值将采用自定义编码器选择的格式(通常是字符串)。反序列化可能需要考虑以下事实:您不确定输入类型。例如,冒着返回一个datetime实际上是刚好为datetimes选择的相同格式的字符串的 a的风险。默认为json.JSONDecoder

如果想设置将字段设置为default,请确保它是一个不变的对象(例如)str,或者是每次都返回一个新的可变对象的可调用对象(例如dict或函数)。提供像一个可变的默认对象default={}default=[]所有股份模型实例之间的一个对象。

UUIDField

用于存储通用唯一标识符的字段。使用Python的UUID类。在PostgreSQL上使用时,它存储在uuid数据类型中,否则存储在 中char(32)。通用的唯一标识符是AutoField的很好替代primary_key。该数据库不会为您生成UUID,因此建议使用如下代码实现自动生成UUID

import uuid
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

请注意,将可调用的对象传递给default,而不是的UUID实例

注意点

使用iexact、contains、icontains、startswith、istartswith、endswith、iendswith在PostgreSQL上查找时不带连字符则不会生效,因为PostgreSQL将它们存储在一个连字符的UUID数据类型类型。

关系字段

演示模型

  • 一对多模型

      class User(models.Model):
          name=models.CharField(max_length=50)
    
      class Article(models.Model):
          name=models.CharField(max_length=50)
          user = models.ForeignKey(User, on_delete=models.CASCADE)
    
  • 多对多默认中间模型

      class Person(models.Model):
          name = models.CharField(max_length=50)
    
      class Group(models.Model):
          name = models.CharField(max_length=128)
          members = models.ManyToManyField(Person)
    
  • 多对多自定义中间模型

      class Person(models.Model):
          name = models.CharField(max_length=50)
    
      class Group(models.Model):
          name = models.CharField(max_length=128)
          # 由于中间表有两个外键(成员和邀请人),在这种情况下,必须通过through_fields来指定django应该使用的外键是哪两个字段
          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)
    

RelatedManager

在讲关系字段前,先来了解下RelatedManager,RelatedManager是表示一对多或多对多相关上下文中使用的关联管理器

  • add(objs,bulk = True,through_defaults = None)

    add()可以接受模型实例或字段值(通常为主键)作为*objs参数。但是使用多对多关系不会调用任何save()方法(该bulk参数不存在),而是使用QuerySet.bulk_create()来创建关系。如果在创建关系时需要执行一些自定义逻辑,请监听m2m_changed信号,该信号将触发pre_addpost_add执行操作。add()在已经存在的关系上使用不会重复该关系(即用户和组已经绑定过,再次绑定并不会重复插入) ,但仍会触发信号。

    对于多对多关系,如果需要,可使用through_defaults参数为新的中间模型实例指定额外的值 。您可以在through_defaults 字典中将可调用对象用作值,在django 3.1中进行了更改:through_defaults 值现在可以是可调用的。

    一对多模型

    >>> user = User.objects.get(id="xxx")
    >>> article = Article.objects.get(id="xxx")
    >>> user.article_set.add(article) # 关联用户和文章
    

    多对多默认中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> group = Group.objects.get(id="xxx")
    >>> person.group_set.add(person)
    

    多对多自定义中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> inviter = Person.objects.get(id="xxx")
    >>> group = Group.objects.get(id="xxx")
    >>> person.group_set.add(person,through_defaults={"inviter":inviter,"invite_reason":"xxxx"})
    
  • create(through_defaults = None, **kwargs)

    一对多模型

    >>> user = User.objects.get(id="xxx")
    >>> user.article_set.create(name="文章一")
    

    多对多默认中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> group = Group.objects.get(id="xxx")
    >>> person.group_set.create(name="xxx")
    

    多对多自定义中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> inviter = Person.objects.get(id="xxx")
    >>> person.group_set.create(name="xxx",{through_defaults={"inviter":inviter,"invite_reason":"xxxx"}})
    
  • remove(objsbulk = True)

    从相关对象集中删除指定的模型对象

    对于多对多关系,remove()可以接受模型实例或字段值(通常为主键)作为*objs 参数。但是,使用将删除关系 QuerySet.delete(),这意味着没有模型save()方法被调用; m2m_changed如果您希望在删除关系后执行自定义代码,请监听信号。对于ForeignKey对象,此方法要求ForeignKey设置了null=True。如果该字段不能设置为NoneNULL),则无法将一个对象从关系中删除而不将其添加到另一个对象中。在下面的一对多模型示例中,在模型Article没有设置user的属性null=True而执行 删除user.article_set(),这是无效的。

    对于ForeignKey对象,此方法接受一个bulk参数来控制如何执行该操作。如果True(默认),QuerySet.update()则使用。如果为bulk=Falsesave()则调用每个单独的模型实例的方法。这会触发 pre_save)和 post_save信号,并以牺牲性能为代价。

    对于多对多关系,bulk关键字参数不存在。

    一对多模型

    >>> user = User.objects.get(id="xxx")
    >>> article = Article.objects.get(id="xxx")
    >>> user.article_set.remove(article)
    

    多对多默认中间模型和多对多自定义中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> group1 = Group.objects.get(id="xxx")
    >>> group2 = Group.objects.get(id="xxx")
    >>> person.group_set.remove(group)
    >>> person.group_set.remove([group1,group2])
    >>> person.group_set.remove([<group1_id>,<group2_id>])
    
  • clear(bulk = True)

    从相关对象集中删除所有对象:

    请注意,这不会删除相关对象,而只是取消关联它们。就像一样remove()clear()仅在ForeignKey位置可用 null=True并且还接受bulk关键字参数。对于多对多关系,bulk关键字参数不存在。

    一对多模型

    >>> user = User.objects.get(id="xxx")
    >>> user.article_set.clear()
    

    多对多默认中间模型和多对多自定义中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> person.group_set.clear()
    
  • set(objs,bulk = True,clear = False,through_defaults = None)

    替换相关对象集,此方法接受一个clear参数来控制如何执行该操作。如果False(默认),则会执行remove()删除集中缺少的元素而仅添加新元素。如果为clear=Trueclear()则改为调用方法,然后立即添加整个集合。

    对于ForeignKey对象,set()仅接受模型实例的列表作为objs 参数,bulk 参数传递给add()remove()

    对于多对多关系,bulk关键字参数不存在。set()接受模型实例或字段值(通常是主键)的列表作为objs 参数。如果需要,可使用through_defaults参数为新的中间模型实例指定值 。在Django 3.1中进行了更改:through_defaults 值现在可以是可调用的。

    需要注意的是add()create()remove()clear(),和 set()所有适用的数据库将立即更改为各类相关领域。换句话说,不需要save() 在关系的任何一端进行调用。如果您使用prefetch_related()add()remove()clear(),和set()方法清除预取缓存。

    一对多模型

    >>> user = User.objects.get(id="xxx")
    >>> article1 = Article.objects.get(id="xxx")
    >>> article2 = Article.objects.get(id="xxx")
    >>> user.article_set.set([article1,article2])
    

    多对多默认中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> group1 = Group.objects.get(id="xxx")
    >>> group2 = Group.objects.get(id="xxx")
    >>> person.group_set.set([group1,group2])
    >>> person.group_set.set([<group1_id>,<group2_id>])
    

    多对多自定义中间模型

    >>> person = Person.objects.get(id="xxx")
    >>> inviter = Person.objects.get(id="xxx")
    >>> group1 = Group.objects.get(id="xxx")
    >>> group2 = Group.objects.get(id="xxx")
    >>> person.group_set.set([group1,group2],{"inviter":inviter,"invite_reason":"xxxx"})
    >>> person.group_set.set([<group1_id>,<group2_id>],through_defaults={"inviter":inviter,"invite_reason":"xxxx"})
    

ForeignKey

准确的说是多对一关系。需要两个位置参数:外键关联的模型和on_delete选项。

from django.db import models
# 汽车
class Car(models.Model):
    # 如果需要在尚未定义的模型上创建关系,则可以使用模型的名称,而不是模型对象本身
    manufacturer = models.ForeignKey(to='Manufacturer',on_delete=models.CASCADE)
    # 模型已经创建
    manufacturer = models.ForeignKey(to=Manufacturer,on_delete=models.CASCADE)

# 制造商   
class Manufacturer(models.Model):
    pass

如果关联的模型是在另一个应用程序中定义的模型,可以显式指定完成的模型路径。例如,如果Manufacturer 上面的模型是在另一个名为production的应用程序中定义的,则需要按照如下操作:

from django.db import models
# 汽车
class Car(models.Model):
    # 如果需要在尚未定义的模型上创建关系,则可以使用模型的名称,而不是模型对象本身
    manufacturer = models.ForeignKey(to='production.Manufacturer',on_delete=models.CASCADE)

在解决两个应用程序之间的循环导入依赖关系时,上面这种称为惰性关系的引用可能会很有用。

django会为ForeignKey自动创建数据库索引,可以通过设置[db_index=False为禁用此功能。

属性

  • db_column

    如果不设置该字段,Django默认会追加"_id"到字段名称以创建其数据库列名称。在上面的示例中,Car 模型的数据库表将具有manufacturer_id列。但是有的时候自定义sql的时候就需要设置该字段来指定明确数据表列名。

  • on_delete

    on_delete用来控制当外键数据删除是预留什么操作

选项 描述
on_delete=models.CASCADE 级联删除。意思就是当你删除了制造商某条数据,这个制造商关联的汽车数据也会被删除,原理是django并没有调用制造商Model.delete()方法来删除,而是通过发送pre_deletepost_delete信号。
on_delete=models.PROTECT 删除了制造商某条数据,会引发错误ProtectedError来告诉用户有其他表关联了该条数据
on_delete=models.SET_NULL 删除了制造商某条数据,会将所有关联该制造商的汽车数据的外键字段设置为为null,但是前提是该外键字段设置了null=True
on_delete=models.SET_DEFAULT 删除了制造商某条数据,会将所有关联该制造商的汽车数据的外键字段设置为为null,但是前提是该外键字段设置了default=xxxxxx
on_delete=models.DO_NOTHING 删除了制造商某条数据,什么也不做
on_delete=models.SET(get_sentinel_user), 删除了制造商某条数据,会将所有关联该制造商的汽车数据的外键字段设置为指定值,如models.SET(值)或设置为可执行对象的返回值,如models.SET(可执行对象)
on_delete=models.RESTRICT Django 3.1的新功能。通过引发RestrictedError防止删除引用的对象 。不同于PROTECT,如果引用的对象还引用了在同一操作中通过CASCADE关系删除的另一个对象,则允许删除该对象。
  • limit_choices_to

    该字段主要是方便使用ModelFormdjango-admin为该字段的可用选项设置一个限制(默认情况下,可以选择queryset中的所有对象)。可以使用字典, Q对象或返回字典或Q]对象的可调用对象。例如:

    # 只获取user的属性is_staff为True的用户
    staff = models.ForeignKey(User,on_delete=models.CASCADE,limit_choices_to={'is_staff': True},)
    
    def limit_pub_date_choices():
        return {'pub_date__lte': datetime.date.utcnow()}
    limit_choices_to = limit_pub_date_choices
    
  • related_name

    用来表示当前对象和关联对象的关系,同时它也是related_query_name用于目标模型的反向过滤器名称的名称)的默认值。如果您希望Django不要创建反向关系,请将设置 related_name'+'或以结束'+'这将确保该User模型不会与此模型具有反向查询关系。

    class Article(models.Model):
        title = models.CharField(max_length=150, verbose_name='文章标题')
        # 不创建反向关系
        user = models.ForeignKey(User,on_delete=models.CASCADE,related_name='+') 
        # 未指定related_name的值,则默认值为<model_name>_set。如:article_set
        user = models.ForeignKey(User,on_delete=models.CASCADE) 
        # 指定related_name的值
        user = models.ForeignKey(User,on_delete=models.CASCADE,related_name="user_article")
    

    例如当需要查询某个用户所有文章可以通过以下方法进行查询

    # 未指定related_name的值
    >>> user=User.object.get(id="xxx")
    >>> user.article_set.all()
    # 指定related_name的值
    >>> user=User.object.get(id="xxx")
    >>> user.user_article.all()
    
  • related_query_name

    用于目标模型的反向过滤器名称的名称。默认为related_name或 的值default_related_name,否则默认为模型的名称。

    例如查询哪些人写的文章名是xxx

  • to_field

    指定关联外键哪个字段。默认情况下,Django使用相关对象的主键。如果您引用其他字段,则该字段必须具有unique=True

  • db_constraint

    是否应在数据库中为此外键创建约束。默认值为True,将此设置False不利于数据完整性。

  • swappable

    默认值是True表示ForeignKeys指向与当前值settings.AUTH_USER_MODEL匹配的模型,则该关系将使用对该设置的引用(而不是直接指向该模型)存储在迁移中。仅False当您确定模型始终指向交换的模型时,才需要覆盖此设置。将其设置为False并不意味着即使已交换掉它也可以引用可交换模型-False意味着使用此ForeignKey进行的迁移将始终引用您指定的确切模型(因此,如果用户尝试与User一起运行,它将很难失败。例如,您不支持的模型)。如有疑问,请将其保留为默认值True

    class User(AbstractUser):
        """
        Users within the Django authentication system are represented by this
        model.
    
        Username and password are required. Other fields are optional.
        """
        class Meta(AbstractUser.Meta):
            swappable = 'AUTH_USER_MODEL'
    

ManyToManyField

多对多关系。可以使用字段的添加,删除或创建相关对象ManyRelatedManager。在不知道,Django创建了一个中间联接表来表示多对多关系。默认情况下,该表名是使用“多对多”字段的名称和包含该表的模型的表名生成的。由于某些数据库不支持超过一定长度的表名,因此这些表名将被自动截断并使用唯一性哈希,例如author_books_9cdf。您可以使用该db_table选项手动提供联接表的名称。

属性

  • symmetrical

    仅用于self上的ManyToManyFields的定义。考虑以下模型:当Django处理此模型时,它会确定 ManyToManyField自身具有,因此不会person_setPerson该类添加 属性。相反ManyToManyField假定s是对称的-也就是说,如果我是您的朋友,那么您就是我的朋友。如果您不希望与保持多对多关系中的对称性self,请将设置 symmetricalFalse。这将迫使Django为反向关系添加描述符,从而允许ManyToManyField关系非对称。在Django 3.0中进行了更改:symmetrical=True允许使用中介模型指定递归多对多关系。

  • through

    一般django会自动生成一个表来管理多对多关系,这个表具有三个用于链接模型的字段。

    如果源模型和目标模型不同,那么将生成以下字段:

字段 解释
id 关系的主键
<containing_model>_id 源实例id
<other_model>_id 目标实例的id

如果源模型和目标模型相同,则将生成以下字段:

字段 解释
id 关系的主键
from_<model>_id 源实例id
to_<model>_id 目标实例的id

但是django自动生成的中间表就没办法就再添加数据了如创建时间、更新时间,像这样的情况,只能手动指定中间表,则可以使用该through选项指定表示要使用的中间表的模型。使用中间模型的递归关系无法确定反向访问器名称,因为它们是相同的。您需要为其中一个模型设置related_name 。如果您不希望Django不创建向后关系,请将设置related_name'+'

  • db_table

    如果没有自定义中间模型,django将根据定义关系的两个模型表和其关联字段的名称来定义表名和字段名,但是如果不想表数据由django来生成,则可以通过该字段来指定表名。

  • through_fields

    中间模型必须包含一个到源模型的唯一外键,当出现多个外键,这个时候django就不知道怎么处理多对多关系了。这个时候就可以用您必须使用through_fields显式指定django应该用于关系的外键。如下代码所示:

    class Person(models.Model):
        name = models.CharField(max_length=50)
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        # 由于中间表有两个外键(成员和邀请人),在这种情况下,必须通过through_fields来指定django应该使用的外键是哪两个字段
        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)
    

    ManyToManyField不支持validators。null没有作用,因为没有办法在数据库级别上要求关系。

对对多ORM操作

  • 模型如下,且自定义了中间模型

    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=128)
    
        def __str__(self):
            return self.name
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(Person, through='Membership')
    
        def __str__(self):
            return self.name
    
    class Membership(models.Model):
        person = models.ForeignKey(Person, on_delete=models.CASCADE)
        group = models.ForeignKey(Group, on_delete=models.CASCADE)
        date_joined = models.DateField()
        invite_reason = models.CharField(max_length=64)
    
   >>> zhangsan = Person.objects.create(name="zhangsan")
   >>> basketball = Group.objects.create(name="basketball")
   >>> m = Membership(person=zhangsan, group=basketball,date_joined=date(1962, 8, 16),invite_reason="play basketball")
   >>> m1.save()
   >>> basketball.members.all()
   <QuerySet [<Person: zhangsan Starr>]>
   >>> zhangsan.group_set.all()
   <QuerySet [<Group: basketball>]>

如下只要通过through_defaults为任何必填字段指定值,就可以使用add()create()set()来创建关系

   >>> lisi = Person.objects.create(name="lisi")
   >>> basketball.members.add(lisi, through_defaults={'date_joined': date(1960, 8, 1),invite_reason="play basketball"})

   >>> basketball.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})

   >>> wangwu = Person.objects.create(name="wangwu")
   >>> jack = Person.objects.create(name="jack")

   >>> beatles.members.set([wangwu, jack], through_defaults={'date_joined': date(1960, 8, 1),invite_reason="play basketball"})

OneToOneField

一对一的关系。从概念上讲,实际上是相当于ForeignKey 设置了unique=True,但是反向查询将直接返回单个对象。如果您未指定的related_name参数,则 OneToOneFielddjango会将当前模型的小写名称用作默认值。

from django.conf import settings
from django.db import models

class VIPUser(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    inviter = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='supervisor_of',
    )

您得到的User模型将具有以下属性:

>>> user = User.objects.get(id='xxxxx')
>>> hasattr(user, 'VIPUser')
True
>>> hasattr(user, 'inviter')
True

属性

  • parent_link

    继承关系在子 model 和它的每个父类之间都添加一个链接 (通过一个自动创建的 OneToOneField来实现)。
    父类里面的所有字段在 子model中也是有效的,只不过没有保存在数据库中的子model表中,在父类上使用parent_link=True声明自己的OneToOneField来覆盖隐式创建的OneToOneField

发表评论 取消回复

电子邮件地址不会被公开。

请输入以http或https开头的URL,格式如:https://oneisall.top