Django关联关系查询

一对一Model ,有外键即设置关联关系的一方为从表,从表查主表为正向查询,反之。这里护照为从表,人为主表。

class Passport(models.Model): # 护照(从表)
note = models.CharField(max_length=20)
person = models.OneToOneField(to="Person",on_delete=models.CASCADE,null=True) #关系属性
class Meta:
db_table="t_passport"

class Person(models.Model): # 人(主表)
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta:
db_table="t_person"
注:不需要手动设置 person字段唯一,自动会设置为唯一

一对一 一个人一本护照

# 1.只查 单方数据 (与单表数据查询一致)
# 只查人的信息
ps = Person.objects.filter(name='Tom').values() # 自己查自己
print(ps)
# 只查 护照的信息
p1 = Passport.objects.all().values()
print(p1)
ps = Person.objects.filter(passport='1').values()
print(ps)

# 2.通过一方查另一方数据 (先获取一方数据,再通过它查询另一方)
# 查询 名字为tom的护照信息
p1 = Person.objects.get(name='Tom')
print(p1.passport.note) #反向查询 基于对象 类名小写
# 查询护照为美国的人的信息
ps = Passport.objects.get(note='美国')
print(ps.per_id, ps.per.name,ps.per.age) #正向查询 基于对象 直接调用外键

# 3.通过一方 查另一方 (查询条件是对方)
# 查询名字为tom的护照信息
p1 = Passport.objects.filter(per__name='Tom').values() #正向查询 基于字段 外键__字段
print(p1)
# 查询护照为美国的人的信息
p1 = Person.objects.filter(passport__note='美国').values() #反向查询 基于字段 类小写__字段
print(p1)
print(Person.objects.filter(passport__note='美国')) # QuerySet集合对象

# 4.保留双方数据 ()
# 查询名字为Tom的人信息 和 护照的信息
p1 = Person.objects.filter(name='Tom').values('name','age','passport__note') #反向查询 基于字段 类小写__字段
print(p1)
p1 = Passport.objects.filter(per__name='Tom').values('note','per__name','per__age','per_id') #正向查询 基于字段 外键__字段
print(p1)

一对一查询总结:

正向查询时,基于对象,对象.直接调用外键;基于字段 外键__字段

反向查询时,基于对象,对象.类名小写;基于字段 类小写__字段

感觉从表和主表查起来差不多。

一对多Model 货物为从表,种类为主表

class Category(models.Model): #种类(主表)
title = models.CharField(max_length=20)
note = models.CharField(max_length=20)
class Meta:
db_table="t_category"

class Goods(models.Model): #货物(从表)
title = models.CharField(max_length=20,unique=True)
price = models.FloatField()
cate = models.ForeignKey(to=Category,on_delete=models.CASCADE) #关系属性 主表删除后,从表中使用主表中数据的也会跟随一起删除
class Meta:
db_table = "t_goods"

# 1对多关系 Category(1):没有关系属性 Goods(*):其中有关系属性cate
# 一对多 查询 category主表 goods从表

# 1.只查询一方数据
# 只查 主表
c1 = Category.objects.filter(name='服装').values()
print(c1)
g1 = Goods.objects.filter(price=5000).values()
print(g1)

# 2.通过一方查询另一方 (先查询到一方数据,再通过它查询另一方)
# 查询服装类别为男装的 商品名称
c1 = Category.objects.get(name='服装')
print(c1.goods_set) # 查询也是一个集合 #反向查询 基于对象 对象.表名_set
print(c1.goods_set.all()) # 查询也是一个集合
# 查询 商品沙发所属的类别
g1 = Goods.objects.get(title='沙发')
print(g1.cate.name, g1.cate.note) #正向查询 基于对象 对象.外键.字段

