一对多表的操作
一、关于一对多的认识
一对多的关系是通过外键来建立关系的,这样的两张表也可以叫多对一,一般我们都是从主表开始叫,不会从从表来叫的,所以一般不会叫多对一.
所谓的主表是指不依赖别人的表,从表是会依赖别的表.
常见的案例:主表(班级)-->从表(学生),主表(部门)-->从表(员工)...
二、django
中创建一对多的关系模型(班级->学生)
1、创建主表(班级表)
class ClassModel(models.Model): class_name = models.CharField(max_length=100, blank=True, null=True, verbose_name='班级名称') def __str__(self): return self.class_name
2、创建一个从表(学生表)
class StudentModel(models.Model): name = models.CharField(max_length=100, verbose_name='学生姓名') gender = models.CharField(max_length=2, verbose_name='性别') age = models.IntegerField(max_length=100, verbose_name='年龄') mobile = models.CharField(max_length=11, verbose_name='手机号码') # 创建一个外键关联到班级表 classs = models.ForeignKey('ClassModel', on_delete=models.CASCADE, null=True, blank=True) def __str__(self): return self.name
3、查看表从表结构(默认会创建一个
外键_id
的字段)mysql> desc app01_studentmodel; +-----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(100) | NO | | NULL | | | gender | varchar(2) | NO | | NULL | | | age | int(11) | NO | | NULL | | | mobile | varchar(11) | NO | | NULL | | | classs_id | int(11) | YES | MUL | NULL | | +-----------+--------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec) mysql>
三、关于外键中删除的指定(django2.0+
后必须要加的)
CASCADE
:这就是默认的选项,级联删除,你无需显性指定它。PROTECT
: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError
错误。SET_NULL
: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True
,定义该字段的时候,允许为空。SET_DEFAULT
: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。SET()
:自定义一个值,该值当然只能是对应的实体了
四、关于一对多新增数据
1、必须先要新增主表数据
def test(request): ClassModel.objects.create(class_name='1班') ClassModel.objects.create(class_name='2班') ClassModel.objects.create(class_name='3班') ClassModel.objects.create(class_name='3班') return HttpResponse('ok')
2、新增学生数据(方法一:使用
classs
模型)classModel = ClassModel.objects.get(pk=1) # 学生模型中创建外键关联的classs是一个数据模型 StudentModel.objects.create(name='张三', gender='男', age=20, mobile='110', classs=classModel) return HttpResponse('ok')
3、新增学生数据(方法二:直接使用
classs_id
)def test(request): classModel = ClassModel.objects.get(pk=1) StudentModel.objects.create(name='李四', gender='男', age=20, mobile='110', classs_id=classModel.id) return HttpResponse('ok')
五、关于一对多的查询数据
1、关于正面查找(从表查询主表数据),直接使用从表中定义的数据模型字段
def test(request): student = StudentModel.objects.get(pk=1) print(student.classs.class_name) return HttpResponse('ok')
2、关于反向查找(主表查询从表数据)
def test(request): classsResult = ClassModel.objects.get(pk=1) re = StudentModel.objects.filter(classs=classsResult).values('name', 'age', 'gender') print(re) return HttpResponse('ok')
3、关于反向查找(主表会默认创建一个从表model小写_set的字段)
def test(request): classsResult = ClassModel.objects.get(pk=1) re = classsResult.studentmodel_set.all() print(re) return HttpResponse('ok')
4、关于反向查找(关于第三点中的自定义别名)
1.在外键关联的时候就创建一个别名(
aaaa
)classs = models.ForeignKey('ClassModel', on_delete=models.CASCADE, null=True, blank=True, related_name='aaaa')
2.反向查找的时候主表中可以直接使用别名
def test(request): classsResult = ClassModel.objects.get(pk=2) re = classsResult.aaaa.all() print(re) return HttpResponse('ok')
5、使用双下划线进行跨表查询主表信息
def test(request): student = StudentModel.objects.all().values('name', 'age', 'gender', 'classs__class_name', 'classs_id') print(student) return HttpResponse('ok')
六、关于父子孙这样的外键关联的使用
1、业务场景:学生-->班级-->学校的关系
class ClassModel(models.Model): class_name = models.CharField(max_length=100, blank=True, null=True, verbose_name='班级名称') school_name = models.ForeignKey('School', on_delete=models.SET_NULL, null=True, blank=True, related_name='bbbb') def __str__(self): return self.class_name
2、关于正向查询
def test(request): student = StudentModel.objects.filter(name='张三').values('name', 'age', 'gender', 'classs__class_name', 'classs__school_name__school_name') print(student) return HttpResponse('ok')
七、总结
- 1、在一对多的关系表创建过程中,注意区分谁是主表(主表什么都不做),谁是从表(在从表中添加
ForeignKey
外键关联) - 2、关于正向查找与反向查找的问题,从表查询主表是正向查询,主表查询从表是反向查询,一般我们开发过程中尽量使用正向查询,少使用反向查询,但是我们也要知道所谓的反向查询
- 3、
django2.0+
后创建外键关联的时候要创建删除方式(请参考第三点)