一、前期概要
1.1 名词解释
- 关系:事物之间相互作用、相互联系的状态。
- 关联:名词:表示对象(数据库表)之间的关系;动词:将对象(数据库表)之间通过某种方式联系起来。
- 映射:将一种形式转化为另一种形式,包括关系。
- 级联:有关系的双方中操作一方,另一方也将采取一些动作
- 值类型:对象不具备数据库同一性,属于一个实体实例其持久化状态被嵌入到所拥有的实体的表行中,没有标识符。
- 实体类型:具有数据库标识符。
二、数据库关系
- 一对一(one-to-one)
- 多对一(many-to-one)
- 多对多(many-to-many)
三、模型
-
完整代码
from django.db import models # Create your models here. class ClassRoom(models.Model): cls_id = models.AutoField(primary_key=True) cname = models.CharField(max_length=32) cdata = models.DateField(auto_now_add=True) class Meta: db_table = 'class_room' def __str__(self): return "%s" % [self.__class__, self.cname] class Student(models.Model): stu_id = models.AutoField(primary_key=True) stu_name = models.CharField(max_length=32) # 一对多 cls_id = models.ForeignKey(to="ClassRoom", on_delete=models.SET_NULL, null=True, to_field='cls_id',db_column='cls_id') class Meta: db_table = 'student' def __str__(self): return "%s" % self.stu_name class StudentDetail(models.Model): stu_detail_id = models.AutoField(primary_key=True) height = models.PositiveIntegerField(null=True) email = models.EmailField(null=True) no = models.CharField(max_length=64) stu = models.OneToOneField('Student', on_delete=models.CASCADE, to_field='stu_id', null=True) class Meta: db_table = 'student_detail' class Teacher(models.Model): id = models.AutoField(primary_key=True) tea_name = models.CharField(max_length=32) cid = models.ManyToManyField(to="Student", name="teacher", db_table='teacher_student') class Meta: db_table = 'teacher'
四、一对一映射关系
1.1、概念
所谓的一对一查询,就是说我们在查询一个表的数据的时候,需要关联查询其他表的数据,例如:husband(丈夫)-wife(妻子) User和Account,一个用户对应一个账户,一个订单对应一个用户,一个学生信息对一个学生详情表
1.2、配置方式
-
语法
OneToOneField(to, on_delete=None, to_field=None,db_column=None)
-
参数说明
-
to
主表 对应类的名称
-
on_delete
当一个被外键关联的对象被删除时,Django将模仿
on_delete
参数定义的SQL约束执行相应操作。比如,你有一个可为空的外键,并且你想让它在关联的对象被删除时,自动设为null常用可选值
1、models.CASCADE 子表相关的数据删除
2、models.SET_NULL 子表的数据不删除 外键字段设置null=True
3、odels.SET_DEFAULT 子表关联数据不删除,在外键字段设置自定义的值4、DO_NOTHING:什么也不做。
5、SET():设置为一个传递给SET()的值或者一个回调函数的返回值。注意大小写
-
related_name
用于关联对象反向引用模型的名称。通常情况下,这个参数我们可以不设置,Django会默认以模型的小写作为反向关联名
-
to_field
参照主表的字段 默认主键
-
-
关系模型
-
对象模型
class Student(models.Model): stu_id = models.AutoField(primary_key=True) stu_name = models.CharField(max_length=32) # 一对多 cls_id = models.ForeignKey(to="ClassRoom", on_delete=models.SET_NULL, null=True, to_field='cls_id',db_column='cls_id') class Meta: db_table = 'student' def __str__(self): return "%s" % self.stu_name class StudentDetail(models.Model): stu_detail_id = models.AutoField(primary_key=True) height = models.PositiveIntegerField(null=True) email = models.EmailField(null=True) no = models.CharField(max_length=64) stu = models.OneToOneField('Student', on_delete=models.CASCADE, to_field='stu_id', null=True) class Meta: db_table = 'student_detail'
1.3、添加
-
方式一
# 先保存主表数据,然后将主表的id给子表的外键字段 stu = Student.objects.create(stu_name='小明') StudentDetail.objects.create(stu=stu, email='123@163.com', no=175)
-
方式二
stu = Student.objects.create(stu_name='小红') StudentDetail.objects.create(stu_id=stu.pk, email='345@163.com', no=170)
-
总结
跟单表操作表,唯一需要注意的是往子表添加数据,主表的数据一定要先存在
1.4、修改
-
通过主表更新子表
xm = Student.objects.get(pk=1) StudentDetail.objects.filter(stu=xm).update(no='123')
-
通过主表更新子表
stu = StudentDetail.objects.get(stu_detail_id=2).stu stu.stu_name = '小花' stu.save()
-
总结
跟单表操作比,如果提供的条件是有关系的表,通过关联关系找到相关的表的记录然后去更新,
1.5、查询
-
通过子表查询主表相关的信息(正向查询)
stu = StudentDetail.objects.get(pk=1) print(stu.stu_name)
-
通过主表查询子表相关的信息(反向查询)
# 系统会自动创建一个 类名小写的字段对象 stu = Student.objects.get(pk=1) # 类名字的小写 print(stu.stu_name, stu.studentdetail.email, str(stu.studentdetail.stu_detail_id))
-
通过主表的条件查询子表数据(可以使用双下划线)
# 一对一的子表字段__母表字段="xxx" # 相当于sql里的等值连接 sd = StudentDetail.objects.filter(stu__stu_name='小明') # 等同于 # stu_id = Student.objects.get(stu_name='小明').stu_id # sd = StudentDetail.objects.filter(stu_id=stu_id) # 也可以 stu = Student.objects.get(stu_name='小明') print(stu.studentdetail)
-
总结
- 通过查询主表,会自动帮我们关联查询子表的数据, 使用主表对象.类名小写的方式
- 通过主表查询子表,如果查询的条件是主表可以直接使用子表字段__母表字段
1.6、删除
- 通过主表删除子表数据 跟on_delete删除设置有关
stu = Student.objects.get(pk=1)
stu.delete()
# 子表数据删除不影响主表数据跟普通单表的删除一样
-
删除子表数据的时候建议使用 假删除
在主表添加额外的字段
1 表示正常 0表示删除
is_delete = models.BooleanField(default=1)stu = Student.objects.get(pk=1) stu.is_delete = 0 stu.save() # 查询的时候把删除的字段加上 # Student.objects.filter(stu_name='隔壁小张', is_delete=1)
-
总结
删除主表数据对子表数据有影响,主要跟on_delete设置的值有关系,删除子表数据一般情况下跟主表没有太多的关系
五、一对多映射关系
2.1、概念
一对多关联是一方持有多方引用。例如:去京东购物,那么一个京东用户可以对应多个购物订单
2.2、配置方式
-
语法格式
ForeignKey(to, on_delete, **options)
-
参数说明
-
to
主表 对应类的名称
-
on_delete
当一个被外键关联的对象被删除时,Django将模仿
on_delete
参数定义的SQL约束执行相应操作。比如,你有一个可为空的外键,并且你想让它在关联的对象被删除时,自动设为null常用可选值
1、models.CASCADE 子表相关的数据删除
2、models.SET_NULL 子表的数据不删除 外键字段设置null=True
3、odels.SET_DEFAULT 子表关联数据不删除,在外键字段设置自定义的值4、DO_NOTHING:什么也不做。
5、SET():设置为一个传递给SET()的值或者一个回调函数的返回值。注意大小写
-
related_name
用于关联对象反向引用模型的名称。通常情况下,这个参数我们可以不设置,Django会默认以模型的小写作为反向关联名
-
to_field
参照主表的字段 默认主键
-
-
关系模型
-
对象模型
class ClassRoom(models.Model): cls_id = models.AutoField(primary_key=True) cname = models.CharField(max_length=32) cdata = models.DateField(auto_now_add=True) class Meta: db_table = 'class_room' def __str__(self): return "%s" % [self.__class__, self.cname] class Student(models.Model): stu_id = models.AutoField(primary_key=True) stu_name = models.CharField(max_length=32) # 一对多 cid = models.ForeignKey(to="ClassRoom", db_column='cls_id') class Meta: db_table = 'student' def __str__(self): return "%s" % [self.stu_name]
2.3、查询操作
-
通过主表查询子表
tea = Teacher.objects.filter(pk=1).first() stu_list = tea.student_set.all() for stu in stu_list: print(stu.stu_name)
-
也可以使用__双下划线方式(推荐)
sd = StudentDetail.objects.filter(stu__stu_name='小明') print(sd)
2.4、添加(跟一对一相同)
-
添加子表数据,往子表添加数据,主表的数据必须先存在
teacher = Teacher.objects.create(tea_name='隔壁小张') print(teacher.id) for index in range(10): Student(stu_name='test' + str(index), teacher_id=teacher.pk).save()
-
总结
- 添加主表数据对子表没有影响
- 往子表添加数据,主表的数据必须先存在
2.4、更新(跟一对一相同)
-
更新数据跟普通的操作没有太多的影响
room = ClassRoom.objects.filter(cname='实训1').first() num = room.student_set.filter(stu_id__gt=1).update(stu_name='111') print(num)
-
总结
通过主表查询子表的时候注意隐藏django会自动给我们创建一个类名_set的一个引用属性