表关系的实现

 

预备知识

ORM的正向操作和反向操作:

1.正向操作:一个模型中定义了一个外键,通过该模型对该外键操作的操作叫做正向操作。

2.反向操作:被外键所关联的模型,通过该模型对外键所在模型的操作叫做反向操作。

 

表关系的操作

我们通过下面的案例,来了解表关系的操作

首先我们需要几张表:学生表,学生信息表,班级表,报名表,课程表

他们的关系是:学生表和学生信息表  一对一

       班级表和学生表         一对多

       学生表和课程表         多对多

下面是Django 模型代码:

学生表

  1. from django.db import models
  2. class Student(models.Model):
  3. name = models.CharField(max_length=20)
  4. age = models.SmallIntegerField(default=0)
  5. sex = models.SmallIntegerField(default=1)
  6. # 班级和学生之间是一对多的关系,不可执行级联删除,所以置空
  7. grade = models.ForeignKey('Grade', on_delete=models.SET_NULL, null=True)
  8. qq = models.CharField(max_length=20, default='')
  9. phone = models.CharField(max_length=20, default='')
  10. c_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
  11. def __str__(self):
  12. return '<Student:名字:%s,年龄:%s>' % (self.name, self.age)

 学生信息表

  1. class StudentDetail(models.Model):
  2. num = models.CharField(max_length=20, default='')
  3. college = models.CharField(max_length=20, default='')
  4. # 学生与学生详情表 一对一关系,执行联级删除
  5. student = models.OneToOneField('Student', on_delete=models.CASCADE)

班级表

  1. class Grade(models.Model):
  2. name = models.CharField(max_length=20)
  3. num = models.CharField(max_length=20)
  4. def __str__(self):
  5. return '<Grade:班级:%s,班号:%s>' % (self.name, self.num)

课程表

  1. class Course(models.Model):
  2. name = models.CharField('课程名称', max_length=20)
  3. # 科目和学生之间是多对多的关系,一般我们都要指定他们之间的 中间表
  4. students = models.ManyToManyField('Student', through='Enroll')
  5. def __str__(self):
  6. return '<Course: 科目:%s>' % self.name

中间表:报名表

  1. class Enroll(models.Model):
  2. student = models.ForeignKey('Student', on_delete=models.CASCADE)
  3. course = models.ForeignKey('Course', on_delete=models.CASCADE)
  4. pay = models.CharField(max_length=20, default='')
  5. c_time = models.DateTimeField('报名时间', auto_now_add=True)
  6. def __str__(self):
  7. return '报名表:学生:%s 科目:%s 缴费金额:%s 报名时间:%s' % (self.student, self.course, self.pay, self.c_time)

注释:在使用外键关联时,需要加入on_delete()参数,此参数为了避免俩个表的数据不一致问题;modles.CASCADE 表示级联删除,models.SET_NULL 表示主表不级联删除,置空。

一对多:班级只有一个,但每个班级有多个学生

首先在俩个表中分别插入俩个值:

  1. #进入Django的交互模式
  2. python manage.py shell
  3. In [1]: from teacher.models import Student,StudentDetail,Grade,Enroll,Course
  4. In [2]: g1=Grade.objects.create(name='django',num='33期')
  5. In [3]: g2=Grade.objects.create(name='爬虫',num='34期')
  6. In [6]: s1=Student.objects.create(name='cmx',grade=g1)
  7. In [7]: s2=Student.objects.create(name='cmx01',grade=g2)

正向操作:

  1. In [8]: s1.grade
  2. Out[8]: <Grade: <Grade:班级:django,班号:33期>>
  3. In [9]: s1.grade.name
  4. Out[9]: 'django'
  5. In [10]: s1.grade.num
  6. Out[10]: '33期'

