内容简介:为了说明这部分的例子,模型结构如下:"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。它存在于下面两种情况:
起步
为了说明这部分的例子,模型结构如下:
class Publisher(models.Model): # 出版社
name = models.CharField(max_length=31)
class Book(models.Model): # 书
name = models.CharField(max_length=31)
price = models.DecimalField(max_digits=5, decimal_places=2)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
class Author(models.Model): # 作者
name = models.CharField(max_length=31)
books = models.ManyToManyField(to=Book)
ForeignKey的正向查询与反向查询
正向查找
book_obj = models.Book.objects.first() # 第一本书对象
print(book_obj.publisher) # 得到这本书关联的出版社对象
print(book_obj.publisher.name) # 得到出版社对象的名称
print(models.Book.objects.values_list("publisher__name"))
反向查找
publisher_obj = models.Publisher.objects.first() # 找到第一个出版社对象
books = publisher_obj.book_set.all() # 找到第一个出版社出版的所有书
titles = books.values_list("title") # 找到第一个出版社出版的所有书的书名
titles = models.Publisher.objects.values_list("book__title")
ManyToManyField 多对多操作
"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。
它存在于下面两种情况:
- 外键关系的反向查询
- 多对多关联关系
简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。
create()
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。
models.Author.objects.first().book_set.create(name="番茄物语"))
add()
把指定的model对象添加到关联对象集中。
author_objs = models.Author.objects.filter(id__lt=3) models.Book.objects.first().authors.add(*author_objs) # 或者 models.Book.objects.first().authors.add(*[1, 2])
set()
更新model对象的关联对象。
book_obj = models.Book.objects.first() book_obj.authors.set([2, 3])
remove()
从关联对象集中移除执行的model对象
book_obj = models.Book.objects.first() book_obj.authors.remove(3)
clear()
从关联对象集中移除一切对象
book_obj = models.Book.objects.first() book_obj.authors.clear() # PS: 对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
聚合查询和分组查询
聚合
aggregate()
是 QuerySet
的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
用到的内置函数:
from django.db.models import Avg, Sum, Max, Min, Count
ret = models.Book.objects.all().aggregate(Avg('price'))
print(ret) # {'price__avg': 12.31}
ret = models.Book.objects.all().aggregate(mykey=Avg('price'))
print(ret) # {'mykey': 12.31}
ret = models.Book.objects.all().aggregate(price_avg=Avg('price'), price_max=Max('price'),
price_sum=Sum('price'))
print(ret) # {'price_avg': 12.31, 'price_max':Decimak('99'), 'price_sum':Decimal('999')}
执行的 sql 语句分别是:
SELECT AVG(`lab_book`.`price`) AS `price__avg` FROM `lab_book`; args=() SELECT AVG(`lab_book`.`price`) AS `mykey` FROM `lab_book`; args=() SELECT AVG(`lab_book`.`price`) AS `price_avg`, MAX(`lab_book`.`price`) AS `price_max`, SUM(`lab_book`.`price`) AS `price_sum` FROM `lab_book`; args=()
分组
书和作者的表是多对多关系
# 查询名字相同的作者数量
# models.Author.objects.annotate(cnt=Count('name')).values('name') # 这样是不行的
ret = models.Author.objects.values('name').annotate(cnt=Count('name'))
# 或者ret = models.Author.objects.all().values('name').annotate(cnt=Count('name')) # 可行
for item in ret: # <QuerySet [{'name': 'author1', 'cnt': 1}, {'name': 'author2', 'cnt': 2}]>
print(item) # {'name': 'author2', 'cnt': 2}
# sql语句是:
SELECT `lab_author`.`name`, COUNT(`lab_author`.`name`) AS `cnt` FROM `lab_author` GROUP BY `lab_author`.`name` ORDER BY NULL; args=()
# 查询每一本书的作者个数
ret = models.Book.objects.all().annotate(author_num=Count('author'))
# print(ret)
for item in ret:
print(item.author_num)
# sql语句是:
SELECT `lab_book`.`id`, `lab_book`.`name`, `lab_book`.`price`, COUNT(`lab_author_books`.`author_id`) AS `author_num` FROM `lab_book`
LEFT OUTER JOIN `lab_author_books` ON (`lab_book`.`id` = `lab_author_books`.`book_id`)
GROUP BY `lab_book`.`id` ORDER BY NULL; args=()
# 查询作者数量大于1的书
ret = models.Book.objects.all().annotate(author_num=Count('author')).filter(author_num__gt=1)
for item in ret:
print(item.author_num)
# sql语句是:
SELECT `lab_book`.`id`, `lab_book`.`name`, `lab_book`.`price`, COUNT(`lab_author_books`.`author_id`) AS `author_num` FROM `lab_book`
LEFT OUTER JOIN `lab_author_books` ON (`lab_book`.`id` = `lab_author_books`.`book_id`
GROUP BY `lab_book`.`id` HAVING COUNT(`lab_author_books`.`author_id`) > 1 ORDER BY NULL; args=(1,)
# 查询各个作者出的书的总价格
ret = models.Book.objects.all().annotate(author_num=Count('author')).filter(author_num__gt=1).order_by('author_num')
for item in ret:
print(item.author_num)
# sql语句是:
SELECT `lab_author`.`id`, `lab_author`.`name`, SUM(`lab_book`.`price`) AS `sum_price` FROM `lab_author`
LEFT OUTER JOIN `lab_author_books` ON (`lab_author`.`id` = `lab_author_books`.`author_id`)
LEFT OUTER JOIN `lab_book` ON (`lab_author_books`.`book_id` = `lab_book`.`id`)
GROUP BY `lab_author`.`id` ORDER BY NULL; args=()
F 与 Q 查询
Django 提供 F()
来做这样的比较。 F()
的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
# 查询评论数大于收藏数的书籍
from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F('keep_num'))
# 常数之间的加减乘除和取模的操作
models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)
# 修改操作也可以使用F函数,比如将每一本书的价格提高30元
models.Book.objects.all().update(price=F("price")+30)
修改char字段:
# 给每一本书书名后面加上 "(第一版)"
from django.db.models.functions import Concat
from django.db.models import Value, F
models.Book.objects.update(name=Concat(F('name'), Value('(第一版)')))
# 执行的sql是:
UPDATE `lab_book` SET `name` = CONCAT_WS('', `lab_book`.`name`, '(第一版)'); args=('(第一版)',)
Q查询
filter()
等方法中的关键字参数查询都是一起进行 AND
的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
# 查询作者名是小仙女或小魔女的 models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))
可以组合 &
和 |
操作符以及使用括号进行分组来编写任意复杂的 Q 对象。同时,Q 对象可以使用 ~
操作符取反,这允许组合正常的查询和取反(NOT) 查询。
models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
锁和事务
这部分需要数据库引擎支持事务操作,如果不支持,sql依然会执行,但不会回滚。
锁
select_for_update(nowait=False, skip_locked=False)
返回一个锁住行直到事务结束的查询集,如果数据库支持,它将生成一个 SELECT ... FOR UPDATE 语句。
entries = Entry.objects.select_for_update().filter(author=request.user)
所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
一般情况下如果其他事务锁定了相关行,那么本查询将被阻塞,直到锁被释放。 如果这不想要使查询阻塞的话,使用select_for_update(nowait=True)。 如果其它事务持有冲突的锁, 那么查询将引发 DatabaseError 异常。你也可以使用select_for_update(skip_locked=True)忽略锁定的行。 nowait和skip_locked是互斥的,同时设置会导致ValueError。
目前,postgresql,oracle和 mysql 数据库后端支持select_for_update()。 但是,MySQL不支持nowait和skip_locked参数。
使用不支持这些选项的数据库后端(如MySQL)将nowait=True或skip_locked=True转换为select_for_update()将导致抛出DatabaseError异常,这可以防止代码意外终止。
from django.db import transaction
with transaction.atomic():
entries = models.Publisher.objects.select_for_update().filter(id=1)
entries.update(name='222')
print(entries)
# 执行的sql
UPDATE `lab_publisher` SET `name` = '222' WHERE `lab_publisher`.`id` = 1; args=('222', 1)
SELECT `lab_publisher`.`id`, `lab_publisher`.`name` FROM `lab_publisher` WHERE `lab_publisher`.`id` = 1 LIMIT 21 FOR UPDATE; args=(1,)
注意:一定要让 select_for_update
在同一个事务中
事务
使用数据库的原子性操作,如果数据库使用了事务操作,当出现上面的操作异常时,待数据库正常运行后,数据库系统会把先前执行了一半的操作退回到这个操作之前的状态,这个通常称为数据库的回滚,也即数据库的原子性操作.
from django.db import transaction
try:
with transaction.atomic():
models.Publisher.objects.create(name="python001")
models.Book.objects.create(title="python002")
except Exception as e:
return HttpResponse("出现错误....")
return HttpResponse("ok")
执行原生SQL
Django 提供两种方法使用原始SQL进行查询:一种是使用 raw()
方法,进行原始SQL查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的SQL语句。
使用 raw() 方法
raw()管理器方法用于原始的SQL查询,并返回模型的实例,这个方法执行原始的SQL查询,并返回一个 django.db.models.query.RawQuerySet
实例。 这个 RawQuerySet
实例可以像一般的 QuerySet
那样,通过迭代来提供对象实例:
ret = models.Book.objects.raw('select * from lab_book')
for b in ret:
print(b) # Book object
注意: raw()
语法查询必须包含主键。
raw()
查询可以查询其他表的数据。
ret = models.Book.objects.raw('SELECT * FROM `lab_author`')
for b in ret:
print(b.address) # 虽然b是Book对象, 但能正确输出作者的地址 'author address'
# Book 表中没有 address 字段,Author 表有,
防止SQL注入:
ret = models.Book.objects.raw('SELECT * FROM `lab_book` WHERE price > %s AND name = %s', params=[1, '名称2(第一版)'])
for b in ret:
print(b)
直接执行自定义SQL
有时候raw()方法并不十分好用,很多情况下我们不需要将查询结果映射成模型,或者我们需要执行DELETE、 INSERT以及UPDATE操作。在这些情况下,我们可以直接访问数据库,完全避开模型层。
可以直接从django提供的接口中获取数据库连接,然后像使用pymysql模块一样操作数据库。
from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
ret = cursor.fetchone()
Django终端打印SQL语句
settings.py
文件中配置:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
非web项目中使用django的orm功能:
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")
django.setup()
from app01 import models
books = models.Book.objects.all()
print(books)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- PostgreSQL 查询成本模型
- Flask框架从入门到精通之模型查询(十三)
- 057.Python前端Django模型ORM多表查询
- Laravel Database——Eloquent Model 关联模型加载与查询
- imi v1.0.9,新增支持树形模型、分页查询
- Mybatis关联查询(嵌套查询)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Filter Bubble
Eli Pariser / Penguin Press / 2011-5-12 / GBP 16.45
In December 2009, Google began customizing its search results for each user. Instead of giving you the most broadly popular result, Google now tries to predict what you are most likely to click on. Ac......一起来看看 《The Filter Bubble》 这本书的介绍吧!