zoukankan      html  css  js  c++  java
  • 84.常用的返回QuerySet对象的方法使用详解:select_related, prefetch_related

    比如,想要获取与Book表通过外键的形式相关联的Author表中的数据,示例代码如下:
    from django.db import connection
    from django.http import HttpResponse
    from .models import Article, Book, BookOrder
    def index4(request):
        # 1. select_related()想要获取与Book表通过外键的形式相关联的Author表中的数据
        # 可以通过select_related()将相关联的表中的数据提取到内存中,减少到数据库中的查询
        books = Book.objects.select_related('author')
        for book in books:
            print("%s, %s" % (book.author.name, book.author.age))
        print(connection.queries) 
        # 最后django底层可以执行一条sql语句就将所有的查询操作完成
       
    

    django底层执行的sql语句为:

    [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'},
    {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'},
    {'sql': 'SELECT book.id, book.name, book.pages, book.price, book.rating, book.author_id, book.publisher_id, book.score, author.id, author.name, author.age, author.email FROM book INNER JOIN author ON (book.author_id = author.id)', 'time': '0.016'}]

    由以上的sql语句,可以看出只进行了一次查询操作,所以这就大大提高了查询的效率了。因此如果在数据量不是太大,并且经常会使用到该表的相关联的表中的数据时,就可以采用select_related()方法首先将数据提取到内存中,以便之后在进行查找的时候可以减少向数据库中发起请求的次数。

    2. 采用传统的方式进行查找,获取Book表通过外键的形式相关联的Author表中的数据,

    示例代码如下:
        books = Book.objects.all()
        # 采用all()方法获取每个book的信息,然后向数据库中提出查询操作每个book进行一次数据库的查询,提取出name,age字段的值
        for book in books:
        	print("%s,%s" % (book.author.name, book.author.age))
        print(connection.queries)
    

    django底层执行的sql语句为:
    [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'},
    {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'},
    {'sql': 'SELECT book.id, book.name, book.pages, book.price, book.rating, book.author_id, book.publisher_id, book.score FROM book', 'time': '0.000'},
    {'sql': 'SELECT author.id, author.name, author.age, author.email FROM author WHERE author.id = 5 LIMIT 21', 'time': '0.000'},
    {'sql': 'SELECT author.id, author.name, author.age, author.email FROM author WHERE author.id = 1 LIMIT 21', 'time': '0.000'},
    {'sql': 'SELECT author.id, author.name, author.age, author.email FROM author WHERE author.id = 4 LIMIT 21', 'time': '0.000'},
    {'sql': 'SELECT author.id, author.name, author.age, author.email FROM author WHERE author.id = 3 LIMIT 21', 'time': '0.000'}]

    由以上sql语句可以看出,采用传统的方式执行的sql语句较多,这会大大的降低查询的效率。所以如果数据量不是太大的情况下可以采用select_related()方法将数据提取到内存中。
    比如,求每本书的订阅量。示例代码如下:
    def index(request):
     # 3. prefetch_related()可以对多对多,多对一的关联模型操作
        # 比如,求每个书的订阅量
        # 返回的books中的是包裹在QuerySet中的book对象
        books = Book.objects.prefetch_related('bookorder_set')
        print(type(books))
        # <class 'django.db.models.query.QuerySet'>
        for book in books:
            print(type(book))
        # <class 'front.models.Book'>, 之后就可以对返回的每一本书上的属性进行操作
        #   以下我们可以提取出每本书上的所有订单信息
        # 注意:如果已经使用prefetch_related()进行了相关的查找,这里就不要使用filter()或者是其他的可以返回QuerySet的任何操作了。
        # book_nums = book.bookorder_set.filter(price__gte=80)
        # 这里可以使用all()方法进行获取。如果对bookorder再次进行了查询就会增加n个查询语句,降低查询的效率
            book_nums = book.bookorder_set.all()
            for book_num in book_nums:
                print("%s, %s, %s" % (book_num.book.name, book_num.price, book_num.id))
        print(connection.queries)
        return HttpResponse("success!")
    

    django底层执行的sql语句为:

    [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'},
    {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'},
    {'sql': 'SELECT book.id, book.name, book.pages, book.price, book.rating, book.author_id, book.publisher_id, book.score FROM book', 'time': '0.000'},
    {'sql': 'SELECT book_order.id, book_order.book_id, book_order.price, book_order.time FROM book_order WHERE book_order.book_id IN (1, 2, 3, 4)', 'time': '0.000'}]

    总结:在多对多,多对一关联对象中执行查询操作,可以使用prefetch_related()进行相关查询,这种方式中可以大大减少执行的sql语句,并且这种方式会产生两条查询语句。同样也可以使用prefetch_related()对一对多或者是一对一的关联对象进行相关查询,同样也会在底层执行两条sql语句,如果使用select_related()进行查询的话只会执行一条查询语句。所以说如果是对一对一或者是一对多关联对象执行操作的话,建议使用select_related(); 如果是多对一或者是多对多关联模型执行操作时,就可以采用prefetch_related()

    4. 采用传统的方式执行与prefetch_related()作用相同的操作,查看django底层执行的sql语句,

    示例代码如下:
    def index(request):
    # 4. 使用传统的方法对多对多或者是多对一的关联模型表进行查询操作
        books = Book.objects.all()
        for book in books:
            print(type(book))
        #     # <class 'front.models.Book'>
            book_nums = book.bookorder_set.all()
            for book_num in book_nums:
                print(type(book_num))
        #         # <class 'front.models.BookOrder'>
                print("%s, %s, %s" % (book_num.book.name, book_num.price, book_num.id))
        print(connection.queries)
        return HttpResponse("success")
    

    django底层执行的sql语句:
    [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'},
    {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'},
    {'sql': 'SELECT book.id, book.name, book.pages, book.price, book.rating, book.author_id, book.publisher_id, book.score FROM book', 'time': '0.000'},
    {'sql': 'SELECT book_order.id, book_order.book_id, book_order.price, book_order.time FROM book_order WHERE book_order.book_id = 1', 'time': '0.000'},
    {'sql': 'SELECT book_order.id, book_order.book_id, book_order.price, book_order.time FROM book_order WHERE book_order.book_id = 2', 'time': '0.000'},
    {'sql': 'SELECT book_order.id, book_order.book_id, book_order.price, book_order.time FROM book_order WHERE book_order.book_id = 3', 'time': '0.000'},
    {'sql': 'SELECT book_order.id, book_order.book_id, book_order.price, book_order.time FROM book_order WHERE book_order.book_id = 4', 'time': '0.016'}]

    由以上所执行的sql语句可以看出,采用传统的方式会使底层执行的sql语句的数量增大

    5. 如果在某些情况下需要对预先查询的结果,再进行一些操作,可以使用Prefetch()函数,

    示例代码如下:
    def index5(request):
        # 5.如果确实要对预先查询的结果,再进行一些操作的话,可以使用Prefetch()函数
        # 可以将要进行的操作赋值给Prefetch函数中的queryset参数
        prefetch = Prefetch('bookorder_set', queryset=BookOrder.objects.filter(price__gte=90))
        books = Book.objects.prefetch_related(prefetch)
        for book in books:
                # <class 'front.models.BookOrder'>
            orders = book.bookorder_set.all()
            for order in orders:
                print("%s, %s, %s" % (order.book.name, order.price, order.id))
        print(connection.queries)
        return HttpResponse("success")
    

    django底层执行的sql语句为:
    水浒传, 95.0, 2
    [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'},
    {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'},
    {'sql': 'SELECT book.id, book.name, book.pages, book.price, book.rating, book.author_id, book.publisher_id, book.score FROM book', 'time': '0.000'},
    {'sql': 'SELECT book_order.id, book_order.book_id, book_order.price, book_order.time FROM book_order WHERE (book_order.price >= 90.0e0 AND book_order.book_id IN (1, 2, 3, 4))', 'time': '0.000'}]

    始于才华,忠于颜值;每件事情在成功之前,看起来都是天方夜谭。一无所有,就是无所不能。
  • 相关阅读:
    小程序页面跳转 之 js页面函数绑定跳转
    win10系统激活提示无法连接到你组织的激活服务器如何解决
    小程序请求后端接口实例
    cors解决跨域问题
    aes加密 工具类
    后端解决跨域的问题
    理解传输层中UDP协议首部校验和以及校验和计算方法的Java实现
    常见面试题之操作系统中的LRU缓存机制实现
    Java算法之根据二叉树不同遍历结果重建二叉树
    基于Java的二叉树层序遍历打印实现
  • 原文地址:https://www.cnblogs.com/guyan-2020/p/12270304.html
Copyright © 2011-2022 走看看