Django学习笔记(一)ForeignKey,ManyToManyField和OneToOneField的辨析

导引

  • 模型(Models)是对网站所需信息种类的定义,其包含了网站存储数据中的重要字段和数据行为。一般来说,一个模型对于数据库中的一个表单。
  • 字段(Fields)是模型的重要和唯一组成部分,他们由类别的属性值所指定。

Field分类

由官方文档Model field reference | Django Documentation定义:
Field一共分为AutoField、BinaryField、BooleanField、CharField、DateField、DecimalField、EmailField、FileField、FloatField、IntegerField、TextField、TimeField、URLField等类别,丰富的类别选项为数据库存储方式提供了完善的支持,而本文主要是针对如下三个关系型字段(Relationship fields):

关系型字段对应关系
ForeignKey多对一
ManyToManyField多对多
OneToOneField一对一

分析

ForeignKey

首先查看源码,在类的开头有如下参数:

    many_to_many = False
    many_to_one = True
    one_to_many = False
    one_to_one = False

由此可见,ForeignKey是many_to_one类型的,即“一对多”,我们引用官方文档给出的示例:

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

由此我们可以看到,Car类型中有manufacturer字段,其类型是对应Manufacturer类的ForeignKey。我们可以根据生活常识理解这种定义,由于一部汽车对应一个生产商,而一个生产商可以对应许多部汽车,所以两者具有“一对多”的关系,在此种情况我们使用ForeignKey。
对于每个ForeignKey,我们需要给出关联的模型和on_delete响应的选项,即

    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )

on_delete函数的作用是在此字段被删除的时候做出的响应,其可选项如下:

选项功能
CASCADE级联删除,此类选项模仿SQL语句ON DELETE CASCADE,再删除此字段信息的时候同时删除包含ForeignKey字段的目标(object)
PROTECT通过django.db.IntegrityError中的ProtectedError来保护此字段不被删除,若进行删除操作则抛出错误
SET_NULL将ForeignKey置为空,这只在null选项为True的时候产生作用
SET_DEFAULT设为默认值(default value),此默认值已预先对ForeignKey设置
SET()对ForeignKey设置对SET()函数传递的数值
DO_NOTHING不进行任何操作。若数据库提高了引用完整性,则此种设置会抛出一个IntegrityError,除非对这一数据字段手动添加了SQL语句中的ON DELETE字段

还可以通过设置abstract属性来定义一个抽象类:

from django.db import models

class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)

    class Meta:
        abstract = True

ForeignKey还有如下的参数可以选择:

参数功能
limit_choices_to通过一个限制对字段信息的某一可能选项进行约束,可以通过字典,函数或者查询值来设置
related_name可以指定关联的类在本类中的名称,通过这一参数可以用两个字段名引用同一个类,通过这个名称父类可以取得子类的值,默认为字段名
related_query_name用于filter函数过滤和values函数
to_field关系关联的相关对象名称
db_constraint控制在数据库中是否应该建立这一字段的约束
swappable用于控制这一字段对于可交换类模型的行为

ManyToManyField

同样在源码中我们可以找到针对ManyToManyField的如下定义:

    many_to_many = True
    many_to_one = False
    one_to_many = False
    one_to_one = False

由此可以知道,ManyToManyField是针对“many-to-many”即多对多关系定义的,它需要知道它关联的类别。
官方文档给出的示例代码可以帮助理解:

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

在示例代码中,Pizza类的toppings字段由ManyToManyField与Toppings关联,我们可以由生活常识得出一片披萨上面会有很多种类的佐料,而一种佐料又可以用来制作多种披萨,两者满足“多对多”的关系。
ManyToManyField类有两个经常使用的参数:through和through_fields,通过这两个参数可以十分方便地建立中间项的关联,如示例代码所示:

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)

在Group类中有ManyToManyField类的字段members,这一字段通过through参数与membership联系起来,后者表示“成员资格”,即表示“团体”与“个人”之间关系的中间项,而“through_fields”字段即为中间项连接起来的两个类名,此处即group和person两个类。
ManyToManyField还有以下参数可以选择:

参数功能
related_name同ForeignKey,可以指定关联的类在本类中的名称
related_query_name同ForeignKey,应用于filter和values函数
limit_choices_to同ForeignKey,但如果自己定义了如“Membership”之类的中间类,则不会起到作用
symmetrical对于迭代定义的ManyToManyField,其为这一字段建立一个单独的属性,而是设定symmetrical属性为True,若期望使用此类迭代关系,可以手动设置其为False
through如上所示,用于设置中间项的名字,可以自己定义一个中间项,若不定义的话系统也会分配一个中间项
through_fields通过元组来给出中间项关联的两个类名,可以查看上面的示例
db_table可以通过这一属性来手动设定保存这一字段的数据表名称,若不设置则默认为字段的名称
db_contraint是否在数据库中建立约束
swappable设置是否指向一个可交换的模型

OneToOneField

源码中对OneToOneField的设置如下:

    many_to_many = False
    many_to_one = False
    one_to_many = False
    one_to_one = True

可知其是针对单对单的关系设定的字段。在概念上我们可以理解其为设置unique属性为True的一种类型,区别之处在于它“反向”的数值会返回一个目标值,这对于继承关系的表达十分有用,例如一下示例程序:

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

OneToOneField既包含ForeignKey中的参数,又包含一个额外的参数parent_link,若定义了一个类,其继承了一个非抽象的类,而设置parent_link这个函数为True,则会将这个类视作继承的类的父类,而不是一个新的OneToOneField。

参考资料

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值