显然,关系数据库的力量在于将表相互关联。Django提供了定义三种最常见的数据库关系类型的方法:多对一,多对多和一对一。

在说明之前,首先来理解一下这三个概念:

多对一: 两个集合a,b;集合a中的多个元素对应集合a中的一个元素。

多对对:两个集合a,b;集合a中的多个元素对应集合b中的多个元素。

一对一:两个集合a,b;集合a中的每个元素对应结合b中的一个元素,一一对应的关系。

理解了这三个关系,下面通过例子来说明。没有具体的查询使用,只是通过实例来说明这三种关系。

多对一

符合多对一的一种常见形式是员工与部门。多个员工是一个部门的。

  1. class Department(models.Model):
        dep_id = models.AutoField(primary_key=True)
        dep_name = models.CharField(max_length=40)
  2.  
  3. class Employee(models.Model):
        emp_id = models.IntegerField(primary_key=True)
        emp_name = models.CharField(max_length=60)
        emp_date = models.DateTimeField(auto_now_add=True)
        emp_dep = models.ForeignKey(to="Department", to_field="dep_id")

这个实例中员工表通过外键关联到部门表中。to指向被关联的表(这里就是部门表),to_field指向被关联表的字段(这个字段必须unique),默认是指向被关联表的主键。

执行如下两条命令:

  1. python manage.py makemigrations
  2. python manage.py migrate

进入数据库中,查看生成的表:

  1. MariaDB [webinfo]> desc mysite_department;
  2. +----------+-------------+------+-----+---------+----------------+
  3. | Field | Type | Null | Key | Default | Extra |
  4. +----------+-------------+------+-----+---------+----------------+
  5. | dep_id | int(11) | NO | PRI | NULL | auto_increment |
  6. | dep_name | varchar(40) | NO | | NULL | |
  7. +----------+-------------+------+-----+---------+----------------+
  8. 2 rows in set (0.01 sec)
  9.  
  10. MariaDB [webinfo]> desc mysite_employee;
  11. +------------+-------------+------+-----+---------+-------+
  12. | Field | Type | Null | Key | Default | Extra |
  13. +------------+-------------+------+-----+---------+-------+
  14. | emp_id | int(11) | NO | PRI | NULL | |
  15. | emp_name | varchar(60) | NO | | NULL | |
  16. | emp_date | datetime | NO | | NULL | |
  17. | emp_dep_id | int(11) | NO | MUL | NULL | |
  18. +------------+-------------+------+-----+---------+-------+
  19. 4 rows in set (0.00 sec)
  20. #外键生成的默认字段名为,类属性名加上“_id”.在django中使用的时候我们可以仍然使用emp_dep,但是在写原生SQL的时候需要加上后面"_id"。
  21. MariaDB [webinfo]>

外键的一些参数说明:

