web后端Django-前戏3关联表操作

操作背景:是在前戏2中已经创建有学生表,同时也完成了单表的查询,此篇的目的是创建关联表以及相关的关联操作

1.创建拓展表(一对一)

  • 工程文件夹下app下modles.py
    class StudentInfo(models.Model):
      s_no = models.CharField(max_length=10,null=False)
      phone = models.CharField(max_length=11,null=True)
      name = models.CharField(max_length=10,null=True)
      #定义一对一的关联关系
      # on_delete:
      # models.CASCADE:删除主表,从表也会被删除
      # models.PROTECT:都会被保护,但是从表可以删除
      # models.SET_NULL:主表被删除,从表的外键设置为空
      stu = models.OneToOneField(Student,
                                on_delete=models.SET_NULL,
                                related_name='info',
                                null=True)
    
  • 对表做修改以及添加新表后都需要迁移文件,在终端中执行代码进行迁移命令
    • python manage.py makemigrations
    • python manage.py migrate

      先观察数据库

      查看当前数据库中有哪些表格查看图片如下:
      (/images/stu_orige.png)

      1.添加学生拓展表信息

      进入urls.py添加路由

      path('add_stu_info/',views.add_stu_info),
      

      进入views.py创建拓展信息表

  • 方法一:
      stu_info = StudentInfo()
      stu_info.s_no = '123456'
      stu_info.phone = '18328099786'
      stu_info.name = '小花22'    #此处模型中定义为紧急联系人
      stu_info.stu = Student.objects.get(id=4) # 获取学生对象进行关联
      stu_info.save()
      return HttpResponse('创建拓展信息成功')
    
  • 方法二:
      stu_info = StudentInfo()
      stu_info.s_no = '123456'
      stu_info.phone = '18328099786'
      stu_info.name = '小花22'
      stu_info.stu_id = 5
      stu_info.save()
      return HttpResponse('创建拓展信息成功')
    

    (1)通过学生对象查询拓展表信息

    此处用于区分关联时id的写法
  • (1)创建路由
    path('sel_phone_by_stu/',views.sel_phone_by_stu),
    
  • (2)在views中写代码查询,方法一
    def sel_phone_by_stu(request):
      # 1.查询学生对象
      stu = Student.objects.filter(s_name='小花').first()
      stu_info = StudentInfo.objects.filter(stu_id=stu.id).first() #在获取学生对象之后关联到StudentInfo;
      phone = stu_info.phone
      print(phone)
      return  HttpResponse('查询成功')
    
  • (2)在views中写代码查询,方法二
    def sel_phone_by_stu(request):
      stu = Student.objects.filter(s_name='小花').first()
      stu_info = StudentInfo.objects.filter(stu=stu).first()
      phone = stu_info.phone
      print(phone)
      return  HttpResponse('查询成功')
    

    (2)通过学生对象查询拓展表信息

    此处用于区分关联时有无关联名称是的写法
  • (1)创建路由,在urls.py中
    path('sel_phone_by_stu2/',views.sel_phone_by_stu2),
    
  • 没有关联名称时即》》在模型中拓展表的stu没有字段related_name=’info’,
      stu = models.OneToOneField(Student,on_delete=models.SET_NULL,null=True)
    
    此时的查询代码为:
    def sel_phone_by_stu2(request):
      # 1.查询学生对象
      stu = Student.objects.filter(s_name='小花').first()
      # 2.反向查询,关联模型对象,关联另外一个模型名称的小写
      stu_inifo = stu.studentinfo
      phone = stu_inifo.studentinfo
      print(phone)
      return HttpResponse('查询成功,没有关联名称')
    
  • 关联名称时即》》在模型中拓展表的stu字段有related_name=’info’,
    def sel_phone_by_stu2(request):
      # 1.查询学生对象
      stu = Student.objects.filter(s_name='小花').first()
      # 2.反向查询,直接学生对象到关联名称的名
      stu_inifo = stu.info
      phone = stu_inifo.phone
      print(phone)
      return HttpResponse('查询成功,有关联名称的查询')
    

    (3)通过拓展表查询学生信息

  • (1)创建路由,urls中
    path('sel_stu_by_info/',views.sel_stu_by_info),
    
  • (2)先在拓展表中取出对象,关联到stu字段中,因为彼此为一对一对应的
    def sel_stu_by_info(request):
      stu_info = StudentInfo.objects.filter(s_no='123456').first()
      stu = stu_info.stu
      print(stu.s_name)
      return HttpResponse('查询成功,拓展表查询学生对象。')
    

    2 删除学生信息

  • (1)创建路由
    path('on_delete_stu/',views.on_delete_stu),
    
    注意:在定义一对一的关联关系时,需要顶底on_delete的值
  • models.CASCADE:删除主表,从表也会被删除
    • models.PROTECT:都会被保护,但是从表可以删除
    • models.SET_NULL:主表被删除,从表的外键设置为空
      def on_delete_stu(request):
      # 删除小花的学生信息
      #删除小花信息,从表是否删除
      Student.objects.filter(s_name='小花2').delete()
      return HttpResponse('删除成功')
      

      2班级表(一对多)

      (1)创建班级表

  • 1在models.py文件中写入代码
    class Grade(models.Model):
      g_name = models.CharField(max_length=10,unique=True)
      class Meta:  #此处的是定义表名
          db_table = 'grade'
    
  • (1)在前戏2中所创建的student类中
    • 一对多的外键定义
      g = models.ForeignKey(Grade,null=True,on_delete=models.CASCADE,
                            related_name='stu')
      
      注意添加外键后要做迁移命令

      (2)添加班级信息

  • 创建路由一对多操作,添加班级信息
    path('add_grade/',views.add_grade),
    
  • 1.添加方法一
      for i in range(1,5):
      grade = Grade()
          grade.g_name = 'java180'+str(i)
          grade.save()
    
  • 2.添加方法二
    def add_grade(requset):
    for i in range(1,5):
      Grade.objects.create(g_name='python180'+str(i))
    return HttpResponse('添加成功')
    

    (3)给学生分配班级信息

  • 1.创建路由
    path('stu_grade/',views.stu_grade),
    
  • 2.分配班级(两种方法)查询id=6的对象(对id为6的学生分配班级)
    def stu_grade(requset):
      stu = Student.objects.get(pk=6)
      #
      # stu.g = Grade.objects.get(pk=1)
      stu.g_id = 4
      stu.save()
      return HttpResponse('分配班级成功')
    

    3.一对多的表单查询

    (1)通过学生查询班级

  • 创建路由
    path('sel_grade_by_stu/',views.sel_grade_by_stu),
    
  • 查询方法
    def sel_grade_by_stu(request):
      # 1.查询姓名叫小明的对象
      stu =  Student.objects.filter(s_name='小明').first()
      grade = stu.g  #此处添加了一对多的外键,因此可以得到班级的对象
      print(grade.g_name)
      return  HttpResponse('查询成功')
    

    (2)通过班级查询学生

  • 创建路由
    path('sel_stu_by_grade/',views.sel_stu_by_grade),
    
  • 查询方法一(没有创建关联名称的情况)
    def sel_stu_by_grade(request):
      grade = Grade.objects.filter(g_name='python1801').first()
      stus = grade.student_set.all()  #
      for stu in stus:
      print(stu.s_name,stu.s_age,stu.s_gender)
      return HttpResponse('查询学生成功,无关联名称')
    
  • 查询方法一(有创建关联名称的情况);即学生表中 g = models.ForeignKey(Grade,null=True,on_delete=models.CASCADE,related_name=’stu’)中有
    def sel_stu_by_grade(request):
      # 1.查询班级python1801
      grade = Grade.objects.filter(g_name='python1801').first()
      stus = grade.stu.all()
      for stu in stus:
          print(stu.s_name,stu.s_age,stu.s_gender)
      return HttpResponse('查询学生成功,有关联名称')
    

    4学生选课表(多对多)

    (1)创建选课表

  • 在models.py中写入代码创建选课表,同时在终端中做迁移。

    • 将会在数据库中多处一个course的 表
    • 同时会多出course_stu的表如下图
      (/images/manytomany.png)

      class Course(models.Model):
      c_name = models.CharField(max_length=10,unique=True)
      # ManyToManyField字段定义在任何一个模型都可以
      stu = models.ManyToManyField(Student,null=True,related_name='cou')
      
      class Meta:
          db_table = 'course'
      

      (2)添加课程信息

  • 创建路由
    path('add_course/',views.add_course),
    
  • 写入添加课程的方法一:
    def add_course(request):
      c_names = ['大学英语','商务英语','线代','高数']
      for i in c_names:
          course = Course()
          course.c_name =i
          course.save()
      return HttpResponse('添加课程成功')
    
  • 写入添加课程的方法二:
    def add_course(request):
      c_names = ['大学英语','商务英语','线代','高数']
      for i in c_names:
          Course.objects.create(c_name=i)
      return HttpResponse
    

    (3)给中间表添加信息(学生添加课程)

  • 创建路由
    path('add_s_c/',views.add_s_c),
    
    两种方法的区别就在关联关系这儿
  • 添加方法一:(无关联名称)
    def add_s_c(request):
      #1 查询课程对象
      cou = Course.objects.filter(c_name='商务英语').first()
      #2.查询学生对象
      stu = Student.objects.filter(s_name='lorry').first()
      # 3.加入关联关系
      stu.course_set.add(cou)
      return HttpResponse('添加中间信息表成功')
    
  • 添加方法二:(有关联名称cou)
    def add_s_c(request):
      #1 查询课程对象
      cou = Course.objects.filter(c_name='商务英语').first()
      #2.查询学生对象
      stu = Student.objects.filter(s_name='lorry').first()
      # 3.加入关联关系
      stu.cou.add(cou)   
      return HttpResponse('添加中间信息表成功')
    

    4.给中间表添加信息(课程添加学生)

    def add_s_c(request):
      #将大学英语分配给小明
      #1 查询课程对象
      cou = Course.objects.filter(c_name='商务英语').first()
      #2.查询学生对象
      stu = Student.objects.filter(s_name='lorry').first()
      cou.stu.add(stu)  #前面的stu是模型中定义的stu。
      return HttpResponse('添加中间信息表成功')
    

    5.删除中间表信息

  • 创建路由
    path('del_s_c/',views.del_s_c)
    
  • 写入方法
    def del_s_c(requset):
      cou = Course.objects.filter(c_name='商务英语').first()
      stu = Course.objects.filter(s_name='lorry').first()
      stu.cou.remove(cou)
      return HttpResponse('删除信息成功')
    

    5.模板(HTML的操作)

  • 创建路由
    path('index/',views.index)
    
    后续操作:
  • a:在工程文件中创建templates的文件夹
    • b:在文件夹中创建index.html文件
    • c:进入文件操作解析内容
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>Title</title>
      </head>
      <body>
      <p>欢迎lorry</p>
      {% for stu in a%}
          

      姓名:{{stu.s_name}} 年龄:{{stu.s_age}} 班级:{{ stu.g.g_name }} 选课: {% for c in stu.cou.all %} {{ c.c_name }} {% endfor %} </p> {% endfor %} </body> </html>


上一篇
web后端Django-高潮3中间件 web后端Django-高潮3中间件
前言面向切面编程AOP中的中间件是一个最好的例子。官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。 1. 中间件Middleware描述
2019-01-09
下一篇
web后端Django-前戏之数据库增删改查 web后端Django-前戏之数据库增删改查
概念引入ORM(objects relationship mapping): 对象关系映射;objects: 管理器,默认模型的属性; 1.数据增加中间表(即自己需要管理的表)举例操作:创建一张学生表,包含名字,性别,年龄,创立日期以及更新
2019-01-03