Python(五十二)表关联对象及多表查询
2022-01-30 本文已影响0人
Lonelyroots
从2021年9月2日发文至今,Python系列(包括代码在内)共计98896个字、五十二篇!
1. 关系表的数据操作
db_test/models.py:
# (七、常用查询及表关系的实现:4、表关系的实现;八、表关联对象及多表查询)
from django.db import models
# Create your models here.
# 学院表
class Department(models.Model):
d_id = models.AutoField(primary_key=True)
d_name = models.CharField(max_length=30,unique=True)
def __str__(self):
return f'd_id={self.d_id},d_name={self.d_name}'
# 学生表
class Student(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=30)
# 一对多关系,当删除学院时,隶属于该学院的学生对应学院的id号为null。当related_name取别名stu,在视图函数反向访问时,student_set可以用stu来代替
dept_id = models.ForeignKey('Department',on_delete=models.SET_NULL,null=True,related_name='stu') # 外键在数据库中显示会自动添加_id
def __str__(self):
return f's_id={self.s_id},s_name={self.s_name},dept_id={self.dept_id}'
# 学生详情表
class StuDetail(models.Model):
stu_id = models.AutoField(primary_key=True)
stu_age = models.IntegerField()
stu_sex = models.BooleanField(default=1)
intro = models.TextField(null=True)
# 一对一关系,在删除学生的同时,删除该学生的详情
s_id = models.OneToOneField('Student',on_delete=models.CASCADE)
def __str__(self):
return f'stu_id={self.stu_id},stu_age={self.stu_age},stu_sex={self.stu_sex},intro={self.intro}'
# 课程表
class Course(models.Model):
c_id = models.AutoField(primary_key=True)
c_name = models.CharField(max_length=30,unique=True)
# 多对多关系,关系创建成功,中间表自动生成。
stu_course = models.ManyToManyField('Student')
def __str__(self):
return f'c_id={self.c_id},c_name={self.c_name}'
db_test/views.py:
# (八、表关联对象及多表查询)
from django.http import HttpResponse
from .models import Department,Student,StuDetail,Course
# 反向访问用连接字段,正向访问用别名或者表_set。
def add(request):
# # 学院表
# Department.objects.create(d_id=1,d_name='航空工程学院') # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# Department.objects.create(d_id=2,d_name='商学院')
# Department.objects.create(d_id=3,d_name='医学院')
# Department.objects.create(d_id=4,d_name='建筑工程学院')
# Department.objects.create(d_id=5,d_name='管理学院')
# return HttpResponse('学院数据添加成功!')
# # 学生表
# Student.objects.create(s_id=1,s_name='德芙',dept_id_id=2) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# Student.objects.create(s_id=2,s_name='疾风',dept_id_id=2) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# Student.objects.create(s_id=3,s_name='切克',dept_id_id=3)
# Student.objects.create(s_id=4,s_name='摸鱼',dept_id_id=4)
# Student.objects.create(s_id=5,s_name='流星',dept_id_id=5)
# Student.objects.create(s_id=6,s_name='无某人',dept_id_id=4)
# Student.objects.create(s_id=7,s_name='帅哥',dept_id_id=1)
# return HttpResponse('学生数据添加成功!')
# # 学生详情表
# StuDetail.objects.create(stu_id=1,stu_age=18,stu_sex=0,intro='德芙巧克力',s_id_id=1) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=2,stu_age=18,stu_sex=1,intro='疾风吹向大海',s_id_id=2) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=3,stu_age=19,stu_sex=1,intro='哟哟哟,切克闹',s_id_id=3) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=4,stu_age=18,stu_sex=0,intro='摸鱼上课就想着摸鱼',s_id_id=4) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=5,stu_age=20,stu_sex=0,intro='吾虽浪迹天涯,身后一许流星',s_id_id=5) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=6,stu_age=19,stu_sex=1,intro='无个人介绍',s_id_id=6) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=7,stu_age=25,stu_sex=0,intro='帅哥一枚',s_id_id=7) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# return HttpResponse('学生详情数据添加成功!')
# # 课程表
# Course.objects.create(c_id=1,c_name='形象设计与形体训练')
# Course.objects.create(c_id=2,c_name='有机化学')
# Course.objects.create(c_id=3,c_name='生物基础')
# Course.objects.create(c_id=4,c_name='细胞学')
# Course.objects.create(c_id=5,c_name='经济学')
# return HttpResponse('课程数据添加成功!')
# 学生课程中间表
# 获取学生对象
s1 = Student.objects.get(s_id=1)
s2 = Student.objects.get(s_id=2)
s3 = Student.objects.get(s_id=3)
# 获取课程对象
c1 = Course.objects.get(c_id=1)
c2 = Course.objects.get(c_id=2)
c3 = Course.objects.get(c_id=3)
# 给学生分配课程
s1.course_set.add(c1,c2,c3) # 从学生表出发,没有任何一个字段可以直接关联课程表,这种称作反向访问
# 给课程安排学生
c1.stu_course.add(s2,s3) # 从课程表出发,有外键关联学生表,属于正向访问
# s2.course_set.create(c_name='Django框架') # 通过学生创建新课程,且让s2这名学生报名了课程
return HttpResponse('学生课程数据添加成功')
# d2 = Department.objects.get(d_id=2)
# d2.student_set.create(s_name='星星') # 反向访问
# return HttpResponse('学生学院数据添加成功')
db_test/urls.py:
# -*- coding: utf-8 -*-
# @Time : 2022/1/28 22:23
# @Author : Lonelyroots
# @Email : Lonelyroots@qq.com
# @File : urls.py
# @Software : PyCharm
# (八、表关联对象及多表查询)
from django.urls import path
# 从同级目录下导入文件
from . import views
urlpatterns = [
path('add/',views.add),
path('query/',views.query),
path('update/',views.update),
path('delete/',views.delete),
path('find/',views.find),
]
2. 表关联对象的访问
2.1. 表关联对象的访问方式:
db_test/models.py:
# (七、常用查询及表关系的实现:4、表关系的实现;八、表关联对象及多表查询)
from django.db import models
# Create your models here.
# 学院表
class Department(models.Model):
d_id = models.AutoField(primary_key=True)
d_name = models.CharField(max_length=30,unique=True)
def __str__(self):
return f'd_id={self.d_id},d_name={self.d_name}'
# 学生表
class Student(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=30)
# 一对多关系,当删除学院时,隶属于该学院的学生对应学院的id号为null。当related_name取别名stu,在视图函数反向访问时,student_set可以用stu来代替
dept_id = models.ForeignKey('Department',on_delete=models.SET_NULL,null=True,related_name='stu') # 外键在数据库中显示会自动添加_id
def __str__(self):
return f's_id={self.s_id},s_name={self.s_name},dept_id={self.dept_id}'
# 学生详情表
class StuDetail(models.Model):
stu_id = models.AutoField(primary_key=True)
stu_age = models.IntegerField()
stu_sex = models.BooleanField(default=1)
intro = models.TextField(null=True)
# 一对一关系,在删除学生的同时,删除该学生的详情
s_id = models.OneToOneField('Student',on_delete=models.CASCADE)
def __str__(self):
return f'stu_id={self.stu_id},stu_age={self.stu_age},stu_sex={self.stu_sex},intro={self.intro}'
# 课程表
class Course(models.Model):
c_id = models.AutoField(primary_key=True)
c_name = models.CharField(max_length=30,unique=True)
# 多对多关系,关系创建成功,中间表自动生成。
stu_course = models.ManyToManyField('Student')
def __str__(self):
return f'c_id={self.c_id},c_name={self.c_name}'
下方views.py代码中如果有涉及到反向访问则用连接字段,正向访问用别名或者表_set。
db_test/views.py:
# (八、表关联对象及多表查询)
from django.http import HttpResponse
from .models import Department,Student,StuDetail,Course
# 反向访问用连接字段,正向访问用别名或者表_set。
def add(request):
# # 学院表
# Department.objects.create(d_id=1,d_name='航空工程学院') # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# Department.objects.create(d_id=2,d_name='商学院')
# Department.objects.create(d_id=3,d_name='医学院')
# Department.objects.create(d_id=4,d_name='建筑工程学院')
# Department.objects.create(d_id=5,d_name='管理学院')
# return HttpResponse('学院数据添加成功!')
# # 学生表
# Student.objects.create(s_id=1,s_name='德芙',dept_id_id=2) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# Student.objects.create(s_id=2,s_name='疾风',dept_id_id=2) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# Student.objects.create(s_id=3,s_name='切克',dept_id_id=3)
# Student.objects.create(s_id=4,s_name='摸鱼',dept_id_id=4)
# Student.objects.create(s_id=5,s_name='流星',dept_id_id=5)
# Student.objects.create(s_id=6,s_name='无某人',dept_id_id=4)
# Student.objects.create(s_id=7,s_name='帅哥',dept_id_id=1)
# return HttpResponse('学生数据添加成功!')
# # 学生详情表
# StuDetail.objects.create(stu_id=1,stu_age=18,stu_sex=0,intro='德芙巧克力',s_id_id=1) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=2,stu_age=18,stu_sex=1,intro='疾风吹向大海',s_id_id=2) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=3,stu_age=19,stu_sex=1,intro='哟哟哟,切克闹',s_id_id=3) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=4,stu_age=18,stu_sex=0,intro='摸鱼上课就想着摸鱼',s_id_id=4) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=5,stu_age=20,stu_sex=0,intro='吾虽浪迹天涯,身后一许流星',s_id_id=5) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=6,stu_age=19,stu_sex=1,intro='无个人介绍',s_id_id=6) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# StuDetail.objects.create(stu_id=7,stu_age=25,stu_sex=0,intro='帅哥一枚',s_id_id=7) # 插入数据的字段都需要与数据库中的字段相同,而不是与模型类中的属性相同
# return HttpResponse('学生详情数据添加成功!')
# # 课程表
# Course.objects.create(c_id=1,c_name='形象设计与形体训练')
# Course.objects.create(c_id=2,c_name='有机化学')
# Course.objects.create(c_id=3,c_name='生物基础')
# Course.objects.create(c_id=4,c_name='细胞学')
# Course.objects.create(c_id=5,c_name='经济学')
# return HttpResponse('课程数据添加成功!')
# 学生课程中间表
# 获取学生对象
s1 = Student.objects.get(s_id=1)
s2 = Student.objects.get(s_id=2)
s3 = Student.objects.get(s_id=3)
# 获取课程对象
c1 = Course.objects.get(c_id=1)
c2 = Course.objects.get(c_id=2)
c3 = Course.objects.get(c_id=3)
# 给学生分配课程
s1.course_set.add(c1,c2,c3) # 从学生表出发,没有任何一个字段可以直接关联课程表,这种称作反向访问
# 给课程安排学生
c1.stu_course.add(s2,s3) # 从课程表出发,有外键关联学生表,属于正向访问
# s2.course_set.create(c_name='Django框架') # 通过学生创建新课程,且让s2这名学生报名了课程
return HttpResponse('学生课程数据添加成功')
# d2 = Department.objects.get(d_id=2)
# d2.student_set.create(s_name='星星') # 反向访问
# return HttpResponse('学生学院数据添加成功')
def query(request):
# # 一对多表属性访问
# s1 = Student.objects.get(s_id=1) # 1号学生
# d1 = Department.objects.get(d_id=1) # 1号学院
# # 正向访问,查找1号学生报名的学院名
# res = s1.dept_id.d_name
# # 反向访问,查询1号学院的第一个学生
# res = d1.stu.all()[0] # 因为模型类中的学生表外键related_name取了别名stu,所以student_set可以用stu来代替
# res = d1.stu.all()[0].s_name
# print(res)
# return HttpResponse('查询成功!')
# # 一对一表属性访问
# sd1 = StuDetail.objects.get(stu_id=1)
# s1 = Student.objects.get(s_id=1)
# # 查询第一个学生详情的学生名字 正向访问
# res = sd1.s_id.s_name
# # 查询第一个学生的学生详情,一对一表属性反向访问不需要 _set与all()
# res = s1.studetail
# print(res)
# return HttpResponse('查询成功!')
# 多对多表属性访问
c1 = Course.objects.get(c_id=1)
s1 = Student.objects.get(s_id=1)
# 查询1号学生报名的课程,正向访问
res = s1.course_set.all()
# 查询1号课程有哪些学生报名,反向访问
res = c1.stu_course.all()
print(res)
return HttpResponse('查询成功!')
def update(request):
d1 = Department.objects.get(d_id=1)
s2 = Student.objects.get(s_id=2)
# 将2号学生移到1号学院
# 反向访问,取了个别名stu
d1.stu.add(s2)
return HttpResponse('修改成功!')
def delete(request):
s1 = Student.objects.get(s_id=1)
c1 = Course.objects.get(c_id=1)
c3 = Course.objects.get(c_id=3)
# 删除1号学生所报名的3号课程数据
s1.course_set.remove(c3)
# 清空1号学生报名的所有课程数据
s1.course_set.clear()
# 清空1号课程里面的所有学生数据
c1.stu_course.clear()
return HttpResponse('删除成功!')
db_test/urls.py:
# -*- coding: utf-8 -*-
# @Time : 2022/1/28 22:23
# @Author : Lonelyroots
# @Email : Lonelyroots@qq.com
# @File : urls.py
# @Software : PyCharm
# (八、表关联对象及多表查询)
from django.urls import path
# 从同级目录下导入文件
from . import views
urlpatterns = [
path('add/',views.add),
path('query/',views.query),
path('update/',views.update),
path('delete/',views.delete),
path('find/',views.find),
]
3. 多表查询
db_test/models.py:
# (七、常用查询及表关系的实现:4、表关系的实现;八、表关联对象及多表查询)
from django.db import models
# Create your models here.
# 学院表
class Department(models.Model):
d_id = models.AutoField(primary_key=True)
d_name = models.CharField(max_length=30,unique=True)
def __str__(self):
return f'd_id={self.d_id},d_name={self.d_name}'
# 学生表
class Student(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=30)
# 一对多关系,当删除学院时,隶属于该学院的学生对应学院的id号为null。当related_name取别名stu,在视图函数反向访问时,student_set可以用stu来代替
dept_id = models.ForeignKey('Department',on_delete=models.SET_NULL,null=True,related_name='stu') # 外键在数据库中显示会自动添加_id
def __str__(self):
return f's_id={self.s_id},s_name={self.s_name},dept_id={self.dept_id}'
# 学生详情表
class StuDetail(models.Model):
stu_id = models.AutoField(primary_key=True)
stu_age = models.IntegerField()
stu_sex = models.BooleanField(default=1)
intro = models.TextField(null=True)
# 一对一关系,在删除学生的同时,删除该学生的详情
s_id = models.OneToOneField('Student',on_delete=models.CASCADE)
def __str__(self):
return f'stu_id={self.stu_id},stu_age={self.stu_age},stu_sex={self.stu_sex},intro={self.intro}'
# 课程表
class Course(models.Model):
c_id = models.AutoField(primary_key=True)
c_name = models.CharField(max_length=30,unique=True)
# 多对多关系,关系创建成功,中间表自动生成。
stu_course = models.ManyToManyField('Student')
def __str__(self):
return f'c_id={self.c_id},c_name={self.c_name}'
db_test/views.py:
# (八、表关联对象及多表查询)
from django.http import HttpResponse
from .models import Department,Student,StuDetail,Course
# 反向访问用连接字段,正向访问用别名或者表_set。
# 多表查询
def find(request):
# 查询商学院的所有学生信息,__左边是连接对应表的字段,右边是查询的条件,从商学院出发,反向访问。
res = Student.objects.filter(dept_id__d_name='商学院')
# 查询学生名字中有“鱼”的学生的学院信息,从学生出发,正向访问。
res = Department.objects.filter(stu__s_name__contains='鱼')
# 查询隶属于商学院并且报名Django框架课程的学生信息,从商学院出发,反向访问,从课程出发,正向访问,两个条件时不需要表_set,写表即可。
res = Student.objects.filter(dept_id__d_name='商学院',course__c_name='Django框架')
# 查询隶属于商学院并报名了生物基础课程的学生信息
res = Student.objects.filter(dept_id__d_name='商学院',course__c_name='生物基础')
# 查询隶属于商学院并报名了生物基础课程的学生详情。(需要借助中间表)
# 先反向访问:从学院出发,学院表先通过dept_id去找学生表;而后反向访问:学生表再通过s_id连接上了学生详情表,去查询学生详情。
# 先正向访问:从课程出发,课程表先通过course去找学生表;而后反向访问:学生表再通过s_id连接上了学生详情表,去查询学生详情。
res = StuDetail.objects.filter(s_id__dept_id__d_name='商学院',s_id__course__c_name='生物基础')
print(res)
return HttpResponse("查询成功!")
db_test/urls.py:
# -*- coding: utf-8 -*-
# @Time : 2022/1/28 22:23
# @Author : Lonelyroots
# @Email : Lonelyroots@qq.com
# @File : urls.py
# @Software : PyCharm
# (八、表关联对象及多表查询)
from django.urls import path
# 从同级目录下导入文件
from . import views
urlpatterns = [
path('add/',views.add),
path('query/',views.query),
path('update/',views.update),
path('delete/',views.delete),
path('find/',views.find),
]
文章到这里就结束了!希望大家能多多支持Python(系列)!六个月带大家学会Python,私聊我,可以问关于本文章的问题!以后每天都会发布新的文章,喜欢的点点关注!一个陪伴你学习Python的新青年!不管多忙都会更新下去,一起加油!
Editor:Lonelyroots