on_delete: 当被关联的对象删除时,外键的值该如何变化,有以下几个选项:

  1. models.CASCADE 此为默认值,级联删除,会删除关联数据。
  2. models.PROTECT 只要存在关联数据就不能删除,但是会弹出ProtectedError异常。
  3. models.SET_NULL 删除数据后关联字段设置为NULL,仅在该字段允许为null时可用(null=True
  4. models.SET_DEFAULT:将外键字段设为默认值。只有当字段设置了default参数时,方可使用
  5. models.DO_NOTHING:什么也不做.
  6. models.SET():设置为一个传递给SET()的值或者一个回调函数的返回值。注意大小写

limit_choice_to: 类似一个过滤的功能。

该参数用于限制外键所能关联的对象,只能用于Django的ModelForm(Django的表单模块)和admin后台,对其它场合无限制功能。其值可以是一个字典、Q对象或者一个返回字典或Q对象的函数调用,如下例所示:

  1. staff_member = models.ForeignKey(
  2. User,
  3. on_delete=models.CASCADE,
  4. limit_choices_to={'is_staff': True},
  5. )
  6.  
  7. 这样定义,则ModelFormstaff_member字段列表中,只会出现那些is_staff=TrueUsers对象,这一功能对于admin后台非常有用。

related_name:用于关联对象反向引用模型的名称.上面的实例就是从部门到员工的引用。通常情况下,这个参数我们可以不设置,Django会默认以模型的小写作为反向关联名,上面的反向关联名称对于部门来说就是“employee”。如果不想定义这个名称,可以赋值为“+”。related_name=“+”。

related_query_name:反向关联查询名。

db_constraint:

默认情况下,这个参数被设为True,表示遵循数据库约束,这也是大多数情况下你的选择。如果设为False,那么将无法保证数据的完整性和合法性。在下面的场景中,你可能需要将它设置为False:

  • 有历史遗留的不合法数据,没办法的选择
  • 你正在分割数据表

当它为False,并且你试图访问一个不存在的关系对象时,会抛出DoesNotExist 异常。

多对多的关系

多对多关系在数据库中也是非常常见的关系类型。如一个应用对应多台主机,一个主机对应多个应用。

多对多关系需要一个位置参数:关联的对象模型。它的用法和外键多对一基本类似。

在数据库后台,Django实际上会额外创建一张用于体现多对多关系的中间表。默认情况下,该表的名称是“多对多字段名+关联对象模型名+一个独一无二的哈希码”,例如‘author_books_9cdf4’,当然你也可以通过db_table选项,自定义表名。

  1. def __init__(self, to, related_name=None, related_query_name=None,
  2. limit_choices_to=None, symmetrical=None, through=None,
  3. through_fields=None, db_constraint=True, db_table=None,
  4. swappable=True, **kwargs)
  5.  
  6. 和外键重复的参数不再说明:

symmetrical: 有点不太理解,把官方文档定义放这里。

  1. Only used in the definition of ManyToManyFields on self. Consider the following model:
  2.  
  3. from django.db import models
  4.  
  5. class Person(models.Model):
  6. friends = models.ManyToManyField("self")
  7.  
  8. When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, it doesnt add a person_set attribute
    to the Person class. Instead, the ManyToManyField is assumed to be symmetrical that is, if I am your friend, then you are my friend.
  9.  
  10. If you do not want symmetry in many-to-many relationships with self, set symmetrical to False. This will force Django to add the descriptor
    for the reverse relationship, allowing ManyToManyField relationships to be non-symmetrical.

through:定义中间表。django会自动生成一张表来管理多对多关系的表,但是,如果要手动指定中间表,可以使用该through选项指定表示要使用的中间表的Django模型。

通常情况下这个表有三个字段如下:

  1. id 中间表的id字段。
  2. 模型对象的名+"_id",
  3. 被关联模型的名+"_id",
  4.  
  5. 例如上面的中间表字段名为:
  6. MariaDB [webinfo]> desc mysite_application_r;
  7. +----------------+---------+------+-----+---------+----------------+
  8. | Field | Type | Null | Key | Default | Extra |
  9. +----------------+---------+------+-----+---------+----------------+
  10. | id | int(11) | NO | PRI | NULL | auto_increment |
  11. | application_id | int(11) | NO | MUL | NULL | |
  12. | host_id | int(11) | NO | MUL | NULL | |
  13. +----------------+---------+------+-----+---------+----------------+
  14. 3 rows in set (0.00 sec)
  1. through_fields 仅在指定自定义中间表模型时使用。通过官网中的一个实例来说明吧:
  1. from django.db import models
  2.  
  3. class Person(models.Model):
  4. name = models.CharField(max_length=50)
  5.  
  6. class Group(models.Model):
  7. name = models.CharField(max_length=128)
  8. members = models.ManyToManyField(
  9. Person,
  10. through='Membership',
  11. through_fields=('group', 'person'),
  12. )
  13.  
  14. class Membership(models.Model):
  15. group = models.ForeignKey(Group, on_delete=models.CASCADE)
  16. person = models.ForeignKey(Person, on_delete=models.CASCADE)
  17. inviter = models.ForeignKey(
  18. Person,
  19. on_delete=models.CASCADE,
  20. related_name="membership_invites",
  21. )
  22. invite_reason = models.CharField(max_length=64)
  23.  
  24. #这个实例中自定义了中间表Membership,但是因为有两个与person相关的外键,django无法判断使用哪一个,因此这时候就必须指定through_fields,
    #through_fields是一个二维元组(field1, field2),其中field1表示发起多对对关系的模型(group),field2表示多对多关系的目标表(person)。

db_table:设置中间表的名称。不指定的话,则使用默认值。

db_constraint:参考外键的相同参数

ManyToManyField多对多字段不支持Django内置的validators验证功能。

null参数对ManyToManyField多对多字段无效!设置null=True毫无意义

一对一

A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.

一对一关系,最有用的就是扩展另一个模型。例如子表通过一对一关联到父表,达到对父表扩充的目的。

  1. from django.conf import settings
  2. from django.db import models
  3.  
  4. class MySpecialUser(models.Model):
  5. user = models.OneToOneField(
  6. settings.AUTH_USER_MODEL,
  7. on_delete=models.CASCADE,
  8. )
  9. supervisor = models.OneToOneField(
  10. settings.AUTH_USER_MODEL,
  11. on_delete=models.CASCADE,
  12. related_name='supervisor_of',
  13. )
  14.  
  15. #如果你没有给一对一关系设置related_name参数,Django将使用当前模型的小写名作为默认值。

OneToOneField一对一关系拥有和多对一外键关系一样的额外可选参数,只是多了一个parent_link参数。

django模型中的关系对应的更多相关文章

  1. Django模型中OneToOneField和ForeignKey的区别

    网上看到一篇讲解"Django模型中OneToOneField和ForeignKey区别" 的文章,浅显易懂; 可以把ForeignKey形象的类比为: ForeignKey是on ...

  2. 如何在Django模型中管理并发性 orm select_for_update

    如何在Django模型中管理并发性 为单用户服务的桌面系统的日子已经过去了 - 网络应用程序现在正在为数百万用户提供服务,许多用户出现了广泛的新问题 - 并发问题. 在本文中,我将介绍在Django模 ...

  3. 如何让django模型中的字段和model名显示为中文

    如何让django模型中的字段和model名显示为中文:在模型中加入class Meta即可 class People(models.Model): name = models.CharField(n ...

  4. django模型中的抽象类(abstract)

    首先介绍下django的模型有哪些属性:先看例子: Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.以下对此作一总结: abstract 这个属性是定义当前的模 ...

  5. django 模型中 class Meta 内 各种属性的用法

    Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.下面对此作一总结: abstract 这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会相应数据库表的 ...

  6. Django 模型中自定义Manager和模型方法

    1.自定义管理器(Manager) 在语句Book.objects.all()中,objects是一个特殊的属性,通过它来查询数据库,它就是模型的一个Manager. 每个Django模型至少有一个m ...

  7. 在 django模型中封装元组和字典, 字段中使用chioce参数实现数据的一一对应

    一.models.py中 class OrderInfo(BaseModel): '''订单模型类''' # 封装一个字典, 便于在视图中取值, 进行比对 PAY_METHODS = { : &quo ...

  8. Django 模型中FileField字段

    FileField¶ class FileField([upload_to=None, max_length=100, **options])¶ 一个上传文件的字段. 注意 FileField字段不支 ...

  9. django模型中, 外键字段使用to_filed属性 指定到所关联主表的某个字段

    在django项目的开发过程中,在设计模型时一开始将主键设置成了一个自定义的字段,但是在创建搜索索引时却发现必须要存在一个id的字段,并且为主键(不知道是否是项目一开始就这样配置的原因), 但此时表结 ...

随机推荐

  1. 多线程——interrupt方法

    测试interrupt()方法: package day_12_01_Thread; import java.util.Date; /** * 测试interrupt()方法:结束线程,但是线程还是活 ...

  2. SOA架构父工程的pom配置

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  3. SEO--简介

    SEO:搜索引擎优化 不需付费 SEM:搜索引擎营销 需要付费 IP:每个家庭每个公司应该是同个IP PV:网站刷新搜索总量 UV:独立用户访客

  4. ODBC是什么

    ODBC(Open Database Connectivity,开放数据库互连)是微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有关数据库的一 ...

  5. iOS UI基础-9.0 UITableView基础

    在iOS中,要实现表格数据展示,最常用的做法就是使用UITableView.UITableView继承自UIScrollView,因此支持垂直滚动,而且性能极佳. UITableView有两种样式: ...

  6. Linux基础(三)Shell test 命令

    Shell test 命令 Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值.字符和文件三个方面的测试. 数值测试 参数 说明 -eq 等于则为真 -ne 不等于则为真 -gt ...

  7. shell基础:环境变量

    子shell是在父shell中打开的shell. 使用pstree查看进程树. $调用环境变量 set查看所有变量内容, env查询环境变量 只是临时改变

  8. 编写一种递归方法,它返回数N的二进制中表示1的个数。

    /** * 编写一种递归方法,它返回数N的二进制中表示1的个数.利用这样一个事实:N为奇数,其1的个数为N/2的二进制中1的个数加1. * @author wulei * */public class ...

  9. Mongodb 分组查询例子

    db.tblCard.aggregate([     {         $match: {             "sNo": {                 " ...

  10. idea软件上设置爱彼迎字体