day8关联对象操作于多表查询 有问题待解决
一对多
正向(定义外键的一方)
一个模型如果有一个外键字段,通过这个模型对外键的操作叫做正向
更新
# 创建一个渠道 ch = Channel(name='小红书') ch.save() # 第一种通过属性方式赋值 s1 = Student.objects.get(name='tom') s1.channel = ch s1.save() # 第二种通过主键的赋值方式 s1 = Student.objects.get(name="李大毛") ch = Channel.objects.get(name="小红书") s1.channel_id = ch.id s1.save()
注:只有当返回 <Student: 中欧>才有save方法,返回查询集<QuerySet [<Channel: 京东>, <Channel: 小红书>]>没有save方法
删除
如果一个外键字段有null=True的属性,我们可以指定外键字段=None来删除关系,没指定null=True的不能删除
s1.channel = None
s1.save()
查
# 查询所有百度渠道的学生 # 正向查询 Student.objects.filter(channel__name="百度") # 跨表查询 表名__属性名 # 反向查询 ch = Channel.objects.get(name="抖音") ch.student_set.all() # student_set是默认属性名,可以自定义更改 ch.students.all() # student_set更改成students后的查询
反向
一个模型如果被另一个模型外键关联,通过这个模型对关联它的模型进行操作叫做反向
模型A外键关联模型B,那么模型B的实例可以返回模型A的一个管理器
Student模型外键关联Channel模型,那么Channel模型的实例,默认情况下有一个属性student_set,它是一个student模型的管理器,这个属性名的规则是:模型名小写_set。
注意:模型名小写_set,这个属性名可以改
增
通过channel模型创建student模型的数据
ch.students.create(name="殷芝", age=25, sex=1)
增加多条数据
# 先使用切片查询出多条数据,然后使用add添加 s1,s2,s3 = Student.objects.all()[:3] ch.students.add(s1, s2, s3)
删除
1、从相关对象中移除指定的对象
# 从抖音删除学生1,2 ch.students.remove(s1, s2)
2、从相关对象中删除所有的对象
# 删除抖音所有学生 ch.students.clear()
改
替换对象
# 将s1,s2学生的渠道修改为抖音 ch = Channel.objects.get(name="抖音") s1, s2 = Student.objects.all()[:2] ch.studens.set([s1,s2])
查
差所有
# 小红书渠道的所有学生 ch = Channel.objects.get(name="小红书") ch.studens.all()
条件查询
# 查询抖音渠道下,叫tom的学生 ch = Channel.objects.get(name="抖音") ch.students.filter(name="tom")
注意:默认的管理器名字(student_set)可以更改,通过在外键字段上添加一个related_name的选项,可以修改默认管理器名字
class Student(models.Mode): ... channel = models.ForeignKey('Channel', on_delete=models.SET_NULL, null=True, verbose_name='渠道', help_text='渠道来源', related_name='students')
一对一
正向(定义onetoone字段的一方)
学生详情模型操作学生模型
s1 = Student.objects.get(name="李大毛") d1 = StudentDetail(city="深圳", company="跨越") # 属性赋值 d1.student = s1 d1.save() # id赋值 d1.student_id = s1_id d1.save()
反向 有问题
学生模型操作,学生详情模型
# 给学生s2添加学生详情 d2 = StudentDetail(city="深圳", company="大疆") d2.save() s1 = Student.objects.get(name="王玉") s1.studentdetail = d2 s1.save()
和一对多的区别:
反向模型实例上的字段不再是管理器,而是一个对象。并且字段名就是模型的小写
多对多(定义manytomany的一方)
多对多模型两端都可以获得另一端的管理器,原理类似,一对多
添加报名记录
# 给学生添加c1,c2课程 c1, c2 = Course.objects.all()[0:2] s1 = Student.objects.get(name="王玉") s1.course_set.add(c1, c2) # 给课程c1添加两名学生s1,s2 c1 = Course.objects.get(name="自动化测试") s1, s2 = Student.objects.all()[8:10] c1.students.add(s1, s2)
指定了第三表,还可以通过第三张表象一对多关系一样操作:
# 1. 创建一条报名记录,s1学生报名了c1这个课 s1 = Student.objects.get(name="李云龙") c1 = Course.objects.get(name="自动化测试") e1 = Entry() e1.student = s1 e1.course = c1 e1.save()
# 想查询所有报名了c1课程的学生 c1.students.all() # 想查询s1学生报名的所有的课程 s1.course_set.all()
跨表查询
在django的ORM中要跨表,只需要使用模型的相关字段名,并以双下划线分隔,直到你想要的字段为止
查询男生都报名了什么课程
Course.objects.filter(students__sex=1).distinct()
例如查询所有报名了python课程的学员
Student.objects.filter(course__name__contains='python')
查询,报名了python课程的百度渠道的学员
Student.objects.filter(course__name__contains='python', channel__name='百度')
查询,百度渠道的所有的订单
Entry.objects.filter(student__channel__name='百度')
执行原生SQL
1. 执行原生查询并返回模型实例
在管理器上调用raw()方法,用于执行远程SQL查询,返回模型实例:
Student.objects.raw('select * from tb_student where id=%s', params=(1,))
执行它会返回一个RawQuerySet
,实例,可以迭代获取对象
for stu in Student.objects.raw('select * from tb_student where id=%s', params=(2,)):
print(stu)
2. 直接执行自定义的SQL
from django.db import connection
def my_custom_sql():
with connection.cursor() as cursor:
cursor.execute('select * from tb_student where id=%s', [2])
row = cursor.fetchone()
return row
它返回的就是原始数据