Day 09 基于ORM记录查询

本文详细介绍了Django ORM中的聚合查询和分组查询,包括平均值、总数、最小值、最大值等聚合函数的使用,以及annotate()、values()和filter()的组合应用。同时讲解了F和Q查询对象的用法,以及原生SQL语句的执行。最后探讨了事务的ACID特性及其在Django中的应用。
摘要由CSDN通过智能技术生成

Day 09 基于ORM记录查询

写在前面的话

  • 模板语言:每个语言的web框架都会有模板语言,django—》dtl
  • 模板语言的渲染,是再后端完成的
  • 用php写前端(html,css,js)(不对的)
  • 前后端分离:前后端交互,统一全用json格式
  • 前端只专注于写前端(vue,react:前端工程化),后端只专注于写后端(提供接口,交互json格式数据)

一、聚合查询

1.1 聚合函数的导入

from django.db.models import Avg,Sum, Min, Max, Sum, Count

1.2 聚合函数的使用

# 1 计算所有图书的平均价格
# aggregate结束,已经不是queryset对象了
book = Book.objects.all().aggregate(Avg('price'))
print(book, type(book))  # 得到是 字段名__聚合函数小写:内容的 字典
# 起别名
book = Book.objects.all().aggregate(avg=Avg('price'))
print(book)
---------------------------------------------------------
{'price__avg': 46.8796} <class 'dict'>
{'avg': 46.8796}
# 2 计算总图书数
book_count_dic = Book.objects.all().aggregate(count=Count('id'))
print(book_count_dic)
----------------------------------------------------------
{'count': 50}
# 3 计算最低价格的图书
book_price_min = Book.objects.all().aggregate(min=Min('price'))
print(book_price_min)
----------------------------------------------------------
{'min': Decimal('1.30')}
 # 4 计算所有书的价格
book_price_sum = Book.objects.all().aggregate(sum=Sum('price'))
print(book_price_sum)
-----------------------------------------------------------
{'sum': Decimal('2343.98')}

二、分组查询

重点:annotate() 内写聚合函数

  • values在表示group by的字段
  • values在表示取某几个字段
  • filter在表示where
  • filter在表示having
    # 1、查询出版社id大于15的出版社id,以及出书平均价格
    # select publish_id,avg(price) from app01_book where publish_id>1 group by publish_id;
    price_avg = Book.objects.values('publish__id').filter(publish__id__gt=15).annotate(avg=Avg('price')).values(
        'publish__name', 'price', 'name', 'avg')
    li = []
    for i in price_avg:
        if i['name'] not in li:
            li.append(i['name'])
        # print(i['publish__name'], i['price'], i['avg'])
    print(len(li))
    --------------------------
    16

与数据库查看的数据相同

image-20201015170017393

    # 2
    # 统计每一个出版社的最便宜的书
    author_min_price = Book.objects.values('publish__id').annotate(min=Min('price')).values('publish__name', 'min')
    for i in author_min_price:
        print(i['publish__name'], i['min'])
    
    # 3
    # 统计每一本以py开头的书籍的作者个数:
     startswith_hu = Book.objects.values('publish__id').filter(name__startswith='湖').annotate(count=Count('publish__id')).values('publish__name', 'count')
     for i in startswith_hu:
         print(i['publish__name'], i['count'])
    
    # 4
    # 作者数量大于2的图书名字和价格
   author_gtt = Publish.objects.values('book__id').annotate(count=Count('book__id')).filter(count__gte=2).values('book__name','book__price', 'count')
   for i in author_gtt:
        print(i['book__name'], i['book__price'], i['count'])

三、F和Q查询

F查询:

F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

from django.db.models import F, Q

    # 修改id为25 书籍的价格 + 100
    book35 = Book.objects.filter(id=25).update(price=F('price')+100)
    
    # 查询id数大于价格的书籍
    books = Book.objects.filter(id__gt=F('price')).values( 'name','id','price')
    for i in books:
        print(i)

