前戏

在我们之前操作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查询的更多相关文章

  1. Django ORM 查询管理器

    Django ORM 查询管理器 ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言 ...

  2. django orm查询和后端缓存的使用

    django orm 查询 1 字段后(db_column='age') (null=True)#表示数据库里面的该字段数据可以为空 (blank=True)#表示前端表单提交的时候可以为空 (db_ ...

  3. Django 源码小剖: Django ORM 查询管理器

    ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从 ...

  4. Django(ORM查询2)

    day70 ORM训练专题 :http://www.cnblogs.com/liwenzhou/articles/8337352.html 内容回顾     1. ORM         1. ORM ...

  5. Python - Django - ORM 查询方法

    models.py: from django.db import models class Human(models.Model): id = models.AutoField(primary_key ...

  6. Django(ORM查询联系题)

    day70 练习题:http://www.cnblogs.com/liwenzhou/articles/8337352.html import os import sys if __name__ == ...

  7. Django(ORM查询1)

    day69 参考:http://www.cnblogs.com/liwenzhou/p/8660826.html 在Python脚本中调用Django环境 orm1.py import os if _ ...

  8. Django ORM 查询

    过滤器 过滤器 作用 all() 查出所有行 filter() 可以添加过滤条件 order_by() 查出所有数据,如果有参数则按参数排序,参数是字符串 ,如:"-username&quo ...

  9. Django orm查询操作

    基于双下划线查询切记!!!!正向查询按字段,反向查询按表名的小写 正向:在Book表里设置关联Obj表,Book------>Obj就是正向查询 反向:在Book表里设置关联Obj表,Obj-- ...

随机推荐

  1. Scratch 3.6环境搭建(万江波实战记录)

    1.Scratch官网在线环境 官方网址:scratch.mit.edu 进入后,点击“Create”建立 2. Scratch官网在线环境_简体中文(点击这个地球) 3-选择:创意 4-进入”创意“ ...

  2. mysql插入数据频繁出现坏表

    测试环境mysql出现了一个怪表:select查询表卡死,alter修改表卡死,甚至我不想要这个表了,delete.truncate.drop表都卡死卡主了...... 解决办法: >show ...

  3. __attribute__((format(printf, a, b)))

    最近,在看libevent源码,第一次看到__attribute__((format(printf, a, b)))这种写法.因此,在这里记录下用法. 功能:__attribute__ format属 ...

  4. C#中字符串的操作大全

    一.C#中字符串的建立过程 例如定义变量 strT="Welcome to "; strT+="www.cuit.edu.cn"; 程序首先创建一个System ...

  5. Markdown温故知新(0):导航目录

    Markdown温故知新(0):导航目录 Markdown温故知新(1):Markdown面面观 Markdown温故知新(2):详解七大标准语法 Markdown温故知新(3):六个实用扩展语法 M ...

  6. Go 笔记之如何防止 goroutine 泄露

    今天来简单谈谈,Go 如何防止 goroutine 泄露. 概述 Go 的并发模型与其他语言不同,虽说它简化了并发程序的开发难度,但如果不了解使用方法,常常会遇到 goroutine 泄露的问题.虽然 ...

  7. git tag 常用笔记

    git tag 常用笔记 查看 tag 列出现有 tag git tag 列出 v1.4.2 相关的 tag git tag -l "v1.4.2" 查看指定 tag 的信息 gi ...

  8. python排序 基数排序

    算法思想 基数排序通过按位比较(一般从最低位开始)将元素按照最低位的数放到10个桶中,当所有的元素都这样被处理一次后,在按从0到9的顺序将每个桶的元素再取出来(不关注其他位的,只关注当前位的)这样就完 ...

  9. Java自学-I/O 中文问题

    Java中的编码中文问题 步骤 1 : 编码概念 计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字. 就像一个棋盘一样,不同的字,处于不同的位置,而不同的位置,有不同的数字编号. 有的棋盘 ...

  10. 基于vue+springboot+docker网站搭建【六】安装中间件

    安装中间件 去另外一台2核4G的机器先安装docker,然后安装后台项目使用的中间件 一.mysql 下载镜像:docker pull mysql:5.7 启动镜像实例:docker run -p 3 ...