反向操作:借用Django的反向管理器(外键所在模型的小写+‘_set’,就相当于‘objects’)

  1. ##增加(俩个方法都是立刻执行)
  2. s3=Student.objects.create(name='cmx02',grade=g2)
  3. #create方法
  4. In [20]: g1.student_set.create(name='cmx')
  5. Out[20]: <Student: <Student:名字:cmx,年龄:0>>
  6. #add方法
  7. In [21]: g1.student_set.add(s2)
  8. #增加后查询检测
  9. In [22]: g1.student_set.all()
  10. Out[22]: <QuerySet [<Student: <Student:名字:cmx01,年龄:0>>, <Student: <Student:名字:cmx,年龄:0>>]>
  11. #add特性:若添加已经有班级的值,会解除原来的关系,将其并入到自己中来,原属班级的该成员被清空。
  12. In [27]: g1.student_set.add(s3)
  13. In [28]: g1.student_set.all()
  14. Out[28]: <QuerySet [<Student: <Student:名字:cmx01,年龄:0>>, <Student: <Student:名字:cmx02,年龄:0>>, <Student: <Student:名字:cmx,年龄:0>>]>
  15. In [29]: s3.grade
  16. Out[29]: <Grade: <Grade:班级:django,班号:33期>>
  17. In [30]: g2.student_set.all()
  18. Out[30]: <QuerySet []>
  19. ##查询
  20. In [31]: g1.student_set.all()
  21. Out[31]: <QuerySet [<Student: <Student:名字:cmx01,年龄:0>>, <Student: <Student:名字:cmx02,年龄:0>>, <Student: <Student:名字:cmx,年龄:0>>]>
  22. In [32]: g1.student_set.filter(name='cmx')
  23. Out[32]: <QuerySet [<Student: <Student:名字:cmx,年龄:0>>]>
  24. ##删除
  25. #remove方法
  26. In [36]: g1.student_set.remove(s2)
  27. In [37]: g1.student_set.all()
  28. Out[37]: <QuerySet [<Student: <Student:名字:cmx02,年龄:0>>, <Student: <Student:名字:cmx,年龄:0>>]>
  29. #clear清空
  30. In [45]: g1.student_set.clear()
  31. In [46]: g1.student_set.all()
  32. Out[46]: <QuerySet []>
  33. ##修改set方法:先执行清空操作,之后再添加
  34. In [58]: g1.student_set.all()
  35. Out[58]: <QuerySet [<Student: <Student:名字:cmx,年龄:0>>, <Student: <Student:名字:cmx01,年龄:0>>, <Student: <Student:名字:cmx02,年龄:0>>]>
  36. In [59]: g1.student_set.set([s1,s2])
  37. In [60]: g1.student_set.all()
  38. Out[60]: <QuerySet [<Student: <Student:名字:cmx,年龄:0>>, <Student: <Student:名字:cmx01,年龄:0>>]>

 一对一:有一对一的表关系的俩表,通过对方模型的小写来相互访问,返回的是对象

  1. #创建一个学生详情
  2. In [61]: sd=StudentDetail.objects.create(num='',college='家里蹲',student=s1)
  3. In [62]: StudentDetail.objects.all()
  4. Out[62]: <QuerySet [<StudentDetail: <StudentDetail:学号:001,毕业院校:家里蹲>>]>
  5. #正向
  6. In [63]: sd.student
  7. Out[63]: <Student: <Student:名字:cmx,年龄:0>>
  8. #反向
  9. In [64]: s1.studentdetail
  10. Out[64]: <StudentDetail: <StudentDetail:学号:001,毕业院校:家里蹲>>

多对多:该关系的操作,俩端都可以自动的获取API访问,与其他关系不同的是它不需要Django提供的管理器,而是使用自己的属性字段。

首先建立几个课程:

  1. In [66]: c1=Course.objects.create(name='python全栈')
  2. In [67]: c2=Course.objects.create(name='java全栈')
  3. In [68]: c3=Course.objects.create(name='c++全栈')
  4. In [69]: Course.objects.all()
  5. Out[69]: <QuerySet [<Course: <Course: 科目:python全栈>>, <Course: <Course: 科目:java全栈>>, <Course: <Course: 科目:c++全栈>>]>

