084:QuerySet API详解prefetch_related方法

QuerySet API详解prefetch_related方法:

prefetch_related :这个方法和 select_related 非常的类似,就是在访问多个表中的数据的时候,减少查询的次数。这个方法是为了解决 多对一 和 多对多 的关系的查询问题。比如要获
取标题中带有 hello 字符串的文章以及他的所有标签,示例代码如下:

from django.db import connection
articles = Article.objects.prefetch_related("tag_set").filter(title__contains=‘hello‘)
print(articles.query) # 通过这条命令查看在底层的SQL语句
for article in articles:
  print("title:",article.title)
  print(article.tag_set.all())

# 通过以下代码可以看出以上代码执行的sql语句
print(connection.queries)

但是如果在使用 article.tag_set 的时候,如果又创建了一个新的 QuerySet 那么会把之前的 SQL 优化给破坏掉。比如以下代码:

tags = Tag.obejcts.prefetch_related("articles")
for tag in tags:
  articles = tag.articles.filter(title__contains=‘hello‘) #因为filter方法会重新生成一个QuerySet,因此会破坏掉之前的sql优化
# 通过以下代码,我们可以看到在使用了filter的,他的sql查询会更多,而没有使用filter的,只有两次sql查询
print(connection.queries)

那如果确实是想要在查询的时候指定过滤条件该如何做呢,这时候我们可以使用 django.db.models.Prefetch 来实现, Prefetch 这个可以提前定义好 queryset 。示例代码如下:

tags = Tag.objects.prefetch_related(Prefetch("articles",queryset=Article.objects.f
ilter(title__contains=‘hello‘))).all()
for tag in tags:
  articles = tag.articles.all()
  for article in articles:
    print(article)
print(connection.queries)

因为使用了 Prefetch ,即使在查询文章的时候使用了 filter ,也只会发生两次查询操作。

实例代码和截图:

    # books = Book.objects.all()
    # books = Book.objects.prefetch_related("bookorder_set")
    # for book in books:
    #     print("#"*30)
    #     print(book.name)
    #     orders = book.bookorder_set.all()
    #     for order in orders:
    #         print(order.id)

    # books = Book.objects.prefetch_related("author")
    # for book in books:
    #     print(book.author.name)

    # books = Book.objects.prefetch_related("bookorder_set")
    # for book in books:
    #     print(book.name)
    #     orders = book.bookorder_set.filter(price__gte=90)
    #     for order in orders:
    #         print(order.id)

    prefetch = Prefetch("bookorder_set", queryset=BookOrder.objects.filter(price__gte=90))
    books = Book.objects.prefetch_related(prefetch)
    for book in books:
        print("#"*30)
        print(book.name)
        orders = book.bookorder_set.all()
        for order in orders:
            print(order.id)

    print(connection.queries)

原文地址:https://www.cnblogs.com/zheng-weimin/p/10281861.html

时间: 2024-10-11 16:24:41

084:QuerySet API详解prefetch_related方法的相关文章

079:【Django数据库】QuerySet API详解-filter、exclude、annotate

QuerySet API详解-filter.exclude.annotate: 在使用 QuerySet 进行查找操作的时候,可以提供多种操作.比如过滤完后还要根据某个字段进行排序,那么这一系列的操作我们可以通过一个非常流畅的 链式调用 的方式进行.比如要从文章表中获取标题为 123 ,并且提取后要将结果根据发布的时间进行排序,那么可以使用以下方式来完成: articles = Article.objects.filter(title='123').order_by('create_time')

081:QuerySet API详解-values和values_list

QuerySet API详解-values和values_list: values:用来指定在提取数据出来,需要提取哪些字段.默认情况下会把表中所有的字段全部都提取出来,可以使用values来进行指定,并且使用了values方法后,提取出的QuerySet中的数据类型不是模型,而是在values方法中指定的字段和值形成的字典: # books = Book.objects.values("id", "name", "price") # books

091:QuerySet API详解-update和delete

QuerySet API详解-update和delete: update :执行更新操作,在 SQL 底层走的也是 update 命令.比如要将所有 图书的价格提高五元.示例代码如下: Book.objects.update(price=F("price") + 5) # 对比一下上下两种方式 # books = Book.objects.all() # for item in books: # item.price += 5 # item.save() 注意这个方法走的是更新的逻辑.

092:QuerySet API详解-切片操作

QuerySet API详解-切片操作: 切片操作:有时候我们查找数据,有可能只需要其中的一部分.那么这时候可以使用切片操作来帮我们完成. QuerySet 使用切片操作就跟列表使用切片操作是一样的.示例代码如下: # books = Book.objects.all()[0:] #这两句是一样的: all和get_queryset方法是一样的 >>> 看一下all方法的源代码 books = Book.objects.get_queryset()[1:2] for item in bo

093:QuerySet API详解-QuerySet转换为SQL的条件

QuerySet API详解-QuerySet转换为SQL的条件: 生成一个 QuerySet 对象并不会马上转换为 SQL 语句去执行.比如我们获取 Book 表下所有的图书: books = Book.objects.all() print(connection.queries) 我们可以看到在打印 connection.quries 的时候打印的是一个空的列表.说明上面的 QuerySet 并没有真正的执行. 在以下情况下 QuerySet 会被转换为 SQL 语句执行:1.迭代:在遍历

080:【Django数据库】QuerySet API详解-order_by:

QuerySet API详解-order_by: order_by:指定将查询的结果根据某个字段进行排序.如果要倒叙排序,那么可以在这个字段的前面加一个负号.示例代码如下: # 时间从前往回排: # orders = BookOrder.objects.order_by("create_time") # 时间从后往前排(与上面相反): orders = BookOrder.objects.order_by("-create_time") # 时间从后往前排,如果时间

085:QuerySet API详解-defer和only

QuerySet API详解-defer和only: defer :在一些表中,可能存在很多的字段,但是一些字段的数据量可能是比较庞大的,而此时你又不需要,比如我们在获取文章列表的时候,文章的内容我们是不需要的,因此这时候我们就可以使用 defer 来过滤掉一些字段.这个字段跟 values 有点类似,只不过 defer 返回的不是字典,而是模型.示例代码如下: articles = list(Article.objects.defer("title")) for sql in con

089:QuerySet API详解-count和exists

QuerySet API详解-count和exists: count :获取提取的数据的个数.如果想要知道总共有多少条数据,那么建议使用 count ,而不是使用 len(articles) 这种.因为 count 在底层是使用 select count(*) 来实现的,这种方式比使用 len 函数更加的高效: # book_sum = Book.objects.all() # print(len(book_sum)) result = Book.objects.count() print(re

Android基础入门教程——8.3.16 Canvas API详解(Part 1)

Android基础入门教程--8.3.16 Canvas API详解(Part 1) 标签(空格分隔): Android基础入门教程 本节引言: 前面我们花了13小节详细地讲解了Android中Paint类大部分常用的API,本节开始我们来讲解 Canvas(画板)的一些常用API,我们在Android基础入门教程--8.3.1 三个绘图工具类详解 中已经列出了我们可供调用的一些方法,我们分下类: drawXxx方法族:以一定的坐标值在当前画图区域画图,另外图层会叠加, 即后面绘画的图层会覆盖前