django ORM模型表的一对多、多对多关系、万能双下划线查询
一.外键使用
在 MySQL 中,如果使用InnoDB引擎,则支持外键约束。(另一种常用的MyIsam引擎不支持外键)
定义外键的语法为fieldname=models.ForeignKey(to_class,on_delete=' ',options),第一个参数表示引用哪个模型,第二个参数表示如果外键引用的模型删除,该字段对应的的值应该怎么处理,第三个语法为其他字段参数。
django ORM模型常用的on_delete的值
models.CASCADE:级联删除,即外键对应的那条数据删除了,这条数据也会被删除
models.SET_NULL:设置为空,即外键对应的那条数据删除了,这条数据对应的字段设置为null,前提是这个字段可以设置为空
models.SET_DEFAULT:设为默认值,即外键对应的那条数据删除了,这条数据对应的字段设置为默认值,前提是这个字段要设置一个默认值
models.PRODECT:受保护,即不允许删除外键对应的那条数据
创建两个模型,学生和班级,一个学生只能属于一个班级,一个班级可以有多个学生,学生与班级为多对一的关系。
class Students(models.Model):#学生模型
sname=models.CharField(max_length=20)
age=models.IntegerField()
gender=models.BooleanField()
cls=models.ForeignKey('Classes',on_delete=models.CASCADE)#通过cls创建学生模型与班级模型的外键关系
def __str__(self):#自定义返回样式
return '%s,%s,%s,%s'%(self.sname,self.age,self.gender,self.cls)
class Meta:#自定义映射到数据库的表名
db_table='students' class Classes(models.Model):#班级模型
cname=models.CharField(max_length=50)
headmaster=models.CharField(max_length=20)
def __str__(self):
return '%s,%s'%(self.cname,self.headmaster)
class Meta:
db_table='classes'
创建学生模型和班级模型
上述cls字段的参数'Classes'表示引用Classes表的主键id作为外键,完整写法为cls=models.ForeignKey(to=''Classes,to_field='id',on_delete=models.CASCADE),to表示表,to_field表示字段。
需要注意的是,在Students模型定义时,外键属性名称为cls,但是在映射到数据库时django会将字段名称加上_id,即Student模型的cls属性在数据内对应的字段名称为cls_id。
如果引用的模型在另外一个app中,那么需要在各自的urls.py的文件中先定义命名空间app_name='appname',再在to_class中加上app的名字,以上如果Classes是在另外一个名叫app01的app中,那么Students的cls的属性定义为cls = models.ForeignKey("app01.Classes",on_delete=models.CASCADE)。
如果要引用自己作为外键,to_class可以写为self,或者app的名字。
二.一对多(多对一)操作
如果模型A被模型B引用用作外键,django会自动给A模型添加一个属性,属性名称为B模型的小写_set,即b_set属性,表示并且该属性同样可以调用all()、objects.get()、objects.filter()、objects.first()等方法进行查询。
例如上述例子,班级会有一个students_set属性,要想获取某个班级c下的所有学生,可通过c.students_set.all()获取。
如果在B模型创建外键字段时自定义一个related_name=‘’,则会覆盖系统自动创建的属性名称,例如上述Students的cls的属性如果定义为cls = models.ForeignKey("Classes",on_delete=models.CASCADE,related_name=‘allstudents’),那么再要获取班级c下的所有学生,则应该通过c.allstudent.all()获取,并且班级不再有students_set属性。通常建议建议自定义related_name。
①增加记录
插入一个班级c和一个学生s记录
c=Classes.objects.create(cname='高三一班',headmaster='王老师')#由于学生模型会引用班级模型,因此需要先创建班级,否则后面创建学生的时候会报错
#方法一:直接对底层数据库进行赋值
s=Students.objects.create(sname='张三',age=19,gender='',cls_id=1)
#方法二:设置Students模型的cls属性等于要引用的模型实例
s=Students.objects.create(sname='张三',age=19,gender='',cls=c)
②查询记录
对于Students模型来说,对象s的cls属性即为对应的班级对象,可通过type(s.cls)查看,结果为<class 'app01.models.Classes'>,因此可通过s.cls.属性再获取班级相关信息
例如要获取学生s所在的班级名称:
cname1=s.cls.cname #方法一
cname2=Students.objects.filter(sname='张三').values('cls__cname') #方法二
cname3=Classes.objects.filter(students__sname='张三').values('cname') #方法三
再例如要获取班级c下的学生姓名:
sname1=c.students_set.all().values('sname') #方法一
sname2=Classes.objects.filter(cname='高三一班').values('students__sname') #方法二
sname3=Students.objects.filter(cls__cname='高三一班').values('sname') #方法三
③万能的双下划线查询
双下划线可实现跨表查询。学生模型引用班级模型做外键,通过学生查询班级时,通过外键属性__进行跨表,通过班级查询学生时,直接通过表名__进行跨表。
例如上述的cname2,'cls__cname'表示通过外键跨到班级表,并且获取班级表的cname属性
而对上述的cname3,'students__sname'表示通过表名跨到学生表,并且获取学生表的sname属性。
④
上述例子,如果要将一篇文章加到某个作者下面,除了上面的方法外,还可以使用如下方法
user=User.objects.first()
article=Article(title='abc',content='abcdefghijklmn')
article.save()
user.articles.add(article)#将article加入user用户下
user.save()
上面这种写法,在article加入user作者前必须先保存article,这个前提是article的author字段可以为空,如果不能为空则这种写法会报错。而用下面这种方法则不会存在该问题。
user=User.objects.first()
article=Article(title='abc',content='abcdefghijklmn')
user.articles.add(article,bulk=False)
三.多对多操作
新创建两个模型,老师和班级,一个老师可以教多个班级,一个班级也会有多个老师。
class Teachers(models.Model):
tname=models.CharField(max_length=20)
age=models.IntegerField()
gender=models.BooleanField()
cls=models.ManyToManyField('Classes')
def __str__(self):
return '%s,%s,%s,%s'%(self.tname,self.age,self.gender,self.cls)
class Meta:
db_table='teachers' class Classes(models.Model):
cname=models.CharField(max_length=50)
def __str__(self):
return self.cname
class Meta:
db_table='classes'
创建老师和班级模型
将上述两个模型映射到数据库,会生成三张表,teachers表、classes表和teachers_cls表。
其中teachers表只有四个字段,id、tname、age和gender,并没有cls字段。
teachers_cls为django为多对多关系自动创建的一张表,命名规则为创建多对多关系的模型名称小写_多对多字段小写,只包含三个字段,id、teachers_id和classes_id。
如果不想使用django自动创建的第三张表,可以自己创建,如下,并使用该表来维护模型的多对多关系。自己创建的第三张表还可以增加另外的字段。
class Teachers(models.Model):
tname=models.CharField(max_length=20)
age=models.IntegerField()
gender=models.BooleanField()
#cls=models.ManyToManyField('Classes')
def __str__(self):
return '%s,%s,%s,%s'%(self.tname,self.age,self.gender,self.cls)
class Meta:
db_table='teachers' class Classes(models.Model):
cname=models.CharField(max_length=50)
def __str__(self):
return self.cname
class Meta:
db_table='classes' class Teachers_Classes(models.Model)
t = models.ForeignKey('Teachers')
c = models.ForeignKey('Classes')
ctime = models.DateField()
class Meta:
db_table='teachers_classes'
unique_together=[('t','c'),] #表示对t和c字段创建联合唯一索引
手动创建多对多的第三张表
上述方法手动创建第三张表,原本自动生成的第三张表还是会生成。如果要手动创建第三张表并且不生成django自动创建的表,需要使用ManyToManyField并且添加参数m = models.ManyToManyField( to='Classes',through='Teachers_Classes',through_fields=['t','c'])。这种方法不推荐。
①增加记录并绑定关系
c1=Classes.objects.filter(cname='一年级').first()
c2 = Classes.objects.filter(cname='二年级').first()
t1=Teachers.objects.filter(tname='李老师').first()
t2 = Teachers.objects.filter(tname='王老师').first()
c1.teachers_set.add(t1)#将t1老师绑定到c1班级,此处参数可以为老师对象,也可为老师id
t2.cls.add(c2) #将c2班级绑定到t2老师,此处参数可以为班级对象,也可以为班级id
上述,c1.teachers_set即外键中的用法,t2.cls为t2对应的班级集合
②查询记录
c=Teachers.objects.filter(tname='李老师').first().cls.all().values('cname') #李老师所带班级的名称
t=Classes.objects.filter(cname='一年级').first().teachers_set.all().values('tname') #一年级老师的名字
③删除绑定关系
Teachers.objects.filter(tname='李老师').first().cls.remove(5)#解除李老师与id为5班级的绑定关系,此处参数也可以为班级对象
Classes.objects.filter(cname='一年级').first().teachers_set.remove(5)#解除一年级与id为5老师的绑定关系,此处参数也可以为老师对象
④重置绑定关系
Teachers.objects.filter(tname='李老师').first().cls.set([4,5]) #将id为4和5的班级与李老师绑定,此处参数也可以为班级对象
Classes.objects.filter(cname='一年级').first().teachers_set.set([5,6]) #将id为5和6的老师与一年级绑定,此处参数也可以为老师对象
django ORM模型表的一对多、多对多关系、万能双下划线查询的更多相关文章
- django基础之day04,必知必会13条,双下划线查询,字段增删改查,对象的跨表查询,双下划线的跨表查询
from django.test import TestCase # Create your tests here. import os import sys if __name__ == " ...
- 测试脚本配置、ORM必知必会13条、双下划线查询、一对多外键关系、多对多外键关系、多表查询
测试脚本配置 ''' 当你只是想测试django中的某一个文件内容 那么你可以不用书写前后端交互的形式而是直接写一个测试脚本即可 脚本代码无论是写在应用下的test.py还是单独开设py文件都可以 ' ...
- Django学习——Django测试环境搭建、单表查询关键字、神奇的双下划线查询(范围查询)、图书管理系统表设计、外键字段操作、跨表查询理论、基于对象的跨表查询、基于双下划线的跨表查询
Django测试环境搭建 ps: 1.pycharm连接数据库都需要提前下载对应的驱动 2.自带的sqlite3对日期格式数据不敏感 如果后续业务需要使用日期辅助筛选数据那么不推荐使用sqlite3 ...
- django models的点查询/跨表查询/双下划线查询
django models 在日常的编程中,我们需要建立数据库模型 而往往会用到表与表之间的关系,这就比单表取数据要复杂一些 在多表之间发生关系的情形下,我们如何利用models提供的API的特性获得 ...
- python-day71--django多表双下划线查询及分组聚合及F/Q查询
#====================================双下划线的跨表查询===============# 前提 此时 related_name=bookList 属性查询: # 查 ...
- 模型层字段-多表查询-神奇的双下划线查询-F,Q查询
Django ORM中常用的字段和参数 常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. In ...
- Django ORM 之基于对象、双下划线查询
返回ORM目录 Django ORM 内容目录: 一. 基于对象的表查询 二. 基于双下划线的查询 三. 聚合查询 aggregate 四. 分组查询 annotate 一. 基于对象的表查询 1.正 ...
- Django框架(九)-- 多表操作:一对一、一对多、多对多的增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询
一.创建多表模型 一对一:OneToOneField 一对多:ForeignKey 多对多:ManyToManyField 创建表时,会自动添加一个nid字段,并且自增,所以id可以不用手动创建 On ...
- Django框架之第六篇(模型层)--单表查询和必知必会13条、单表查询之双下划线、Django ORM常用字段和参数、关系字段
单表查询 补充一个知识点:在models.py建表是 create_time = models.DateField() 关键字参数: 1.auto_now:每次操作数据,都会自动刷新当前操作的时间 2 ...
随机推荐
- 【UML】-NO.43.EBook.5.UML.1.003-【UML 大战需求分析】- 状态机图(State Machine Diagram)
1.0.0 Summary Tittle:[UML]-NO.43.EBook.1.UML.1.003-[UML 大战需求分析]- 状态机图(State Machine Diagram) Style:D ...
- 【Redis】事务
在Redis中,事务是以multi/exec/discard进行的, 其中multi表示事务的开始, exec表示事务的执行,discard表示丢弃事务. > multi # 事务的开始 OK ...
- selenium及webdriver的原理【转】
selenium与webdriver整合后,形成的新的测试工具叫做selenium2.x.在selenium1时间,selenium使用javascript来达到测试自动化的目标. 1. seleni ...
- 引:Jmeter添加变量的四种方法
一.在样本中添加同请求一起发送的参数.根据服务器设置的数据类型,来添加不同类型的参数 二.用户定义的变量 1.创建:添加->配置元件->用户定义的变量 2.作用:当前的线程组内所有Samp ...
- Maven中的-D(Properties属性)和-P(Profiles配置文件)
-D代表(Properties属性) 使用命令行设置属性-D的正确方法是: mvn -DpropertyName=propertyValue clean package 如果propertyName不 ...
- iText C# 合并PDF文件流,以及A5变A4时内容默认放在最底下的问题的解决方法;ASP.NET 实现Base64文件流下载PDF
/// <summary> 合併PDF檔(集合) </summary> /// <param name="files">欲合併PDF檔之集合(一 ...
- mysql 增加列,修改列名、列属性,删除列语句
mysql增加列,修改列名.列属性,删除列语句 mysql修改表名,列名,列类型,添加表列,删除表列 alter table test rename test1; --修改表名 alter t ...
- sqli-labs(三)
第五关:这关的重点是有联合查询的注入漏洞,但是页面不会显示查询信息,但是会有报错信息显示在页面上 这关是双查询注入,其实用报错注入和盲注都是可以注入的,但是我觉得这个双查询注入还是很有意思的,所以这关 ...
- UVA 11168 Airport(凸包)
Airport [题目链接]Airport [题目类型]凸包 &题解: 蓝书274页,要想到解析几何来降低复杂度,还用到点到直线的距离公式,之后向想到预处理x,y坐标之和,就可以O(1)查到距 ...
- FZU 1683 纪念SlingShot(矩阵水)
纪念SlingShot [题目链接]纪念SlingShot [题目类型]矩阵水 &题解: 这代码调了十多分钟,结果是Mul没返回值,好zz啊. 令sum(n)=sum(n-1)+f(n) 那么 ...