中间表添加数据:

  1. In [71]: Enroll.objects.create(student=s1,course=c1)
  2. Out[71]: <Enroll: 报名表:学生:<Student:名字:cmx,年龄:0> 科目:<Course: 科目:python全栈> 缴费金额: 报名时间:2019-03-05 08:18:41.163008+00:00>
  3. In [72]: Enroll.objects.create(student=s2,course=c2)
  4. Out[72]: <Enroll: 报名表:学生:<Student:名字:cmx01,年龄:0> 科目:<Course: 科目:java全栈> 缴费金额: 报名时间:2019-03-05 08:19:00.548559+00:00>
  5. In [73]: Enroll.objects.create(student=s1,course=c3)
  6. Out[73]: <Enroll: 报名表:学生:<Student:名字:cmx,年龄:0> 科目:<Course: 科目:c++全栈> 缴费金额: 报名时间:2019-03-05 08:19:12.081490+00:00>

正向查询:使用课程表的多对多字段名

  1. In [74]: c1.students.all()
  2. Out[74]: <QuerySet [<Student: <Student:名字:cmx,年龄:0>>]>

 反向查询:使用课程表明小写+‘_set’

  1. In [75]: s1.course_set.all()
  2. Out[75]: <QuerySet [<Course: <Course: 科目:python全栈>>, <Course: <Course: 科目:c++全栈>>]>

注释:

Course的多对多关系字段:students = models.ManyToManyField('Student', through='Enroll')

through这个字段就是指定了中间表的字段,当中间表被指定之后,add,remove,set  方法都不可用,无论正反向操作。

若是没有给定该字段,系统会自动创建一个中间表,上方的几个方法也可使用。

跨表查询

前提:跨表查询,所关联的表必须有一定的关系

方法:使用双下划线‘__’来达到所需条件的字段

案例:

1.查询所有Django班的学生信息

  1. In [76]: res=Student.objects.filter(grade__name__contains='django')
  2. In [78]: res
  3. Out[78]: <QuerySet [<Student: <Student:名字:cmx,年龄:0>>, <Student: <Student:名字:cmx01,年龄:0>>]>

2.查询男生都报名了那些课程

  1. In [80]: res=Course.objects.filter(students__sex=1)
  2. In [81]: res
  3. Out[81]: <QuerySet [<Course: <Course: 科目:python全栈>>, <Course: <Course: 科目:c++全栈>>, <Course: <Course: 科目:java全栈>>]>

综上俩点可以看出:学生表操作grade外键,课程表操作students外键,都属于正向操作,并且都使用已经定义好的外键原字段。

3.查询报名了python全栈的学生

分析:学生表和课程表 属于多对多,多对多的模型字段在课程表里,而我们要查的是学生,所以就是反向查询

反向查询所用的字段不是 模型的小写+’_set‘,而仅是模型的小写

  1. In [83]: res=Student.objects.filter(course__name__contains='python')
  2. In [84]: res
  3. Out[84]: <QuerySet [<Student: <Student:名字:cmx,年龄:0>>]>

4.查询报名了Java全栈 班级为33期的学生

分析:这是多条件查询,条件一:课程名为java全栈,条件二:班级的期数为33,所要查的学生

  1. In [89]: res=Student.objects.filter(course__name__contains='java',grade__num__contains='')
  2. In [90]: res
  3. Out[90]: <QuerySet [<Student: <Student:名字:cmx01,年龄:0>>]>

最后的日常技巧记录:django 删除表所有的数据:Student.objects.all().delete()