注意:F和Q只适用于 Quire_SET对象,也就是说get,first,last 是不适用的

Q查询:制造 与或非的条件

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象

与(|)
    # 查询 作者id为8 并且 出版社id为3 的书籍名称和出版社名字
    res = Book.objects.filter(Q(author__id=8) & Q(publish__id=3)).values('name', 'publish__name')
    print(res)
-------------------------------
<QuerySet [{'name': '西藏自治区的老奶奶', 'publish__name': '尼日利亚出版社'}]>
或(&)
    # 查询作者id 为4 或者8的 作者,书籍的名称,和出版社名字
    res = Book.objects.filter(Q(author__id=4) | Q(author__id=8)).values('author__name', 'name', 'publish__name')
    for i in res:
        print(i)
---------------------------------
{'author__name': '王婷', 'name': '甘肃省不相信眼泪', 'publish__name': '尼泊尔出版社'}
{'author__name': '王婷', 'name': '甘肃省不相信眼泪', 'publish__name': '沙特阿拉伯出版社'}
{'author__name': '马晶', 'name': '西藏自治区的老奶奶', 'publish__name': '尼日利亚出版社'}
{'author__name': '马晶', 'name': '西藏自治区的老奶奶', 'publish__name': '多米尼加共和国出版社'}
非(~)
    res = Publish.objects.filter(~Q(book__name='湖南省不相信眼泪') & Q(book__publish__id=2)).values('book__name', 'id','book__id')
    for i in res:
        print(i)

四、原生SQL语句

方案一:用的比较少

    from django.db import connection
    
    cursor = connection.cursor()
    
    cursor.execute("""SELECT * from app01_book where id = %s""", [1])
    
    # row = cursor.fetchone()
    row = cursor.fetchall()
    print(row)

本质与 pymysql 执行方法没啥不同

  • 先创建连接
  • 创造游标
  • 游标接口执行SQL语句
  • 返回结构 fetchall 或者 fethone

方案二:用的多

# 查询id大于 45 的所有书籍信息
books = Book.objects.raw('select * from app01_book where id >45')
for i in books:
    print(i.id, i.name, i.price)
    
    # 跨表查询
    res = Book.objects.raw(
        'select app01_book.id, app01_book.name as name2,app01_author.name from app01_book inner join app01_author on app01_book.author_id=app01_author.id')
    for i in res:
        print(i.name2, i.id, i.name)
    

五、defer和only

    # defer和only(查询优化相关)
    # only保持是book对象,但是只能使用only指定的字段
    # books = models.Book.objects.all().only('name')
    # print(books[0].name)
    # print(books[0].price)  # 能出来,但是会再执行一句SQL语句

    # books = models.Book.objects.all().only('name')
    #
    # print(books[0].__dict__)
    books = models.Book.objects.all().defer('name','price')
    print(books[0].__dict__)

六、事务(请求,装饰器,局部)

事务的特性ACID

  1. 原⼦性: 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么完全不起作⽤;
  2. ⼀致性: 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;
  3. 隔离性: 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;
  4. 持久性: ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何 影响。

事务的三个粒度

1、局部使用
    from django.db import transaction
    with transaction.atomic(): # 都在事物中,要么都成功,要么都失败
        author_detail=models.AuthorDetail.objects.create(addr='xxx',phone='123',sex=1)
        # raise Exception('抛了异常')
        author=models.Author.objects.create(name='llqz',age=19,author_detail=author_detail)
2、视图函数装饰器,这一个视图函数都在一个事物中
@transaction.atomic
    def index(request):
        return HttpResponse('ok')
3、整个http请求,在事物中,在setting.py中配置
DATABASES = {
        'default': {
            ...
            'PORT': 3306,
            'ATOMIC_REQUEST': True,
       
        }
    }

    'ATOMIC_REQUEST': True,
设置为True统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值