ORM之多表操作
一、创建模型
from django.db import models # Create your models here. class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2) # 与Publish建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors=models.ManyToManyField(to='Author',) class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField() # 与AuthorDetail建立一对一的关系
authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64) class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()
注意事项:
1、可以在任意一张表的模型下自定义这张表的元类信息,来覆盖一些自动生成的元数据,自定义方式可参考如下:
#以Publish表举例 class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField() class Meta:
#app_label这个选项只在一种情况下使用,就是你的模型类不在默认的应用程序包下的models.py文件中,这时候你需要指定你这个模型类是那个应用程序的。比如你在其他地方写了一个模型类,而这个模型类是属于myapp的,那么你这是需要指定为:
app_label="myapp"
db_table="app01book" #用于指定自定义数据库表名
unique_together=["title","price"] #设置联合唯一,这两个字段的值在数据库中存储的值不能完全一样
verbose_name="书籍" #给你的模型类起一个更可读的名字
ordering=["price"] #数据存储按照price字段排序,默认为升序,如果不指定排序的字段,django会默认按照主键升序来排序
元类信息设置完成之后您可以使用如下命令来测试元数据设置的值:
>>>Book._meta.verbose_name >>>Book._meta.model_name >>>Book._meta.app_label
2、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名。
二、添加表记录
一对多添加:
方式一:
book = Book.objects.create(
title='冰与火之歌',
price=320,
publishDate = '2010-12-08',
publish_id = 2
)
方式二:
pub_obj = Publish.objects.filter(name = '人民出版社').first()
book = Book.objects.create(
title='java',
price=88,
publishDate='2015-11-24',
publish=pub_obj
)
核心:book.publish为book模型对象所对应的出版社对象,book.publish_id为book对象所对应的出版社的主键值。
多对多添加
方式一:
feng= Author.objects.filter(name='feng').first()
zhao= Author.objects.filter(name='zhao').first()
book.authors.add(feng,zhao)
方式二:
book.authors.add(1,2)
方式三:
book.authors.add(*[1,2])
多对多关系其它常用API:
book.authors.remove(1) #将主键值为1的作者对象从被关联对象集合中去除
book.authors.clear() #清空被关联集合对象 book.authors.set(1) #先清空在设置
三、跨表查询
基于对象的跨表查询(子查询)
一对多查询(Publish与Book):
正向查询:关联属性所在的表查询关联表记录 正向查询按字段:book.publish
Book-------------------------------------->Publish
<---------------------------------------
反向查询:表名小写_set.all():pub_obj.book_set.all()
#1 查询python这本书出版社的名字和邮箱
book = Book.objects.filter(title = 'python').first()
print(book.publish) #与book这本书关联的出版社对象
print(book.publish.name) #与book这本书关联的出版社对象的名字
print(book.publish.email)
#2 查询苹果出版社出版的所有的书籍的名称
pub_obj = Publish.objects.get(name='苹果出版社')
print(pub_obj.book_set.all()) #queryset
print(pub_obj.book_set.all().values("title")) # queryset,列表里面放的一个个字典
多对多查询(Author与Book):
正向查询按字段 book.authors.all()
Book -------------------------------------->Author
<--------------------------------------
反向查询按表名小写_set.all(): feng.book_set.all()
# 查询python这本书籍的作者的年龄
book = Book.objects.filter(title='python').first()
ret = book.authors.all().values('age') # 查询feng出版过的所有的书籍名称
feng= Author.objects.filter(name = 'feng').first()
print(feng.book_set.all())
一对一查询(Author与AuthorDetail)
正常查询安字段:author_obj.authorDetail
Author -----------------------------------------> AuthorDetail
<------------------------------------------
反向查询按表名小写:authordetail_obj.author
# 查询alex的手机号
author_obj = Author.objects.filter(name='feng').first()
print(author_obj .authorDetail.tel) # 查询手机号为110的作者的名字
ad = AuthorDetail.objects.filter(tel = 110).first()
print(ad.author.name)
基于双下划线的跨表查询(join查询)
KEY:无论是一对一、一对多还是多对多都遵循正向查询按字段,反向查询按表名小写。
# 1 查询python这本书出版社的名字
ret = Book.objects.filter(title='python').values('publish__name') ret = Publish.objects.filter(book__title='python').values('name') # 2 查询苹果出版社出版的所有的书籍的名称
ret = Publish.objects.filter(name='苹果出版社').values('book__title') ret = Book.objects.filter(publish__name='苹果出版社').values('title') # 3 查询python这本书籍的作者的年龄
ret = Book.objects.filter(title='python').values('authors__age') ret = Author.objects.filter(book__title='python').values('age') # 4 查询feng出版过的所有的书籍名称
ret = Book.objects.filter(authors__name='feng').values('title') ret = Author.objects.filter(name='feng').values('book__title') # 5 查询手机号为110的作者的名字
ret = AuthorDetail.objects.filter(tel=110).values('author__name') ret = Author.objects.filter(ad__tel=110).values('name') # 6 查询feng的手机号
ret = Author.objects.filter(name='feng').values('ad__tel') ret = AuthorDetail.objects.filter(author__name='feng').values('tel') ########### 连续跨表 ############### # 查询苹果出版社出版过的所有书籍的名字以及作者的姓名 ret = Publish.objects.filter(name='苹果出版社').values('book__title','book__authors__name')
ret = Book.objects.filter(publish__name='苹果出版社').values('title','authors__name') # 手机号以110开头的作者出版过的所有书籍名称以及出版社名称 #方式一
ret = Book.objects.filter(authors__ad__tel__startswith=110).values('title','publish__name') #方式二
ret = Author.objects.filter(ad__tel__startswith=110).values('book__title','book__publish__name') #方式三
ret = AuthorDetail.objects.filter(tel__startswith=110).values('author__book__title','author__book__publish__name')
related_name
反向查询时,如果定义了related_name ,则用related_name替换表名,例如:
1
|
publish = ForeignKey(Blog, related_name = 'bookList' ) |
# 练习: 查询人民出版社出版过的所有书籍的名字与价格(一对多) # 反向查询 不再按表名:book,而是related_name:bookList queryResult=Publish.objects.filter(name="人民出版社").values_list("bookList__title","bookList__price")
四、聚合(aggregate)
1
2
3
4
|
# 计算所有图书的平均价格 >>> from django.db.models import Avg >>> Book.objects. all ().aggregate(Avg( 'price' )) { 'price__avg' : 34.35 } |
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
1
2
|
>>> Book.objects.aggregate(average_price = Avg( 'price' )) { 'average_price' : 34.35 } |
如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
1
2
3
|
>>> from django.db.models import Avg, Max , Min >>> Book.objects.aggregate(Avg( 'price' ), Max ( 'price' ), Min ( 'price' )) { 'price__avg' : 34.35 , 'price__max' : Decimal( '81.20' ), 'price__min' : Decimal( '12.99' )} |
五、分组
单表分组查询:
key:annotate()前values里是哪一个字段,就按哪一个字段group by
# 查询书籍表每一个出版社id以及对应的书籍个数
ret = Book.objects.values('publish_id').annotate(c=Count(1)) # 查询每一个部门的名称以及对应员工的平均薪水
ret = Emp.objects.values('dep').annotate(avg_salary = Avg('salary')) # 查询每一个省份的名称以及对应的员工最大年龄
ret = Emp.objects.values('pro').annotate(max_age = Max('age'))
注意:单表按主键分组没有意义
跨表分组查询:
# 查询每一个出版社的名称以及对应的书籍平均价格
ret = Publish.objects.annotate(avg_price = Avg('book__price')).values('name','avg_price') # 查询每一个作者的名字以及出版的书籍的最高价格
ret = Author.objects.annotate(max_price=Max('book__price')).values('name','max_price') # 查询每一个书籍的名称以及对应的作者的个数
ret = Book.objects.annotate(c=Count('authors')).values('c') #查询作者数不止一个的书籍名称以及作者个数
Book.objects.annotate(c=Count('authors__name')).filter(c__gt=1).values('title','c') #根据一本图书作者数量的多少对查询集 QuerySet进行排序
Book.objects.annotate(c=Count('authors__name')).order_by('c') #统计每一本以py开头的书籍的名称以及作者个数
Book.objects.filter(title__startswith='py').annotate(c=Count('authors__name')).values('title','c')
六、F查询与Q查询
F查询:
在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
1
2
3
4
|
# 查询评论数大于收藏数的书籍 from django.db.models import F Book.objects. filter (commnetNum__lt = F( 'keepNum' )) |
Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
1
2
|
# 查询评论数大于收藏数2倍的书籍 Book.objects. filter (commnetNum__lt = F( 'keepNum' ) * 2 ) |
修改操作也可以使用F函数,比如将每一本书的价格提高30元:
1
|
Book.objects. all ().update(price = F( "price" ) + 30 ) |
Q查询:
filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q对象。
1
2
|
from django.db.models import Q Q(title__startswith = 'Py' ) |
Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
1
|
bookList = Book.objects. filter (Q(authors__name = "yuan" )|Q(authors__name = "egon" )) |
等同于下面的SQL WHERE 子句:
1
|
WHERE name = "yuan" OR name = "egon" |
你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:
1
|
bookList = Book.objects. filter (Q(authors__name = "yuan" ) & ~Q(publishDate__year = 2017 )).values_list( "title" ) |
查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:
1
2
3
|
bookList = Book.objects. filter (Q(publishDate__year = 2016 ) | Q(publishDate__year = 2017 ), title__icontains = "python" ) |
Q查询的另外一种写法:
q=Q()
q.connector="or" #如果不写默认为and
q.children.append(("title__startswith","py"))
q.children.append(("price__gt",100))
注意:q.children.append()元组中的数据可以进行字符串的拼接,如下
val = request.GET.get('q')
field = request.GET.get('field')
if val:
q = Q()
q.children.append((field + '__contains', val)) # 注意里面放的是元组
customer_list = customer_list.filter(q)
补充知识点:中介模型
试想一下有student和score两个表模型,两张表是多对多的关系,此时可以生成student_score第三个表,但是通过ManyToMany自动生成的第三张表,表里面的字段也是自动生成的,第三张表可以自动生成三个字段:id student_id score_id,但此时我们的需求是在第三张表里面还要有一个score字段,此时中介模型就可以很好的帮我们解决这个问题。
class Student(models.Model):
name = models.CharField( max_length=32)
courses=models.ManyToManyField("Courses",through="Score")
#through='score'可以翻译成第三张score表不需要通过ManyToMany自动生成,要用自己写的score表,在自己写的score表中,可以随表写自己业务需求的字段,orm查询语句可以照常使用 class Course(models.Model):
name = models.CharField( max_length=32) class Score(models.Model):
student=models.ForeignKey("Student")
course=models.ForeignKey("Course")
score=models.IntegerField()
ORM之多表操作的更多相关文章
- Django中模型层中ORM的单表操作
ORM概念: MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员 ...
- ORM的单表操作
ORM的单表操作 MTV框架包含一个重要的部分就是ORM----对象关系映射(Object Relational Mapping),它实现了数据模型与数据库的解耦,即数据模型的设计.利用它我们不需要依 ...
- ORM之连表操作
ORM之连表操作 -----------------------------连表的正向操作------------------------- 在models.py中创建两张表UserType和User ...
- Django学习手册 - ORM 数据创建/表操作 汇总
ORM 查询的数据类型: QuerySet与惰性机制(可以看作是一个列表) 所谓惰性机制:表名.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它 ...
- ORM 简介 单表操作
cls超 Django基础五之django模型层(一)单表操作 本节目录 一 ORM简介 二 单表操作 三xxx 一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型 ...
- Django中模型层中ORM的多表操作
ORM的多表创建(一对一.一对多,多对多): 1模型创建 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等 ...
- Django开发:(3.1)ORM:单表操作
MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需 ...
- ORM之单表操作
ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的 ...
- Django开发:(3.2)ORM:多表操作
表关系总结: 一对多:在多的表中建立关联字段 多对多:创建第三张表(关联表):id 和 两个关联字段 一对一:在两张表中的任意一张表中建立关联字段(关联字段一定要加 unique 约束) 子查询:一次 ...
随机推荐
- Spring MVC-从零开始-web.xml中classpath和classpath* 有什么区别
web.xml中classpath和classpath* 有什么区别?classpath:只会到你的class路径中查找找文件;classpath*:不仅包含class路径,还包括jar文件中(cla ...
- 使用 .gitignore 忽略 Git 仓库中的文件
.gitignore 在Git中,很多时候你只想将代码提交到仓库,而不是将当前文件目录下的文件全部提交到Git仓库中,例如在MacOS系统下面的.DS_Store文件,或者是Xocde的操作记录,又或 ...
- SSM框架手动实现分页逻辑(非PageHelper)
第一种方法:查询出所有数据再分页 分析: 分页时,需要获得前台传来的两个参数,分别为pageNo(第几页数据),pageSize(每页的条数); 根据这两个参数来计算出前端需要的数据是查出数据list ...
- MongoDB的查询索引
目录 为什么要建立索引? 索引的分类有哪些? _id索引 单键索引 多键索引 复合索引 过期索引 hello,今天是万圣节
- redis服务打不开--解决办法
D:\>redis-server[11896] 04 Dec 19:20:05.122 # Warning: no config file specified, using the defaul ...
- python——成语接龙小游戏
小试牛刀的简易成语接龙. 思路—— 1.网上下载成语字典的txt版本 2.通过python进行处理得到格式化的成语,并整理成字典(python字典查找速度快) 3.python程序,查找 用户输入的最 ...
- linux分析工具之lsof详解
一.概述 在linux中,所有东西都是以文件的形式存在的,所以我们在linux上的操作都是通过对文件的操作来执行我们所需要的逻辑,比如我们对文件数据的访问,修改,访问网络的连接等,刚好lsof(lis ...
- [Swoole] 在Ubuntu下安装、快速开始
本文主要讲述在 Ubuntu 下编译安装 Swoole,并根据官方文档给出的demo进行了测试和搬运,包括:TCP服务器.UDP服务器.HTTP服务器.WebSocket服务器.异步客户端.定时器和协 ...
- Tomcat源码分析二:先看看Tomcat的整体架构
Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...
- python基本数据类型及常用功能
1.数字类型 int -int(将字符串转换为数字) a = " print(type(a),a) b = int(a) print(type(b),b) num = " v = ...