django开发知识点4-内置接口调用

内置接口调用

1、进阶接口

除了常用接口外,还有其他用来提高性能的接口,在下面介绍。 在优化Django项目时,尤其要考虑这几种接口的用法。

defer

把不需要展示的字段做延迟加载。比如说,需要获取到文章中除正文外的其他字段,就可以通过posts = Post.objects.all() .defer('content'),这样拿到的记录中就不会包含content部分。但是当我们需要用到这个字段时,在使用时会去加载。代码:

products=Product.objects.all().defer('content')

for product in products:  #此时会执行数据库查询

print (product.content)  #此时会执行数据查询,获取到content

当不想加载某个过大的字段时(如text类型的字段),会使用defer,但是上面的演示代产生N+1的查询问题,在实际使用时千万要注意!

注意:上面的代码是个不太典型的 N+1查询的问题, 一般情况下 由外键查询产生的N+1问题比较多,即一条查询请求返回N条数据,当我们操作数据时,又会产生额外的请求。这就是N+1问题,所有的ORM框架都存在这样的问题。

only

同defer接口刚好相反, 如果只想获取到所有的title记录,就可以使用only,只获取title的内容,其他值在获取时会产生额外的查询。

select_related

这就是用来解决外键产生的N+1问题的方案。我们先来看看什么情况下会产生这个问题:

products = Product.objects.all ()

for product inproducts:  #产生数据库查询

   print (product.owner)  #产生额外的数据库查询

代码同上面类似,只是这里用的是owenr(是关联表)。它的解决方法就是用select_ related接口:

ProductS =Product.objects.all() .select_related('category')

for Product in Products: # 产生数据库查询,category数据也会一次性查询出来

   print (Product.category)

当然,这个接口只能用来解决一对多的关联关系。对于多对多的关系,还得使用下面的接口。

prefetch_related

针对多对多关系的数据,可以通过这个接口来避免N+1查询。比如,post和tag的关系可以通过这种方式来避免:

Products = Product.objects.all().prefetch_related('tag')

for Product in Products:#产生两条查询语句,分别查询post和tag

   print(Product.tag.al1())

2.常用的字段查询

contains

包含,用来进行相似查询。

icontains

同contains,只是忽略大小写。

exact

精确匹配。

iexact

同exact,忽略大小写。

in

指定某个集合,比如Product.objects.filter(id__in=[1, 2, 3])相当于SELECT FROM table WHERE IN (1, 2, 3);。

gt

大于某个值。比如:Product.objects.filter(id__gt=1)

注意:是__gt

gte

大于等于某个值。

lt

小于某个值。

lte

小于等于某个值。

startswith

以某个字符串开头,与contains类似,只是会产生LIKE '<关键词>%'这样的SQL。

istartswith

同startswith, 忽略大小写。

endswith

以某个字符串结尾。

iendswith

同endswith,忽略大小写。

range

范围查询,多用于时间范围,如Product.objects.filter(created_time__range= ('2018-05-01','2018-06-01'))会产生这样的查询: SELECT .. . WHERE created_ time BETWEEN '2018-05-01' AND '2018-06-01' ;。

这里你需要理解的是,Django之所以提供这么多的字段查询,其原因是通过ORM来操作数据库无法做到像SQL的条件查询那么灵活。

因此,这些查询条件都是用来匹配对应SQL语句的,这意味着,如果你知道某个查询在SQL中如何实现,可以对应来看Django提供的接口。

3 、高阶查询

除了上面基础的查询语句外,Django还提供了其他封装,来满足更复杂的查询,比如 SELECT ... WHERE id = 1 OR id = 2 这样的查询,用上面的基础查询就无法满足。

F

F表达式常用来执行数据库层面的计算,从而避免出现竞争状态。比如需要处理每篇文章的访问量,假设存在post.pv这样的字段,当有用户访问时,我们对其加1:

product =Product.objects.get(id=1)

product .pv = product .pv+1

product .save()

这在多线程的情况下会出现问题,其执行逻辑是先获取到当前的pv值,然后将其加1后赋值给post .pv.最后保存。

如果多个线程同时执行了post = Post.objects.get(id=1),那么每个线程里的post .pv值都是一样的, 执行完加1和保存之后,相当于只执行了一个加1,而不是多个。

这时通过F表达式就可以方便地解决这个问题:

from ajango.ab. models import F

product = product .objects.get(id=1)

product .pv = F('pv') + 1

product .save():

这种方式最终会产生类似这样的SQL语句: UPDATE table SET pv = pv +1 WHERE ID = 1。 它在数据库层面执行原子性操作。

Q

Q表达式就是用来解决前面提到的那个OR查询的,可以这么用:

from django.db.mode1s import Q

product .objects.filter(Q(id=1) | Q(id=2))

或者进行AND查询:

product .objects.filter(Q(id=1) & Q(id=2))

Count

用来做聚合查询,比如想要得到某个分类下有多少篇文章,简单的做法就是:

category = Category.objects.get(id=1)

posts_count = category.post_set.count()

但是如果想要把这个结果放到category上呢?通过category.post_count可以访问到:

from django.db.models import Count

categories = Category.objects.annotate(posts_count=Count('post'))

print(categories[0].posts_count)

这相当于给category动态增加了属性post_count,而这个属性的值来源于Count('post'),最后可以用int取整。

Sum

同Count类似,只是它是用来做合计的。比如想要统计所有数据字段的总和,可以这么做:

from django.db.models import Sum

Post.objects.all().aggregate(a=Sum('字段'))

#输出类似结果:{'a':487}为字典

python中对字典中键值对的获取:

for i in book:

   print(i)#键的获取

   print(book[i])#值的获取

上面演示了QuerySet的annotate和aggregate的用法,其中前者用来給QuerySet结果増加属性,后者只用来直接计算结果,这些聚合表达式都可以与它们结合使用。

除了Count和Sum外,还有Avg、Min和Max等表达式,均用来满足我们对SQL査洵的需求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值