1、一对一关系
比如某班级学生表和学生详细信息表两张表结构如下
class Student(models.Model):
stu_id = models.AutoField(primary_key=True)
stu_name = models.CharField(max_length=32)
class StudentDetail(models.Model):
stu_detail_id = models.AutoField(primary_key=True)
height = models.PositiveIntegerField(null=True)
#设置一对一关系
stu = models.OneToOneField('Student', on_delete=models.CASCADE, to_field='stu_id', null=True)
在这里主表为Student,子表为StudentDetail(即包含外键的表)
通过子表查询主表为正向查询,代码如下
#实例化获取数据
stu = StudentDetail.objects.get(pk=1)
#打印Student表中的stu_name字段
print(stu.stu_name)
通过主表查询子表为反向查询,代码如下
(系统会自动创建一个 类名小写的字段对象)
# 系统会自动创建一个 类名小写的字段对象
stu = Student.objects.get(pk=1)
# 类名字的小写
print(stu.studentdetail.height)
2、一对多关系
一对多关系可如此理解: 一个班级中有多个学生,但一个学生并不同时属于多个班级此处班级表为“一”,学生表为“多”
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 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]
正向查询和一对一相同
反向查询如下
(1、系统会自动创建一个 "类名小写_set"的字段对象)
(2、通过正向查询关键字段+双下划线__+“一”表中的字段)
#第一种方法
class = ClassRoom.objects.get(pk=1)
stu_list = class.student_set.all()
#第二种方法
stu_list = Student.objects.filter(cid__cname="英语")
3、多对多关系
一本书有多个作者,某位作者出版了多本书class Book(models.Model):
name = models.CharField(
max_length=23
)
price = models.FloatField()
class Author(models.Model):
name = models.CharField(
max_length=30,
verbose_name="人名"
)
books = models.ManyToManyField(
Book,
verbose_name="书籍"
)
通过书籍查找作者(__set方法)
book = Book.objects.all().first() #先获取一本书
authors = book.author_set.all() #通过数据获取
通过作者查找书籍
author = Author.objects.all().first()
books = author.books.all()
查询优化(适用于一对一和一对多)
比如查看所有学生的班级名字普通查询方法:
student = Student.objects.all()
for i in student:
print(i.cid.cname)
这样会导致线性的SQL查询,如果对象数量n太多,每个对象中有k个外键字段的话,就会导致n*k+1次SQL查询。可以采用select_related减少查询次数:
student = Student.objects.select_related("cid").all()
for i in student:
print(i.cid.cname)
只有一次查询
适用于多对多
查看所有作者写的所有书名books = Author.objects.prefetch_related("books").all()
for i in books:
print(i.books.name)