SQL语句中有很多的关联查询:外关联、内关联、自关联等。而这些都是在进行多表之间的查询。一次你首先需要建立多张表,并建立他们之间的联系。
关系 | moels语法 | 注释 |
---|---|---|
一对一 | models.OneToOneField | 在两种表中的任意一个添加即可 |
一对多 | mdoels.ForeignKey | 在多类中添加外键 |
多对多 | models.ManyToManyField | 在两种表中任意一个添加即可 |
表之间的关系很好设定,只需要添加对应的字段即可,但是有几点需要注意!
1、关系型字段可以在两张表中同时设置,但是当两张表中的数据都为空时,两个关系型字段必须有一个可以为空,否则会发生类“死锁”的情况。两张表插入数据的前提是另一张表中要有已存在的数据。所以咋实际所运用中最好只设置一个。
2、设置完表之间的关系后,在表的查询过程中需要区别对待。是否设置了关系字段会影响到数据的操作。
创建好类后,需要在两个类中的任意一个类中定义关联字段,该字段的相关属性,可以为空值,但是在关联另一张表中的数据时,必须要一一对应不可重复。
models代码:
from django.db import models
# Create your models here.
# 定义学生类
class Student(models.Model):
Name = models.CharField(max_length=10)
Age = models.IntegerField(null=True, blank=True)
# 定义将来显示数据对象时显示的内容
def __str__(self):
return self.Name
# 定义学生卡类
class Card(models.Model):
Num = models.CharField(max_length=11)
# 定义一对一关系字段
Stu = models.OneToOneField('Student')
# 定义将来显示数据对象时显示的内容
def __str__(self):
return self.Stu.Name + '---' + self.Num
代码分析:
在应用的models模块中定义如上数据模型之后,需要先进行迁移才能够在数据库中产生对应的表。并保存数据。
生成迁移文件:python manage.py makemigrations
迁移到数据库:python manage.py migrate
完成迁移后,就可以进入交互式环境中进行数据的操作了。
交互式环境中代码示例:
# 导入数据模型
from app.models import Student, Card
# 通过模型对象添加学生数据。并接受返回值
s1 = Student.objects.create(Name='Jack', Age='18')
s2 = Student.objects.create(Name='Jerry', Age='18')
# 添加学生卡数据对象
c1 = Card.objects.create(Num='16520340211', Stu=s1)
c2 = Card.objects.create(Num='16520340212', Stu=s2)
# 含有关联字段的学生卡对象可以通过定义的关联字段来获取关联的学生对象
print(c1.Stu)
print(type(s1.Stu))
# 没有设置关联字段的学生对象可以使用内置方法来获取关联对象
print(s1.card)
print(s1.type(s1.card))
代码结果:
代码分析:
定义了关联关系的数据模型在相互关来年数据对象的时候,给字段添加关联字段属性的方法有所不同,我们可以看到在给 Card 的关联字段进行赋值时,并不是一个赋予一个具体的数据,而是赋了一个学生Student对象,这一点是需要注意的地方,如果赋予的不是学生对象的实例,就会报错。而且赋予的对象不能是已经关联到其他Card数据对象的对象。这样就破坏了一对一的关联规则,会报错。
通过打印结果我们可以发现,定义了一对一关系后,两张表的数据对象可以通过不同的方法来获取相关联的对象。
定义了关联字段的数据对象,可以通过关联字段来获取相关联的数据对象。
没有定义关联字段的数据对象,则可以使用关联的类模型来获取关联对象。要注意的是,Student中的card方法并不时所有数据对象都有的,而是由于该数据模型与Card数据模型建立了一对一的关联关系,而该模型中并没有定义关联字段,也就不能使用关联字段来获取关联对象。因此Django为我们自动提供了这样一种获取关联对象的方法。
当我们定义了一对一的关系后,没有关联字段的数据对象就会创建一个方法来获取关联对象,方法名和关联数据模型类名相同。但是所有字母均为小写。因此我们才会看到Student数据对象中有card方法。
对于建立了一对一关系的数据对象。在执行删除操作的时候,删除的结果有些不同。
对定义了关联字段的数据对象执行删除操作时,删除操作不会影响到另一张表中的数据。
对没有定义关联字段的数据对象执行删除操作时,不仅会删除当前对象数据,还会删除与之关联的数据对象数据。
执行delete()方法即可实现从数据库中删除当前对象数据。返回结果为一个元组。元祖中包含两个元素。第一个是一个数字,表名删除了数据对象的数量。第二个元素是一个字典。里面保存着所删除的数据对象的出处:键为删除数据对象在数据库中的表名,值为删除的数据对象的数量。
默认情况下,当人被删除的情况下,与人绑定的卡就也删除了,这个可以使用on_delete进行调整
on_delete
models.CASCADE 默认值
models.PROTECT 保护模式
models.SET_NULL 置空模式
models.SET_DEFAULT 置默认值
models.SET() 删除的时候重新动态指向一个实体
在数据表之间的关系中,一对多的关联是很常见的,在Django中创建该关系的字段是 models.ForeignKey 来这只外键的方式来实现。
一对多的关联创建。
from django.db import models
# Create your models here.
# 创建学生表(多类)
class Student(models.Model):
Name = mdoels.CharField(max-length=20)
# 在多类中定义外键,关联到班级表
Clas = models.ForeignKey('Cls')
# 定义班级表(一类)
class Cls(models.Model):
Name = models.CharField(max_length=20)
代码分析:
以上代码就创建了一个一对多的关系表。在多类中定义外键即可。外键中写上一类表的类名。
1、通过对象查询
通过对象查询时,首先拿到具体的对象,然后调用对象的方法来获取关联对象。
# 在交互式环境中输入以下代码
# 导入模块
from app.models import Student, Teacher
# 先添加班级数据,因为添加学生对象时需要给关系字段赋值班级对象
c1 = Cls.objects.create(Name='一班')
c2 = Cls.objects.create(Name='二班')
# 添加班级对象
s1 = Student.objects.create(Name='Jack', Clas=c1)
s2 = Student.objects.create(Name='Jerry', Clas=c2)
# 多类查询一类 —— 查询学生对相应的班级,使用关联字段查询
print(s1.Clas)
print(type(s1.Clas))
print(s2.Clas)
print(type(s2.Clas))
# 一类查询多类 —— 查询班级中所有的学生,使用内置的方法来查询
print(c1.student_set.all())
print(c1.student_set)
print(c2.student_set.all())
print(c2.student_set)
代码分析:
上面的代码中,添加数据后,通过具体的数据对象进行查询。查询的结果都是和该对象相关的结果。无论是正向查询还是反向查询,其结果都是活的关联对象或者查询集。
打印结果中可以发现一件事,学生查询到的结果是一个数据对象类型是班级类,而班级的查询类型是一个模型管理类。
上例中学生是多类,多个学生可以对应一个班级,因此使用对象进行关联查询时,获取的是一个具体的数据对象。
而班级是一类,一个班级中可以有多个学生,因此使用对象进行关联查询时,获取的是一个查询集。如果没有关联对象则返回空集。
2、通过类对象进行关联查询
使用对象进行关联查询时会有很大的局限性。因为只能查询到与该对象关联的数据对象,而很多时候我们要进行的查询会是大范围的查询。不能受到对象数量的限制。因此就需要使用到类对象的和关联查询。
# 使用类对象进行关联查询示例
# 查询班级中名字带有‘J’的学生
res = Student.objects.filter(Clas__Name__contains='J')
print(res)
# 查询Jack所在班级
res = Cls.objects.filter(student__Name__exact='Jack')
print(res)
代码分析:
使用类名进行查询时,语法 :
查询一类:一类名.objects.fliter(多类名__多类属性__筛选条件=值)
查询多类:多类名.objects.filter(关联字段__一类属性__筛选条件=值)
查询谁,就调用谁的数据模型管理器对象。
删除多类的数据时,不会影响到一类的数据,但是当删除一类的数据时,会将与之关联的数据也一并删除。因为多类是依赖于一类。此外,在定义外键时,必须指定默认值或者指定可以为空值,否则会无法迁移数据。
class Student(models.Model):
Name = models.CharField(max_length=20)
Teach_by = ManyToManyField('Teacher', null=True)
def __str__(self):
return self.Name
class Teacher(models.Model):
Name = models.CharField(max_length=20)
def __str__(self):
return self.Name
创建了多对多的关系后,回自动生成第三张表用来表示两张表之间的关系。当删除了某一个数据时,与之相关联的数据对象的关联字段会被设置为空。
删除数据不会影响另一张表中的数据。删除数据仅仅是在第三张表中进行联系的删除,而不会删除相关联的数据。
自关联就是自己关联自己。看上去就像是在操作两张表一样。
自关联的设置方式和多张表之间的设置一样,只是设置的类属性变成了‘self’。表示关联的对象为自身。
自关联关系 | moels语法 | 注释 |
---|---|---|
一对一 | models.OneToOneField('self') | 查询时均使用关联字段查询 |
一对多 | mdoels.ForeignKey('self') | 查询时均使用关联字段查询 |
多对多 | models.ManyToManyField('self') | 查询时均使用关联字段查询 |
由于共用了一张表,因此在查询时,均可以使用关联字段进行查询,也可以使用 类名.objects.filter(类名__属性__条件=值) 的方式。
自关联的关系创建
# 定义数据模型
class Area(models.Model):
Name = models.CharField(max_length)
# 定义一对一的自关联
# Above = models.OneToOneField('self', null=True)
# 定义一对多的自关联
# Above = models.OneToManyField('self', null=True)
# 定义多对多的自关联
# Above = models.ManyToManyField('self', null=True)