本文转载自https://blog.csdn.net/xiaogeldx/article/details/88084034

表关系



一对一(OneToOne)

  • 通过本表的主键外键关联另一张表的主键

  • 创建张学生详情表(在students的models.py文件中)

      		from django.db import models
    class Student(models.Model):
    name = models.CharField(max_length=20)
    age = models.SmallIntegerField(default=0)
    gender = models.SmallIntegerField(default=1)
    qq = models.CharField(max_length=20,default='')
    phone = models.CharField(max_length=20,default='')
    c_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    def __str__(self):
    return '%s-%s' % (self.name, self.age)
    class StudentDetail(models.Model): #学生对学生详情,一对一
    num = models.CharField(max_length=20, default='')
    college = models.CharField(max_length=20,default='')
    #Student最好用字符串
    student = models.OneToOneField('Student', on_delete=models.CASCADE)
    #外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题,不然会报错 #一般使用CASCADE表示级联删除

    图中的student_id就是外键关联

一对多(OneToMany)

		from django.db import models
class Student(models.Model):
name = models.CharField(max_length=20)
age = models.SmallIntegerField(default=0)
gender = models.SmallIntegerField(default=1)
grade = models.ForeignKey('Grade', on_delete=models.SET_NULL, null=True) #删除某个学生后,班级对应的位置会显示为NULL
qq = models.CharField(max_length=20,default='')
phone = models.CharField(max_length=20,default='')
c_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
def __str__(self):
return '%s-%s' % (self.name, self.age)
class StudentDetail(models.Model): #学生对学生详情,一对一
num = models.CharField(max_length=20, default='')
college = models.CharField(max_length=20,default='')
#Student最好用字符串
student = models.OneToOneField('Student', on_delete=models.CASCADE)
class Grade(models.Model): #学生对班级,一对多
num = models.CharField(max_length=20)
name = models.CharField(max_length=20)

多对多(ManyToMany)

		class Course(models.Model):
name = models.CharField('课程名称', max_length=20) #参数第一位就是verbose_name,“verbose_name=”可省略
students = models.ManyToManyField('Student', through='Enroll') #Student表和Course表可以不通过Enrol就能相互访问l#如果只有外键和id两个字段时会自动创建第三张表关联
class Enroll(models.Model): #报名表,有多个字段
student = models.ForeignKey('Student', on_delete=models.CASCADE)
course = models.ForeignKey('Course', on_delete=models.CASCADE)
pay = models.FloatField('缴费金额', default=0)
c_time = models.DateTimeField('报名时间', auto_now_add=True)



关联表的数据操作

进入项目目录的idle

  • 为了能方便学习,进入项目的idle去执行操作
  • 通过python manage.py shell就能进入当前目录下的idle
    • 进入idle
    • 查看当前的目录路径
    • 导入我们项目中的模型类

