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 ...
随机推荐
- Mongodb 基础 查询表达式
数据库操作 查看:show dbs; 创建:use dbname; // db.createCollection('collection_name'); 隐式创建,需要创建的数据库中有表才表示创 ...
- 【Linux】-NO.9.Linux.5.Nexus.1.001-【CentOS 7 Install Nexus 3.3】-
1.0.0 Summary Tittle:[Linux]-NO.9.Linux.5.Nexus.1.001-[CentOS 7 Install Nexus 3.3]- Style:Linux Seri ...
- mac-禅道环境
开机不能访问,换成IP地址就好了
- 把文本数据转化为json
awk '{for (i=1 ;i<=NF;i++){ printf "\"" $i; if ( i==NF) {printf "\",&quo ...
- HttpwebRequest - 带ViewState的网页POST请求
这是我今天下午碰到的案例,一个退订页面的post请求,请求头信息都很明确,but看看下面这个请求体,除了最后一个key是我的页面控件名称,其他的几个ViewState相关都是what呢?(ViewSt ...
- 还是Go 为了伟大的未来
今天,还是想讲讲Go 我觉得还没讲够,哈哈哈 其实,是想把框架再清晰些,因为上一篇框架没能引入goroutine(协程),感觉比较遗憾 下边,我就用上goroutine,但这里的协程仅是为了演示,没有 ...
- arrow
1.c++(OOGP) 与数据结构与算法 1.一定要有一门自己比较熟悉的语言. 我由于使用C++比较多,所以简历上只写了C++.C++的特性要了解,C++11要了解一些,还有STL.面试中常遇到的一些 ...
- LA 3890 Most Distant Point from the Sea(半平面交)
Most Distant Point from the Sea [题目链接]Most Distant Point from the Sea [题目类型]半平面交 &题解: 蓝书279 二分答案 ...
- opcode
https://www.cnblogs.com/JohnABC/p/4531029.html
- Self hosted OWIN 绑定地址127.0.0.1,外网无法访问
static void Main() { string baseAddress = "http://localhost:4004/"; ...