" name="sm-site-verification"/>
侧边栏壁纸
博主头像
PySuper博主等级

千里之行,始于足下

  • 累计撰写 203 篇文章
  • 累计创建 14 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录
Web

Django Model 的多种查询

PySuper
2020-09-09 / 0 评论 / 0 点赞 / 16 阅读 / 15181 字
温馨提示:
所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

查看orm内部sql语句的方法

  1. 看是否是queryset 对象,是的话,可直接.query查看SQL语句;
  2. 在django配置文件中,配置相关参数,orm查询时自动打印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',
        },
    }
}

查询方法

  • all():查询所有结果
  • filter(**kwargs):它包含了与所给筛选条件相匹配的对象
  • get(**kwargs):返回数据对象,结果只有一个,没匹配到报错
  • exclude(**kwargs):它包含了与所给筛选条件不匹配的对象
# 只要pk不是1的数据全部查询出来
print(models.Book.objects.exclude(pk=1))
  • order_by(*field):对查询结果排序;默认是升序,加-就是降序
print(models.Book.objects.order_by('price'))   # 默认是升序
print(models.Book.objects.order_by('-price'))  # 加负号就是降序
  • reverse():对查询结果反向排序
# 注:前面要先有排序才能反向
print(models.Book.objects.order_by('price').reverse())
  • count():返回数据库中匹配查询(QuerySet)
# 对查询出来的结果进行一个计数
print(models.Book.objects.count())
  • first():返回第一条记录
  • last():返回最后一条记录
  • exists():存在返回True,否则返回False
print(models.Book.objects.filter(pk=1000).exists())
  • values(*field):返回一个ValueQuerySet对象,运行后得到的并不是一系列
# 得到的结果是列表套字典
print(models.Book.objects.values('title','price'))
  • values_list(*field):它与values()类似
# 得到的结果是列表套元组
print(models.Book.objects.values_list('title','price'))
  • distinct():从返回结果中剔除重复纪录
# 注:去重的前提是 一定要有完全重复的数据 才能去重
print(models.Book.objects.values('title','price','create_time').distinct())

双下滑查询

  • __gt:大于
# 查询价格大于200的书籍
res = models.Book.objects.filter(price__gt=200)
  • __lt:小于
# 查询价格小于200的书籍
res = models.Book.objects.filter(price__lt=200)
  • __gte:大于等于
# 查询价格大于等于200.22的书籍
res = models.Book.objects.filter(price__gte=200.22)
  • __lte: 小于等于
# 查询价格小于等于200.22的书籍
res = models.Book.objects.filter(price__lte=200.22)
  • __in::或者
# 查询价格要么是200,要么是300,要么是666.66
res = models.Book.objects.filter(price__in=[200,300,666.66])
  • __range:区间 左右都包括
# 查询价格在200到800之间的
res = models.Book.objects.filter(price__range=(200,800))
  • __contains:模糊匹配
# 查询书籍名字中包含p的
res = models.Book.objects.filter(title__contains='p')  # 仅仅只能拿小写p
res = models.Book.objects.filter(title__icontains='p')  # 忽略大小写
  • __startswith:以…开头