OneToMany

  • 正向:一个模型如果定义了一个外键字段,通过这个模型去操作这个外键就是正向

      In [2]: from students.models import Student,StudentDetail,Grade,Course,Enroll
    In [3]: Grade.objects.all()
    Out[3]: <QuerySet [<Grade: 33期-django框架>, <Grade: 256期-爬虫>]>
    In [4]: s = Student()
    In [5]: s.name = 'xiaoge'
    In [6]: g1 = Grade.objects.first()
    In [7]: g1
    Out[7]: <Grade: 33期-django框架>
    In [8]: s.grade = g1 #增 #方法1
    In [9]: s.save()
    In [10]: s2 = Student(name='na')
    In [11]: g2 = Grade.objects.last()
    In [12]: s2.grade_id = g2.id #增 #方法2,效果和方法1一样
    In [13]: s2.save()
    In [18]: s = Student.objects.first()
    In [21]: s.grade = g2 #改 #grade是定义在模型Student里面的ForeignKey,对它的操作就是正向 #它的修改和普通字段修改没什么区别,赋值然后保存
    In [22]: s.grade
    Out[22]: <Grade: 256期-爬虫>
    In [24]: s.grade = None #删
    In [25]: s.save()
    In [26]: s = Student.objects.first()
    In [28]: s.grade #返回值为空#只有外键定义了null=True才能删除,否则不能
    In [30]: s2
    Out[30]: <Student: na-0>
    In [31]: s2.grade.name #查 #和属性操作一样
    Out[31]: '爬虫'
    In [33]: s2.grade.num #查 #和属性操作一样
    Out[33]: '256期'
  • 反向:

      In [36]: g3 = Grade.objects.create(name='进阶',num='40期')
    #如果模型1有一个ForeignKey,那么该ForeignKey所指的模型2实例可以通过一个管理器返回前面有Foreignkey的模型1的所有实例,默认情况下,这个管理器的名字为模型名字的小写+_set
    In [37]: g3.student_set.create(name='long') #反向增1 #模型名的小写_set 是个管理器 ,是对象的集合
    Out[37]: <Student: long-0>
    In [38]: s = Student.objects.last()
    In [39]: s.grade.name #查
    Out[39]: '进阶'
    In [40]: s.grade.num
    Out[40]: '40期'
    In [47]: s = Student.objects.first()
    In [49]: g3.student_set.add(s) #增2 #可以一次增多个
    In [51]: g3.student_set.all() #查 #student_set在此处的用法相当于objects
    Out[51]: <QuerySet [<Student: xiaoge-0>, <Student: long-0>]>
    In [52]: g3.student_set.filter(name='xiaoge') #查
    Out[52]: <QuerySet [<Student: xiaoge-0>]>
    In [53]: g3.student_set.filter(name='xiaoge').count() #查
    Out[53]: 1
    In [54]: g3.student_set.remove(s) #删1 #可以一次删多个
    In [55]: g3.student_set.all()
    Out[55]: <QuerySet [<Student: long-0>]>
    In [56]: g3.student_set.clear() #删2 清空
    In [57]: g3.student_set.all()
    Out[57]: <QuerySet []>
    In [58]: g3.student_set.set([s,s2]) #改 #set方法会先调用clear,再添加 (如果没有clear方法,clear不执行,直接添加)
    In [59]: g3.student_set.all()
    Out[59]: <QuerySet [<Student: xiaoge-0>, <Student: na-0>]>
    In [60]: res = Student.objects.filter(grade__name='django框架')
    In [61]: print(res.query)
    SELECT `students_student`.`id`, `students_student`.`name`, `students_student`.`age`, `students_student`.`gender`, `students_student`.`grade_id`, `students_student`.`qq`, `students_student`.`phone`, `students_student`.`c_time` FROM `students_student` INNER JOIN `students_grade` ON (`students_student`.`grade_id` = `students_grade`.`id`) WHERE `students_grade`.`name` = django框架
    In [62]: res
    Out[62]: <QuerySet []>

ManyToMany

	In [64]: Course.objects.create(name='python全栈')
Out[64]: <Course: python全栈>
In [65]: Course.objects.create(name='python全套')
Out[65]: <Course: python全套>
In [66]: Course.objects.create(name='english')
Out[66]: <Course: english>
In [67]: c1,c2,c3 = Course.objects.all()
In [68]: c1
Out[68]: <Course: python全栈>
In [69]: c2
Out[69]: <Course: python全套>
In [70]: c3
Out[70]: <Course: english>
In [71]: Student.objects.all().count()
Out[71]: 3
In [72]: s1,s2,s3 = Student.objects.all()
In [73]: s1
Out[73]: <Student: xiaoge-0>
In [74]: s2
Out[74]: <Student: na-0>
In [75]: s3
Out[75]: <Student: long-0>
In [76]: e = Enroll()
In [77]: e.course = c1
In [78]: e.student = s1
In [79]: e.save()
In [80]: Enroll.objects.create(student=s1,course=c3)
Out[80]: <Enroll: Enroll object (2)>
In [81]: Enroll.objects.create(student=s3,course=c1)
Out[81]: <Enroll: Enroll object (3)>
In [82]: Enroll.objects.create(student=s1,course=c1)
Out[82]: <Enroll: Enroll object (4)>
In [83]: c1.students
Out[83]: <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager at 0x7fdc1d9d46a0>
In [84]: c1.students.all()
Out[84]: <QuerySet [<Student: xiaoge-0>, <Student: xiaoge-0>, <Student: long-0>]>
In [85]: s1.course_set.all()
Out[85]: <QuerySet [<Course: python全栈>, <Course: english>, <Course: python全栈>]>

多对多时如果指定了中间表(本例中是Enroll表),则不能用add,remove,set,必须用中间表

