django -- ORM查询
前戏
在我们之前操作ORM中,你也许是启动Django项目,通过地址访问固定的函数,或者在pycharm里的python console里执行,第一种比较麻烦,而且每次都要启动项目,写路由,第二种虽然不需要写路由,但是写的东西保存不下来,只要关闭就没有了。今天来通过python脚本的形式来写,既不需要启动项目,也可以保存
在项目下面创建一个python文件,里面写如下代码
- import os
- if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目名.settings")
- import django
- django.setup()
- from appTest01 import models # 导入视图函数
- obj = models.Person.objects.all()
- print(obj)
这样我们就可以写ORM语句,只需要右键运行就可以了
如果想查看ORM转为的SQL语句,只需要在项目的settings.py里写如下代码就可以把SQL语句打印到控制台上
- LOGGING = {
- 'version': 1,
- 'disable_existing_loggers': False,
- 'handlers': {
- 'console':{
- 'level':'DEBUG',
- 'class':'logging.StreamHandler',
- },
- },
- 'loggers': {
- 'django.db.backends': {
- 'handlers': ['console'],
- 'propagate': True,
- 'level':'DEBUG',
- },
- }
- }
ORM常用查询
数据库里数据如下
- import os
- if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_project.settings")
- import django
- django.setup()
- from appTest01 import models
- # all() 查询所有结果,返回的是对象列表。如果要获取对应的字段值,先取索引,在用.字段名
- # 比如下面的要获取第二个姓名,ret[1].name
- ret = models.Person.objects.all()
- # print(ret) <QuerySet [<Person: Person object>, <Person: Person object>, <Person: Person object>]>
- # get() 查询到的是对象,有且只能有一个,要不然会报错,要获取对应的字段值直接用.
- # 比如下面的要获取姓名,ret.name
- ret = models.Person.objects.get(id=1)
- # print(ret) Person object
- # filter() 查询出满足条件的对象,返回的是对象列表,获取对应的值也要使用索引的方式
- ret = models.Person.objects.filter(id=1)
- # print(ret) <QuerySet [<Person: Person object>]>
- # exclude() 查询出所有不满足条件的对象,返回的是对象列表,获取对应的值也要使用索引的方式
- ret = models.Person.objects.exclude(id=1)[1]
- # print(ret.name) 王五
- # value() 具体的数据,没有指定参数,获取所有的字段数据,指定参数,获取指定字段数据
- ret = models.Person.objects.values()
- # for i in ret:
- # print(i)
- '''
- {'id': 1, 'name': 'zouzou', 'age': 25, 'birth': datetime.datetime(2019, 7, 19, 15, 7, 15, 296496, tzinfo=<UTC>)}
- {'id': 2, 'name': '张三', 'age': 43, 'birth': datetime.datetime(2019, 7, 20, 14, 4, 4, tzinfo=<UTC>)}
- {'id': 3, 'name': '王五', 'age': 23, 'birth': datetime.datetime(2019, 7, 28, 14, 4, 23, tzinfo=<UTC>)}
- '''
- # values_list() 具体的数据,没有指定参数,获取所有的字段数据,指定参数,获取指定字段数据
- ret = models.Person.objects.values_list()
- # for i in ret:
- # print(i)
- '''
- (1, 'zouzou', 25, datetime.datetime(2019, 7, 19, 15, 7, 15, 296496, tzinfo=<UTC>))
- (2, '张三', 43, datetime.datetime(2019, 7, 20, 14, 4, 4, tzinfo=<UTC>))
- (3, '王五', 23, datetime.datetime(2019, 7, 28, 14, 4, 23, tzinfo=<UTC>))
- '''
- # order_by() 对查询结果排序,前面加-表示降序,不写表示升序
- # 可以指定多个字段,如果第一个字段相同,则以第二个排,以此类推
- ret = models.Person.objects.all().order_by('-id')[0]
- # print(ret.id) 3
- # reverse() 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)
- # ordering=('id',)
- ret = models.Person.objects.all().order_by('-id').reverse()[0]
- # print(ret.id) 1
- # distinct() 去重 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
- # count() 计数
- ret = models.Person.objects.all().count()
- # print(ret) 3
- # first() 返回第一条记录,取值不需要按索引
- ret = models.Person.objects.all().first()
- # print(ret.name) zouzou
- # last() 返回最后一条记录,取值不需要按索引
- ret = models.Person.objects.all().last()
- # print(ret.name) 王五
- # exists() 如果QuerySet包含数据,就返回True,否则返回False
- ret = models.Person.objects.filter(name='赵六').exists()
- # print(ret) False
总结:
返回QuerySet对象的方法有
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的QuerySet
values() 返回一个可迭代的字典序列
values_list() 返回一个可迭代的元组序列
返回具体对象的
get()
first()
last()
返回布尔值的
exists()
返回数字的
count()
双下划线方法
前面的都是查询某个值等于什么什么的。但是我们经常会查询大于多少,比如成绩大于60分的,这时候就要用到双下滑线方法了
- ret = models.Person.objects.filter(id__gt=1) # id大于1
- ret = models.Person.objects.filter(id__gte=1) # id大于等于1
- ret = models.Person.objects.filter(id__lt=3) # id小于3
- ret = models.Person.objects.filter(id__lte=3) # id小于等于3
- ret = models.Person.objects.filter(id__in=[1, 3]) # id为1和3的
- ret = models.Person.objects.filter(id__gte=1, id__lte=3) # id大于等于1并且小于等于3的
- ret = models.Person.objects.filter(id__range=[1,3]) # id大于等于1并且小于等于3的
- ret = models.Person.objects.filter(name__contains='u') # name里包含字母u的,区分大小写
- ret = models.Person.objects.filter(name__icontains='u') # name里包含字母u的,不区分大小写
- ret = models.Person.objects.filter(name__startswith='z') # 以z开头,区分大小写
- ret = models.Person.objects.filter(name__istartswith='z') # 以z开头,不区分大小写
- ret = models.Person.objects.filter(name__endswith='u') # 以u结尾,区分大小写
- ret = models.Person.objects.filter(name__iendswith='u') # 以u结尾,不区分大小写
- ret = models.Person.objects.filter(birth__year='') # 查询年份为2019
ForeignKey查询
先来创建几张表
- class Press(models.Model):
- name = models.CharField(max_length=32)
- def __str__(self):
- return '<Press %s-%s>'%(self.id,self.name)
- class Book(models.Model):
- title = models.CharField(max_length=32)
- price = models.IntegerField()
- publisher = models.ForeignKey(to='Press')
- def __str__(self):
- return '<Book %s-%s>'%(self.id, self.title)
- class Author(models.Model):
- name = models.CharField(max_length=32)
- books = models.ManyToManyField(to='Book')
创建表
往press表和book表里添加一些数据,如下
- book_obj = models.Book.objects.get(id=1)
- print(book_obj.title) # linux
- print(book_obj.price) #
- print(book_obj.publisher_id) #
- print(book_obj.publisher) # publisher对应的上Press表,所以是press对象---》<Press 2-清华出版社>
- print(book_obj.publisher.name) # press里对应的name---》清华出版社
查找上海出版社的书
常规写法
- models.Book.objects.filter(publisher_id=models.Press.objects.get(name='上海出版社').id)
结果:
- <QuerySet [<Book: <Book 2-python入门到放弃>>, <Book: <Book 3-java直接放弃>>]>
高级写法
- obj = models.Book.objects.filter(publisher__name='上海出版社')
publisher__name ,前面的publisher为Book表里的字段,对应的结果是Press这个表对象,__name表示press表里的name字段
反向查询
上面的查询是通过book表查询press表的里数据,因为外键是写在book表里的,我们把这种叫做正向查询
通过press表查询book表里的数据,我们叫做反向查询
通过press里的id查找对应的书
- obj = models.Press.objects.get(id=3)
- print(obj.book_set.all())
结果:
- <QuerySet [<Book: <Book 2-python入门到放弃>>, <Book: <Book 3-java直接放弃>>]>
book_set,表名小写_set得到的是一个管理对象,如果要获取所有的对象,在后面写.all()
还有另一种写法是在表里的字段后面写上related_name
- class Book(models.Model):
- title = models.CharField(max_length=32)
- price = models.IntegerField()
- publisher = models.ForeignKey(to='Press', related_name='mybook')
- def __str__(self):
- return '<Book %s-%s>'%(self.id, self.title)
上面的查询就变成
- obj = models.Press.objects.get(id=3)
- print(obj.mybook.all())
正向查询书名也要用mybook_xxx='xxx'
根据书名查询出版社
常规写法
- obj = models.Press.objects.filter(id=models.Book.objects.get(title='python入门到放弃').publisher_id)
结果:
- <QuerySet [<Press: <Press 3-上海出版社>>]>
高级写法
- obj = models.Press.objects.filter(book__title='python入门到放弃')
ManyToManyField
在我们创建表的时候,book和author是多对多的关系,先来看一下他们之间的关系
set() 更新model对象的关联对象
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
- obj.books.set(models.Book.objects.all())
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
- obj.books.set([1,3])
add() 把指定的model对象添加到关联对象集中。
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
- obj.books.add(*[2,4])
add还可以这样写
- obj.books.add(1,2,3,4)
- obj.books.add(*models.Book.objects.all())
remove() 从关系对象中移除执行的model对象
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
obj.books.remove(1,4)
删除全部
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
- obj.books.remove(*models.Book.objects.all())
clear() 从关联对象集中移除一切对象
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
- obj.books.clear()
创建书和对应的关系
- obj = models.Author.objects.get(id=1)
- # print(obj.name) 孙悟空
- obj.books.create(title='一小时精通Django',price=66,publisher_id=3)
反向查询
- class Author(models.Model):
- name = models.CharField(max_length=32)
- books = models.ManyToManyField(to='Book')
因为books是写在Author表里,所以通过Author查询book表里的是正向查询,通过book表查询author表里的是反向查询
- obj = models.Book.objects.get(id=5)
- print(obj.author_set.all())
反向查询要使用表名_set
注意:对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
栗子
ForeignKey字段没设置null=True时
- class Book(models.Model):
- title = models.CharField(max_length=32)
- publisher = models.ForeignKey(to=Publisher)
没有clear()和remove()方法:
- >>> models.Publisher.objects.first().book_set.clear()
- Traceback (most recent call last):
- File "<input>", line 1, in <module>
- AttributeError: 'RelatedManager' object has no attribute 'clear'
当ForeignKey字段设置null=True时
- class Book(models.Model):
- name = models.CharField(max_length=32)
- publisher = models.ForeignKey(to=Class, null=True)
此时就有clear()和remove()方法:
- models.Publisher.objects.first().book_set.clear()
聚合查询
在sql语句中,我们知道聚合语句,比如查询最大值,最小值,平均值等等。在ORM中,使用aggregate()来进行聚合查询,首先需要导入
- from django.db.models import Max, Min, Avg, Sum, Count
查询价格最大是多少
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.aggregate(Max('price'))
- print(ret)
- ret = models.Book.objects.all().aggregate(Max('price'))
- print(ret)
结果:
- {'price__max': 66}
- {'price__max': 66}
结果是一个字典格式,key为“字段_聚合名”,如果你看它不爽,你也可以自定义
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.aggregate(最大值=Max('price'),最小值=Min('price'))
- print(ret)
结果:
- {'最大值': 66, '最小值': 22}
注意:如果你查询了多个,有些聚合你自己定义了名称,有些你没有定义名称,则没有定义名称的要放在前面(位置参数不能在关键字参数后面)
分组查询
先来看一下数据表关系
查询出每本书的作者
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.annotate(num=Count('author'))
- print(ret)
结果是QuerySet
- <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>
使用.values()获取所有
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.annotate(num=Count('author')).values()
- for i in ret:
- print(i)
结果:
- {'id': 1, 'title': 'linux', 'price': 22, 'publisher_id': 2, 'num': 1}
- {'id': 2, 'title': 'python入门到放弃', 'price': 55, 'publisher_id': 3, 'num': 0}
- {'id': 3, 'title': 'java直接放弃', 'price': 22, 'publisher_id': 3, 'num': 1}
- {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'num': 2}
- {'id': 5, 'title': '一小时精通Django', 'price': 66, 'publisher_id': 3, 'num': 1}
可以在value里指定参数获取想要的字段
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.annotate(num=Count('author')).values('title','num')
- for i in ret:
- print(i)
结果:
num对应的值就是这本书作者的个数
- {'title': 'linux', 'num': 1}
- {'title': 'python入门到放弃', 'num': 0}
- {'title': 'java直接放弃', 'num': 1}
- {'title': 'go精通', 'num': 2}
- {'title': '一小时精通Django', 'num': 1}
统计每个出版社最便宜的书的价格
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.values('publisher_id').annotate(min_num=Min('price'))
- for i in ret:
- print(i)
结果:
- {'publisher_id': 1, 'min_num': 54}
- {'publisher_id': 2, 'min_num': 22}
- {'publisher_id': 3, 'min_num': 22}
因为不分组的结果
- from django.db.models import Max, Min, Avg, Sum, Count
- ret = models.Book.objects.values('publisher_id')
- for i in ret:
- print(i)
结果:
- {'publisher_id': 1}
- {'publisher_id': 2}
- {'publisher_id': 3}
- {'publisher_id': 3}
- {'publisher_id': 3}
统计不止一个作者的图书
- ret = models.Book.objects.annotate(num=Count('author')).filter(num__gt=1).values()
- for i in ret:
- print(i)
结果:
- {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'num': 2}
查询各个作者出的书的总价格
F查询
在之前的查询中,我们都是拿某个字段对一个固定的值做比较,如果想用字段和字段做比较,就要用到F查询了,先来看下数据表里的数据
需求,查出所有num大于money的
- from django.db.models import F
- ret = models.Book.objects.filter(num__gt=F('money')).values()
- for i in ret:
- print(i)
结果:
- {'id': 1, 'title': 'linux', 'price': 22, 'publisher_id': 2, 'money': 23, 'num': 65}
- {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'money': 33, 'num': 88}
- {'id': 5, 'title': '一小时精通Django', 'price': 66, 'publisher_id': 3, 'money': 44, 'num': 99}
需求:给每个num的值*2
之前的都是对某一条数据更新的,如
- ret = models.Book.objects.get(id=2)
- ret.num=24
- ret.save()
上面的这种写法要进行save(),而且要写更新的具体数值
使用update更新
- ret = models.Book.objects.filter(id=2).update(num=50)
update就不需要save
- ret = models.Book.objects.update(num=50) # 对所有的数据更新
这两种写法都满足不了我们的需求,我们用F来实现,下面两种结果是一样的
- from django.db.models import F
- ret = models.Book.objects.update(num=F('num')*2)
- ret = models.Book.objects.all().update(num=F('num')*2)
需求:在所有书名后面加上(测试)
- ret = models.Book.objects.update(title=Concat(F("title"), Value("("), Value("测试"), Value(")")))
不需要()
- ret = models.Book.objects.update(title=Concat(F("title"), Value("测试")))
Q查询
之前我们所有进行的查询都是and关系的,如果要使用or关系的查询,就要用Q查询了。继续看数据表数据
需求:查询id小于3并且大于等于6的
- from django.db.models import Q
- ret = models.Author.objects.filter(Q(id__lt=3) | Q(id__gte=6)).values()
- for i in ret:
- print(i)
结果:管道符( | )表示或的关系
- {'id': 1, 'name': '孙悟空'}
- {'id': 2, 'name': '猪八戒'}
- {'id': 6, 'name': '蜘蛛精'}
- {'id': 7, 'name': '女儿国'}
- {'id': 8, 'name': '紫霞仙子'}
&表示并且的关系
- from django.db.models import Q
- ret = models.Author.objects.filter(Q(id__lt=7) & Q(id__gte=6)).values()
- for i in ret:
- print(i)
结果:
- {'id': 6, 'name': '蜘蛛精'}
~表示取反
- from django.db.models import Q
- ret = models.Author.objects.filter(~Q(id__lt=7) & Q(id__gte=6)).values()
- for i in ret:
- print(i)
结果:
- {'id': 7, 'name': '女儿国'}
- {'id': 8, 'name': '紫霞仙子'}
事务
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
针对上面的描述可以看出,事务的提出主要是为了解决并发情况下保持数据一致性的问题。
事务具有以下4个基本特征。
- Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
- Consistency(一致性):只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初状态。
- Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
- Durability(持久性):事务结束后,事务处理的结果必须能够得到固化。
- import os
- if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_project.settings")
- import django
- django.setup()
- from appTest01 import models
- try:
- from django.db import transaction
- with transaction.atomic():
- 这里写要执行的ORM语句
- except Exception as e:
- print(str(e))
django -- ORM查询的更多相关文章
- Django ORM 查询管理器
Django ORM 查询管理器 ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言 ...
- django orm查询和后端缓存的使用
django orm 查询 1 字段后(db_column='age') (null=True)#表示数据库里面的该字段数据可以为空 (blank=True)#表示前端表单提交的时候可以为空 (db_ ...
- Django 源码小剖: Django ORM 查询管理器
ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从 ...
- Django(ORM查询2)
day70 ORM训练专题 :http://www.cnblogs.com/liwenzhou/articles/8337352.html 内容回顾 1. ORM 1. ORM ...
- Python - Django - ORM 查询方法
models.py: from django.db import models class Human(models.Model): id = models.AutoField(primary_key ...
- Django(ORM查询联系题)
day70 练习题:http://www.cnblogs.com/liwenzhou/articles/8337352.html import os import sys if __name__ == ...
- Django(ORM查询1)
day69 参考:http://www.cnblogs.com/liwenzhou/p/8660826.html 在Python脚本中调用Django环境 orm1.py import os if _ ...
- Django ORM 查询
过滤器 过滤器 作用 all() 查出所有行 filter() 可以添加过滤条件 order_by() 查出所有数据,如果有参数则按参数排序,参数是字符串 ,如:"-username&quo ...
- Django orm查询操作
基于双下划线查询切记!!!!正向查询按字段,反向查询按表名的小写 正向:在Book表里设置关联Obj表,Book------>Obj就是正向查询 反向:在Book表里设置关联Obj表,Obj-- ...
随机推荐
- javascript 对象,函数,原型和 this
1.对象 在javascript里,一切都是对象,包括函数自身(不是指具体的函数,而是指"Function"这个东东).例如: var fun1=new Function(&quo ...
- maven基本知识的7个提问
在如今的互联网项目开发当中,特别是Java领域,Maven的仓库管理.依赖管理.继承和聚合等特性为项目的构建提供了一整套完善的解决方案. 这里我们通过7个关于Maven的提问来了解Maven的一些基本 ...
- 04、状态模式(State)
一.概念: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类.[DP] 二.作用: 状态模式的主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况.吧状态的判断逻辑转 ...
- 前端学习:JS(面向对象)代码笔记
前端学习:JS(面向对象)代码笔记 前端学习:JS面向对象知识学习(图解) 创建类和对象 创建对象方式1调用Object函数 <body> </body> <script ...
- 【LeetCode】145. Binary Tree Postorder Traversal
Difficulty: Hard More:[目录]LeetCode Java实现 Description https://leetcode.com/problems/binary-tree-pos ...
- WebAPI HelpPage帮助页
WebAPI HelpPage是个插件,根据代码的注释生成API说明页,一目了然. 下面开始安装和配置 1.添加引用 先选择管理NuGet程序包,搜索 Microsoft.AspNet.WebApi. ...
- webapi ClaimsPrincipal使用
参考文档:ClaimsPrincipal Class 个人demo:SwaggerDemoApi 今天看到一段代码懵逼了 var principal = new ClaimsPrincipal(new ...
- Linux用户管理(4)
Linux系统是一个多用户多任务的操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.Linux用户至少属于一个组. 1.添加用户 useradd ...
- MySQL难点语法——连接
本篇涉及的数据表格可以自行查阅上篇<MySQL难点语法——子查询> MySQL的数据表格之间有三种连接方式:等值连接.外连接.自连接.以下是通过举例介绍这三种连接方式 1.等值连接 等值连 ...
- SQLMAP源码阅读(一)