美文网首页Python_Django
Python(五十二)表关联对象及多表查询

Python(五十二)表关联对象及多表查询

作者: Lonelyroots | 来源:发表于2022-01-30 20:48 被阅读0次

    从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

    相关文章

      网友评论

        本文标题:Python(五十二)表关联对象及多表查询

        本文链接:https://www.haomeiwen.com/subject/gucckrtx.html