OneToOne

  • 正向

      In [1]: from students.models import Student,StudentDetail,Course,Enroll,Grade
    In [3]: s1 = Student.objects.first()
    In [4]: s2 = Student.objects.filter(name='na')
    In [5]: s3 = Student.objects.last()
    In [6]: s1
    Out[6]: <Student: xiaoge-0>
    In [7]: s2
    Out[7]: <QuerySet [<Student: na-0>]>
    In [8]: s3
    Out[8]: <Student: long-0>
    In [9]: sd = StudentDetail.objects.create(num='121204040',college='辽工',student=s1)
    In [10]: sd
    Out[10]: <StudentDetail: StudentDetail object (1)>
    In [11]: sd.student
    Out[11]: <Student: xiaoge-0>
  • 反向

      In [12]: s1.studentdetail       	#用模块名的小写,是个对象,不是管理器(没有_set)
    Out[12]: <StudentDetail: StudentDetail object (1)>
    In [13]: s1.studentdetail.college
    Out[13]: '辽工'

跨表查询

  • Django提供一种强大而直观的方式来处理查询中的关联关系,他在后台自动帮你处理join

  • 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段

      #查询男生报了什么课程#最终是要查课程,所以用Course模型,通过本模型里的字段正向查
    In [14]: res = Course.objects.filter(students__gender=1) #正向,本模型里的字段名+__想要查的字段
    In [15]: print(res.query)
    SELECT `students_course`.`id`, `students_course`.`name` FROM `students_course` INNER JOIN `students_enroll` ON (`students_course`.`id` = `students_enroll`.`course_id`) INNER JOIN `students_student` ON (`students_enroll`.`student_id` = `students_student`.`id`) WHERE `students_student`.`gender` = 1
    In [16]: res
    Out[16]: <QuerySet [<Course: python全栈>, <Course: python全栈>, <Course: python全栈>, <Course: english>]>
    In [17]: res = Course.objects.filter(students__name='long')
    In [18]: res
    Out[18]: <QuerySet [<Course: python全栈>]>
    #查询报Python的学生#最终是要查学生,所以用Student模型,通过course反向查
    In [19]: res = Student.objects.filter(course__name__contains='python') #相关模型名的小写+__相关字段名
    In [20]: print(res.query)
    SELECT `students_student`.`id`, `students_student`.`name`, `students_student`.`age`, `students_student`.`gender`, `students_student`.`grade_id`, `students_student`.`qq`, `students_student`.`phone`, `students_student`.`c_time` FROM `students_student` INNER JOIN `students_enroll` ON (`students_student`.`id` = `students_enroll`.`student_id`) INNER JOIN `students_course` ON (`students_enroll`.`course_id` = `students_course`.`id`) WHERE `students_course`.`name` LIKE BINARY %python%
    In [21]: res
    Out[21]: <QuerySet [<Student: xiaoge-0>, <Student: xiaoge-0>, <Student: long-0>]>
    #查询报了英语33期的学生
    In [31]: res = Student.objects.filter(course__name__contains='english',grade__num__contains='33期')
    In [32]: res
    Out[32]: <QuerySet []>
    #查询缴费金额小于3000的学生
    In [33]: res = Student.objects.filter(enroll__pay__lt=3000)
    In [34]: print(res.query)
    SELECT `students_student`.`id`, `students_student`.`name`, `students_student`.`age`, `students_student`.`gender`, `students_student`.`grade_id`, `students_student`.`qq`, `students_student`.`phone`, `students_student`.`c_time` FROM `students_student` INNER JOIN `students_enroll` ON (`students_student`.`id` = `students_enroll`.`student_id`) WHERE `students_enroll`.`pay` < 3000.0
    #查询报了python课程的学生的班级有哪些
    In [35]: res = Grade.objects.filter(student__course__name__contains='python')
    In [36]: print(res.query)
    SELECT `students_grade`.`id`, `students_grade`.`num`, `students_grade`.`name` FROM `students_grade` INNER JOIN `students_student` ON (`students_grade`.`id` = `students_student`.`grade_id`) INNER JOIN `students_enroll` ON (`students_student`.`id` = `students_enroll`.`student_id`) INNER JOIN `students_course` ON (`students_enroll`.`course_id` = `students_course`.`id`) WHERE `students_course`.`name` LIKE BINARY %python%

