发布于2019-09-11 14:20 阅读(634) 评论(0) 点赞(26) 收藏(4)
1. 外键的跨表查询
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="书名")
publisher_date = models.DateField(auto_now_add=True)
price = models.DecimalField(max_digits=5, decimal_places=2)
publisher = models.ForeignKey(Publisher, related_name='book', related_query_name='books')
class Publisher(models.Model):
name = models.CharField(max_length=32, verbose_name="出版社名")
city = models.CharField(max_length=32, verbose_name="城市名")
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", related_name="authors")
book_obj = models.Book.objects.get(id=1)
book.publisher.name
models.Book.objects.filter(id=1).values("publisher__name")
publisher_obj = models.Publisher.objects.get(id=1)
# 没有配置related_name
publisher_obj.book_set.all()
# 配置related_name='book'
publisher_obj.book.all()
publisher_obj = models.Publisher.objects.filter(id=1).values('book__name')
# 如果配置了related_query_name='books'
publisher_obj = models.Publisher.objects.filter(id=1).values('books__name')
# 第一步:给多表中添加对象时,如果添加对象不存在,则会报错
publishers = Publisher.objects.get(id=1)
# 创建book对象
book = Book(title='十万个为什么', price=45)
# 将book对象添加给出版社,此处会出错,因为book对象没有被保存进数据库
publishers.book.add(book)
# 保存对象时,字段指定不全,且未指定字段值不能为空时,会报错
publishers = Publisher.objects.get(id=1)
# 创建book对象
book = Book(title='十万个为什么', price=45)
book.save() # 此处会报错,因为我们未指定他的出版社,且出版社字段时必须填写字段
# 将book对象添加给出版社,此处会出错,因为book对象没有被保存进数据库
publishers.book.add(book)
# 解决方法
publishers = Publisher.objects.get(id=1)
# 创建book对象
book = Book(title='十万个为什么', price=45)
# 将book对象添加给出版社,系统会自动将publisher绑定给该书籍对象,且将该对象进行保存
publishers.book.add(book, bulk=False)
2. 分组和聚合
from django.db.models import Count
# 查询每本书的作者数量 related_name 值
# 将查询统计出来的结果保存为author_num字段,相当于对象多了一个属性
book_list = models.Book.objects.all().annotate(author_num=Count('authors'))
# 输出书名和作者数量
book_list = models.Book.objects.all().annotate(author_num=Count('authors')).values("title", "author_num")
<QuerySet [{"title": "天方夜谭", "author_num": 3},{},{}]>
from django.db.models import Avg, Sum, Max, Min, Count
# 求所有书本的平均价格,得到一个字典{"price__avg": 200}
models.Book.bjects.all().aggregate(Avg('price'))
# 指定返回字典的聚合名:{"book_price_avg": 200}
models.Book.bjects.all().aggregate(book_price_avg=Avg('price'))
# 统计有多少个不同的价格
models.Book.bjects.all().aggregate(book_price_count=Count('price', distinct=True))
3. F查询
from django.db.models import F
models.Book.objects.filter(comment_num__gt=F('fav_num'))
models.Book.objects.filter(commnet_num__lt=F('fav_num')*2)
models.Book.objects.all().update(price=F("price")+10)
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"),Value(")")))
4. Q查询
models.Book.objects.filter(Q(price__lt=30) | Q(publish_date__year=2019))
5. .values
from django.db import models
from django.db.models import Count
# 查找结果只需要返回书的id、名称、作者名
models.Book.objects.all().values('id', 'title', 'author__name')
# {"id": xxx, "name": xxx, "author__name": xxx}
# 作者名变量,重新指定为auth_name,切忌指定的变量名不能是存在于Book表中的字段名
models.Book.objects.all().values('id', 'title', auth_name='author__name')
# {"id": xxx, "name": xxx, "auth_name": xxx}
# 在.values中使用聚合函数(统计每个出版社出版的书籍数量)
models.Publisher.objects.all().values('id', 'name', 'city', book_count=Count('book__id'))
# {"id": xxx, "name": xxx, "city": xxx, "book_count": xxx}
6. .values_list
from django.db import models
# 查找结果只需要返回书的id、名称、作者名
models.Book.objects.all().values_list('id', 'title', 'author__name')
# (xxx, xxx, xxx)
# 当返回结果只有一个字段时,我们可以给定参数flat=True,此时直接返回数据真实值,而不是元祖形式,便于我们处理
models.Book.objects.all().values_list('id')
# xxx
7. .select_related:产生一条查询语句
select_related
将book信息提取出来,以后再次使用book.publisher的时候就不需要再次去访问数据库了,可以减少数据库的查询次数。select_related
只能用在多对一
、一对一
关系表中,即从多表查询一表时使用。from django.db import models
book = models.Book.objects.get(id=1)
book.publisher.name # 此处重新执行了一次数据库查询(查询出版社信息)
# 可以指定多个关系外键
publisher = models.Book.objects.select_related('publisher').get(id=1)
book.publisher.name # 不需要再次执行数据库查询(第一次查询书籍信息时已经查询出来出版社相关相关信息了)
8. .prefetch_related:产生两条查询语句
prefetch_related
方法和select_related
方法相似,就是在访问多个表中的数据时,减少查询次数。这个方法是为了解决多对多
和一对多
的关系查询问题,即从一表查询多表时使用。from django.db import models
publisher= models.Publisher.objects.get(id=1)
publisher.book.title # 此处重新执行了一次数据库查询(查询书籍信息)
# 可以指定多个关系外键
publisher = models.Publisher.objects.prefetch_related('book').get(id=1)
publisher.book.title # 不需要再次执行数据库查询(第一次查询出版社信息时已经查询出来书籍相关相关信息了)
# 正常查询
publishers = Publisher.objects.all() # 获取所有出版社信息
for publisher in publishers:
books = publisher.book.all() # 循环获取每个出版社下的所有书籍信息(每次循环都去book表中查询)
for book in books: # 循环每个出版社下的每本书籍的名称
print(book.title)
# 优化查询 book_set
publishers = Publisher.objects.prefetch_related('book') # 获取所有出版社信息
for publisher in publishers:
# books = publisher.book_set.all()
books = publisher.book.all() # 循环获取每个出版社下的所有书籍信息(不再去book表中查询)
for book in books: # 循环每个出版社下的每本书籍的名称
print(book.title)
# 优化查询 book_set
publishers = Publisher.objects.prefetch_related('book') # 获取所有出版社信息
for publisher in publishers:
# books = publisher.book_set.all()
books = publisher.book.filter(price__gte=10) # 此时会再去book表中进行查询,导致 prefetch_related 方法失去意义
for book in books:
print(book.title)
from django.db.models import Prefetch
prefetch = Prefetch('book', queryset=Book.objects.filter(price__gte=10))
publishers = Publisher.objects.prefetch_related(prefetch)
for publisher in publishers:
# books = publisher.book_set.all()
books = publisher.book.all() # 此处不要进行过滤等操作,如果必要,则去prefetch中操作
for book in books:
print(book.title)
9. .defer
defer
来进行过滤掉
那些不需要的字段,这个字段跟values
有点类似,只不过defer返回的不是字典,而是模型对象。book_obj = Book.objects.defer('price') # id字段操作不了
for book in book_obj:
print(type(book))
print(book.title)
# 如果此时再次查询price字段值,依然是可以查询出来的,因为它又重新去数据库查询了一次
print(book.price) # 这样做就失去了意义,所以如果需要你就将其,如果过滤掉了,你就不要再去查询该字段
10. .only
过滤出
需要的字段book_obj = Book.objects.only('title') # id字段操作不了
for book in book_obj:
print(type(book))
print(book.title)
# 如果此时再次查询price字段值,依然是可以查询出来的,因为它又重新去数据库查询了一次
print(book.price) # 这样做就失去了意义
11. .get_or_create
obj, created = Book.objects.get_or_create(
title='天方夜谭',
price=90,
defaults={'publisher_date': 'xxx', 'publisher': 'xxx'},
)
defaults
进行创建对象11. .bulk_create
from book.models import Publisher
publisher_list = []
for i in range(100):
publisher_list.append({
"name": '沙河出版社' + str(i),
"city": '北京' + str(i)
})
Publisher.objects.bulk_create([Publisher(**publisher) for publisher in publisher_list])
12. 事务
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
import datetime
from app01 import models
try:
from django.db import transaction
with transaction.atomic(): # with语句内部代码块出错,将会导致with代码块内部的所有语句都回滚到最初状态,例如出版社创建成功,但书籍对象创建时指定了一个不存在的出版社id,所以会创建失败,此时,将会执行数据库回滚操做,之前创建成功的出版社对象也将消失。
new_publisher = models.Publisher.objects.create(name="火星出版社")
models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
except Exception as e:
print(str(e))
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
from app01 import models
books = models.Book.objects.all()
print(books)
作者:老板跑路了
链接:https://www.pythonheidong.com/blog/article/107261/9aac5d6d68ea298f2365/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!