Django中的表关系实现及操作的更多相关文章

  1. django ORM中的表关系

    多对一: 为了方便理解,两个表之间使用ForeignKey连接时,使用ForeignKey的字段所在的表为从表,被ForeignKey连接的表为主表. 使用场景:书和出版社之间的关系,一本书只能由一个 ...

  2. Django中的表单

    目录 表单 Django中的表单 用表单验证数据 自定义验证 表单 HTML中的表单是用来提交数据给服务器的,不管后台服务器用的是 Django  还是 PHP还是JSP还是其他语言.只要把 inpu ...

  3. Django中多对多关系的orm表设计

    作者的管理 1.设计表结构 出版社 书籍 作者 一个出版社出版多个书籍  1对多 书籍和作者的关系:一个作者写多本书,一本书可以是多个作者写.多对多 1)创建一张表,表中多对多的数据关系.使用 多对多 ...

  4. Django中ORM表的创建以及基本增删改查

    Django作为重量级的Python web框架,在做项目时肯定少不了与数据库打交道,编程人员对数据库的语法简单的还行,但过多的数据库语句不是编程人员的重点对象.因此用ORM来操作数据库相当快捷.今天 ...

  5. django中form表单的提交:

    一,关于表单: 表单在百度百科的解释:   表单在网页中主要负责数据采集功能.一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法. 表单域 ...

  6. Django中多表查询思路

    需求: 1.有一张文章表和一张评论表 2.两张表的关系是一对多 3.规则:若是有新评论,则将对应的文章置顶,若是有新文章则将新文章置顶. 思路: 在文章表中增加一个最后评论时间的字段.然后采用分组排序 ...

  7. Django中的ORM关系映射查询方面

    ORM:Object-Relation Mapping:对象-关系映射 在MVC框架中的Model模块中都包括ORM,对于开发人员主要带来了如下好处: 实现了数据模型与数据库的解耦,通过简单的配置就可 ...

  8. Django中Cookie和Session配置和操作

    Cookie Cookie以键值对Key-Value形势进行信息的存储. Cookie基于域名安全,不同域名的Cookie是不能互相访问的 Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏 ...

  9. django中自定义表名及字段名称

    在meta 类中指定表名,在字段中通过db_column指定列名如下所示 class Record(models.Model): content=models.CharField(max_length ...

随机推荐

  1. 牛客第五场多校 A gpa 分数规划(模板)

    链接:https://www.nowcoder.com/acm/contest/143/A来源:牛客网 Kanade selected n courses in the university. The ...

  2. 牛客小白月赛5 D 阶乘 数学

    链接:https://www.nowcoder.com/acm/contest/135/D来源:牛客网 题目描述 输入描述: 输入数据共一行,一个正整数n,意义如“问题描述”. 输出描述: 输出一行描 ...

  3. 牛客网暑期ACM多校训练营(第二场) 题解 A run 递推 dp

    链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 White Cloud is exercising in the playground. Whi ...

  4. SPOJ - QTREE(树链剖分+单点更新+区间最大值查询)

    题意:给出n个点n-1条边的树,有两个操作,一个是查询节点l到r的边的最大值,然后指定边的更改权值. 题解:差不多是树链剖分的模版题,注意每个点表示的边是连向其父亲节点的边. #include < ...

  5. Robot Framework自动化测试

    http://blog.csdn.net/wangjingna/article/details/49782001

  6. Fire Balls 09——修正游戏的BUG

    版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...

  7. Filter过滤器学习

    一.Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态 ...

  8. 【UEFI】---BIOS中UserPassword的重复校验总结

    UEFI作为目前较为流行的一套X86架构初始化的标准框架,已受到业界内的广泛认可.而其中很多编程所采用的思想确实值得学习.今天总结下UEFI的框架下修改代码的一点小经验,仅供菜鸟参考. 先列干货,具体 ...

  9. android 和 webService交互

    webService 很久不用了,第一次使用还是13年, 早已忘记怎么搞了.今天看了篇博文,写了个demo .记录下吧! 首先要下载skoap2  .... xxx.jar  ,我用的是最新的3.6. ...

  10. Net基础篇_学习笔记_第九天_数组_三个练习

    练习一: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Sys ...