# 3.通过一方查询另一方(查询条件是另一方)
# 查询 床 商品的 类别信息
c1 = Category.objects.filter(goods__title='床').values() #反向查询 基于字段 表名__字段
print(c1)
# 查询分类为 家居 类别的 商品信息
g1 = Goods.objects.filter(cate__name='家居').values() #正向查询 基于字段 外键__字段
print(g1)

# 4.保留双方数据
# 查询商品名称为 电视 的分类信息 和 商品信息
c1 = Category.objects.filter(goods__title='电视').values('name','note','goods__title','goods__price') #反向查询 基于字段 表名__字段
print(c1)
# 查询商品价格大于5000的商品的分类信息
c1 = Category.objects.filter(goods__price__gt=5000) #反向查询 基于字段 表名__字段
print(c1)
print(set(c1))

#注意在进行联合查询时,可能会由重复数据出现,解决:
list(set(Category.objects.filter(goods__price__gt=200)))

一对多总结:

正向查询时,基于对象,对象.外键.字段;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

多对多Model

class Student(models.Model): #学生(主表)
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta:
db_table="t_student"

class Course(models.Model): #课程(从表)
title = models.CharField(max_length=30)
expire = models.SmallIntegerField()
stu = models.ManyToManyField(to=Student) #关系属性
class Meta:
db_table="t_course"

# 多对多关系 Course:有对方关系属性students, Student:没有对方关系属性

# 1.只查询一方
# 查询学生 linda 学生信息
s1 = Student.objects.filter(name='Linda').values()
print(s1)
# 查询mysql课程信息
c1 = Course.objects.filter(title__icontains='MYSQL').values()
print(c1)

# 2.查询一方,通过它查询另一方
# 查询 学习mysql的学生信息
c1 = Course.objects.get(title='DJANGO')
print(c1.stu.all()) #正向查询 基于对象 对象.外键
# 查询 学生 linda 课程信息
s1 = Student.objects.get(name='Linda')
print(s1.course_set.all()) #反向查询 基于对象 对象.表名_set
print(s1.course_set.values())

# 3.通过一方 查询 另一方 (查询条件为对方)
# 查询 学生 linda 课程信息
c1 = Course.objects.filter(stu__name='Linda').values() #正向查询 基于字段 外键__字段
print(c1)
# 查询 学习mysql的学生信息
s1 = Student.objects.filter(course__title='PYTHON').values() #反向查询 基于字段 表名__字段
print(s1)


# 4.保留双方数据
# 查询学习django的学生信息 和 课程信息
s1 = Student.objects.filter(course__title='DJANGO').values('name','age','course__title','course__expire') #反向查询 基于字段 表名__字段
print(s1)
# 查询jack学习的课程信息 和 学生信息
c1 = Course.objects.filter(stu__name='Jack').values('title','expire','stu__age','stu__name') #正向查询 基于字段 外键__字段
print(c1)


#关联查询
Student.objects.filter(course__title__contains="h") #标题中含有"h"的课程中的学生 #反向查询 基于字段 表名__字段
Course.objects.filter(stu__name="zzz") #姓名为zzz的学生参加的课程 #正向查询 基于字段 外键__字段
Course.objects.filter(stu__age__gt=18) #年龄大于18的学生参加的课程 #正向查询 基于字段 外键__字段
坑:不能查具体某个字段

多对多总结:

正向查询时,基于对象,对象.外键;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

最后3个总结写在一起比较:

一对一查询总结:

正向查询时,基于对象,对象.直接调用外键;基于字段 外键__字段

反向查询时,基于对象,对象.类名小写;基于字段 类小写__字段

一对多总结:

正向查询时,基于对象,对象.外键.字段;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

多对多总结:

正向查询时,基于对象,对象.外键;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

最后总结,

基于对象的情况下,正向查询时基本一致,直接调用外键就好;反向查询时一对多和多对多,需要对象.表名_set调用。

基于字段的情况下,正向查询时,外键__字段;反向查询时,表名__字段。一对一可能为类名小写__字段。

原文地址:https://www.cnblogs.com/lag1/p/13821461.html