django模型基础(三)的更多相关文章

  1. Django 08 Django模型基础3(关系表的数据操作、表关联对象的访问、多表查询、聚合、分组、F、Q查询)

    Django 08 Django模型基础3(关系表的数据操作.表关联对象的访问.多表查询.聚合.分组.F.Q查询) 一.关系表的数据操作 #为了能方便学习,我们进入项目的idle中去执行我们的操作,通 ...

  2. Django 07 Django模型基础2 (常用查询和多表关联)

    Django 07 Django模型基础2 (常用查询和多表关联) 一.常用查询 #查找数据 def search_user(request): #获取 rs = User.objects.first ...

  3. Django 06 Django模型基础1(ORM简介、数据库连接配置、模型的创建与映射、数据的增删改查)

    Django 06 Django模型基础1(ORM简介.数据库连接配置.模型的创建与映射.数据的增删改查) 一.ORM系统 #django模型映射关系 #模型类-----数据表 #类属性-----表字 ...

  4. Django 学习第六天——Django模型基础第一节

    一.Django 的 ORM 简介: Django的ORM系统的分析: 1.ORM 概念:对象关系映射(Object Relational Mapping,简称ORM) 2.ORM的优势:不用直接编写 ...

  5. 六、Django模型基础第一节

    1 数据库的连接配置 django 连接mysql的配置流程: 安装 pymysql pip install pymysql 创建数据库用户 '; grant all on *.* to 'xiang ...

  6. 九.django模型基础(三)之关联对象操作及多表查询

    Ⅰ.关系表的数据操作 1.正向 正向:如果一个模型有外键字段,通过这个模型对外键进行操作叫做正向. 1)更新(增) a.通过属性复制 b.通过主键的方式 总结: ForeignKey 字段的更新,跟普 ...

  7. Django模型基础(三)——关系表的数据操作

    模型之间可以有三种表关系,即一对一,一对多和多对多.表关联之间的数据操作在Django中可以很方便的操作到.在模型中,表关联的字段类型是关联表的实例,而不是字段本身类型.关联字段在数据库中会在其后补上 ...

  8. Django 学习第八天——Django模型基础第三节

    一.表关系的实现: 一对一:OneToOne(外键+唯一键) xxx = models.OneToOneField('关联的表',on_delete=models.CASCADE) 外键和一对一关系的 ...

  9. 【Mac系统 + Python + Django】之开发一个发布会系统【Django模型(三)】

    上一部分给大家介绍Django的视图. 接下来继续来了解Django框架,来看第三部分,此部分是对数据库的操作. 目录: 一.设计系统表 二.admin后台管理 三.基本数据访问(SQLite数据库) ...

随机推荐

  1. hover样式失效的解决方法

       提到 css 的hover 选择器,想必大家都不陌生(:hover 用于设置鼠标指向某元素上后显示的样式)  除了常用的 hover 选择器,还有3个可以和它搭配使用的选择器: :link 设置 ...

  2. Spring整合MyBatis 你get了吗?

    Spring整合MyBatis 1.整体架构dao,entity,service,servlet,xml 2..引入依赖 <dependencies> <dependency> ...

  3. C语言中指针中的值赋值给数组

    如果把各种语言做个冷兵器类比的话,C语言一定是刀客的最佳工具.入门很简单,但是要是能把它熟练运用,那就是顶尖级别的高手了. 用了那么多年的C语言,发现自己还是仅仅处于熟练的操作工.今天遇到了一个bug ...

  4. 多线程 Thread.yield 方法到底有什么用?

    概念 我们知道 start() 方法是启动线程,让线程变成就绪状态等待 CPU 调度后执行. 那 yield() 方法是干什么用的呢?来看下源码. /** * A hint to the schedu ...

  5. DedeCMS上传视频

    DedeCMS建站方便快捷,但是在上传视频时会出现问题,主要是文件格式与大小限制,需要修改配置文件,修改的地方主要有: 1.修改 DedeCMS系统配置参数--附件设置--允许的多媒体软件类型(以MP ...

  6. Jenkins技巧:如何更新Jenkins到最新版本

    ----------------------------------------------------------------- 原创博文,未经作者允许禁止转载. 博主:疲惫的豆豆 链接:http: ...

  7. 打成Jar包后运行报错 Unable to locate Spring NamespaceHandler for XML schema namespace

    MAVEN项目,在IDEA中运行正常,但是把它打成jar包后再运行就会出现异常:   Exception in thread "main" org.springframework. ...

  8. 一个BAT老程序员的忠告!

      一.在中国,你千万不要因为学习技术就可以换来稳定的生活和高的薪水待遇,你更不要认为那些从事市场.运营的人,没有前途. 不清楚你是不是知道,咱们中国有相当大的一部分软件公司,他们的软件开发团队都小的 ...

  9. 我对java String的理解 及 源码浅析

    摘要: 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 每天起床告诉自己,自己的目标是 ”技术 + 英语 还有生活“! ...

  10. java 容器 集合 用法

    Set,List,Map,Vector,ArrayList的区别 JAVA的容器---List,Map,Set Collection ├List │├LinkedList │├ArrayList │└ ...