# 查询书籍是以三开头的
res = models.Book.objects.filter(title__startswith='三')
  • ``__endswith`:以…结尾
# 查询书籍是以三结尾的
res = models.Book.objects.filter(title__endswith='三')
  • __year:查询年相关的
# 查询出版日期是2017的年(**)
res = models.Book.objects.filter(create_time__year='2017')

多表查询

一对多

# publish_id传数字:
models.Book.objects.create(title='三国演义', price=189.99, publish_id=1)

# publish直接传出版社对象:
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦', price=999.99, publish=publish_obj)

# 传数字的:
models.Book.objects.filter(pk=1).update(publish_id=3)

# 传对象的:
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj) 

# 默认都是级联更新 级联删除
models.Publish.objects.filter(pk=2).delete()

多对多

增(add)

既可以传数字也可以传对象并且支持一次性传多个,逗号隔开即可

# 要给主键为1的书籍添加两个作者

# 1. 传数字:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1)
book_obj.authors.add(2, 3)

# 2. 传对象:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1, author_obj2)

改(set)

  1. set中要传可迭代对象,可迭代对象中 可以是多个数字组合也可以是多个对象组合;
  2. 数字与对象不要混着用!!!
# 将主键为1的书籍对象,作者修改为2、3

# 传数字:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2, ])
book_obj.authors.set([2, 3])

# 传对象:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj, ])
book_obj.authors.set([author_obj, author_obj1, author_obj2])

删(remove | clear)

  1. 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
  2. remove支持传数字,对象,并且可以传多个;
  3. clear不需要传任何参数
# 传数字:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(3)
book_obj.authors.remove(1, 2)

# 传对象:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj1, author_obj2)

# 什么都不传: 将xx跟xx的关系全部清空
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()  # 清空当前书籍与作者的所有关系

跨表查询

  • 正向与反向概念
    • 正向查询按外键字段查,反向查询按表名小写
    • 一对一
      • 正向:author—关联字段在author表里—>authordetail 按字段
      • 反向:authordetail—关联字段在author表里—>author 按表名小写
    • 一对多
      • 正向:book—关联字段在book表里—>publish 按字段
      • 反向:publish—关联字段在book表里—>book 按表名小写_set.all() 因为一个出版社对应着多个图书
    • 多对多
      • 正向:book—关联字段在book表里—>author 按字段
      • 反向:author—关联字段在book表里—>book 按表名小写_set.all() 因为一个作者对应着多个图书

子查询

将一张表的查询结果当做另外一个查询语句的条件

当反向查询的结果有多个时,要在后面加上_set;

# 1. 查询书籍id是1的出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish.name)

# 2. 查询书籍id是2的作者姓名
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())

res = book_obj.authors.all()

for r in res:
    print(r.name)

# 3. 查询作者是jason的家庭住址
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.addr)

# 4. 查询出版社是东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())

# 5. 查询作者是jason的写过的所有的书籍
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set)  # app01.Book.None
print(author_obj.book_set.all())

# 6. 查询电话号码是130的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first()
print(author_detail_obj.author.name)
print(author_detail_obj.author.age)

# 7. 查询书籍id为1的作者的电话号码
book_obj = models.Book.objects.filter(pk=1).first()
author_list = book_obj.authors.all()
for author_obj in author_list:
    print(author_obj.author_detail.phone)

连表操作(基于__)

  1. 只要表里面有外键字段, 你就可以无限制跨多张表
  2. 如:外键字段1外键字段2...外键字段__普通字段n
# 1. 查询jason作者的手机号
# 正向
res = models.Author.objects.filter(name='jason').values('author_detailphone', 'author_detailaddr')
print(res)

# 反向
res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res1)


# 2. 查询jason这个作者的年龄和手机号
# 正向
res = models.Author.objects.filter(name='jason').values('age', 'author_detail__phone')
print(res)

# 反向
res1 = models.AuthorDetail.objects.filter(authorname='jason').values('phone', 'authorage')
print(res1)


# 3. 查询手机号是130的作者年龄
# 正向
res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
print(res)

# 反向
res1 = models.Author.objects.filter(author_detail__phone=130).values('age')
print(res1)

# 4. 查询书籍id是1的作者的电话号码
res = models.Book.objects.filter(pk=1).values('authorsauthor_detailphone')
print(res)

# 5. 查询出版社为北方出版社的所有图书的名字和价格
res = models.Publish.objects.filter(name='北方出版社').values('booktitle', 'bookprice')
print(res)

# 6. 查询北方出版社出版的价格大于19的书
res = models.Book.objects.filter(pricegt=19, publishname='北方出版社').values('title', 'publish__name')
print(res)

聚合查询(aggregate)

最大,最小,个数,平均,总和

aggregate(后面可跟多个函数)

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

res = models.Book.objects.aggregate(Sum('price'))
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5 = models.Book.objects.aggregate(Max('price'), Min('price'), Count('pk'), Avg('price'), Sum('price'))

分组查询(annotate)

models.那个表名就以那个分组

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

# 1. 统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors')).values('author_num', 'title')
print(res)

# 2. 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(mmp=Min('book__price')).values('name', 'mmp')
print(res)

# 3. 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
print(res)

# 4. 查询各个作者出的书的总价格
res = models.Author.objects.annotate(sp=Sum('book__price')).values('name', 'sp')
print(res)

F查询

本质就是从数据库中获取某个字段的值

from django.db.models import F

# 1. 查询卖出数量
res = models.Book.objects.filter(kucun__gt=F('maichu'))
print(res)

# 2. 将书籍库存数全部增加1000
models.Book.objects.update(kucun=F('kucun') + 1000)

# 3. 把所有书名后面加上'新款'
from django.db.models import Value
from django.db.models.functions import Concat

ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
# models.Book.objects.update(title=F('title') + '新款')  # 不能这么写

Q查询

默认and,可人为改为 or , not

from django.db.models import Q

# 查询书籍名称是三国演义或者价格是444.44

# and:
res = models.Book.objects.filter(title='三国演义', price=444.44)  # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'), Q(price=444))  # 如果用逗号 那么还是and关系

# or:
res2 = models.Book.objects.filter(Q(title='三国演义') | Q(price=444))

# not:
res3 = models.Book.objects.filter(~Q(title='三国演义') | Q(price=444))


# Q高级用法(了解)

q = Q()
q.connector = 'or'  # 修改查询条件的关系   默认是and
q.children.append(('title__contains', '三国演义'))  # 往列表中添加筛选条件
q.children.append(('price__gt', 444))  # 往列表中添加筛选条件

res = models.Book.objects.filter(q)  # filter支持你直接传q对象  但是默认还是and关系
print(res)

查询优化

orm内所有的语句操作都是惰性查询

只会在你真正需要数据的时候才会走数据库,这样有利于减轻数据库压力

  • only与defer
    • only
      • 会将only()内的字段一次性的查出来返封装进一个对象中;
      • 你查only内的数据,不管取值多少次,也只会走一次数据库 ;
      • 你查的不是only内的数据,不会报错也会返回数据,但是会频繁的走数据库
    • defer
      • 会将不是defer()内的所有字段信息全查出来封装进对象中;
      • 你查询()内的字段会频繁的走数据库,对手库python的压力比较大,反之只走一次库

  • select_related与prefetch_related
    • select_related
      • 会将括号内外键字段所关联的那张表直接全部拿过来(可以一次性拿多张表)跟当前表拼接操作;
      • 从而降低你跨表查询 数据库的压力;
      • select_related括号只能放外键字段(一对一、一对多)
    • prefetch_related
      • 不主动连表操作(但是内部给你的感觉像是连表操作了);
      • 会将book表中的publish_id全部拿来;
      • 再去publish表中将id对应的所有的数据取出。
    • 区别:
      • select_related需要连表,但只走一次数据库;连表会花时间
      • prefech_related不用连表,括号内有几个外键字段 就会走几次数据库查询操作
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区