Python_Django

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

上一篇下一篇

猜你喜欢

热点阅读