当前位置: 首页 > 编程笔记 >

Django 减少对ManyToManyField的查询数量(n + 1个问题)

顾学真
2023-03-14
本文向大家介绍Django 减少对ManyToManyField的查询数量(n + 1个问题),包括了Django 减少对ManyToManyField的查询数量(n + 1个问题)的使用技巧和注意事项,需要的朋友参考一下

示例

问题

# models.py:
class Library(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Book)

class Book(models.Model):
    title = models.CharField(max_length=100)
# views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.all()

    # Query the database on each iteration (len(author) times)
    # if there is 100 librairies, there will have 100 queries plus the initial query
    for library in libraries:
        books = library.books.all()
        books[0].title
        # ...

    # total : 101 queries

使用prefetch_related上ManyToManyField,如果你知道你需要访问后场是一个ManyToManyField场。

# views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related('books').all()
    
    # Does not query the database again, since `books` is pre-populated
    for library in libraries:
        books = library.books.all()
        books[0].title
        # ...

    # total : 2 queries - 1 for libraries, 1 for books

prefetch_related 也可以用于查找字段:

# models.py:
class User(models.Model):
    name = models.CharField(max_length=100)

class Library(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Book)

class Book(models.Model):
    title = models.CharField(max_length=100)
    readers = models.ManyToManyField(User)
 # views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related('books', 'books__readers').all()
    
    # Does not query the database again, since `books` and `readers` is pre-populated
    for library in libraries:
        for book in library.books.all():
            for user in book.readers.all():
                user.name
                # ...

    # total : 3 queries - 1 for libraries, 1 for books, 1 for readers

但是,一旦执行了查询集,就无法更改获取的数据,而无需再次击中数据库。下面将执行额外的查询,例如:

 # views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related('books').all()
    for library in libraries:
        for book in library.books.filter(title__contains="Django"):
            print(book.name)

可以使用PrefetchDjango 1.7中引入的对象优化以下内容:

from django.db.models import Prefetch
# views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related(
        Prefetch('books', queryset=Book.objects.filter(title__contains="Django")
    ).all()
    for library in libraries:
        for book in library.books.all():
            print(book.name)  # Will print only books containing Django for each library
           

 类似资料:
  • 本文向大家介绍Django 减少对ForeignKey字段的查询数量(n + 1个问题),包括了Django 减少对ForeignKey字段的查询数量(n + 1个问题)的使用技巧和注意事项,需要的朋友参考一下 示例 问题 Django查询集以惰性方式求值。例如:   上面的代码使django在数据库中查询每本书的作者。这样效率低下,最好只包含一个查询。 解 使用select_related上Fo

  • 我已经用reduce内置函数编写了这些代码行,但它显示了给定参数的错误。 45 lst=[1,2,3]中的TypeError回溯(最近一次调用)---- TypeError:d_n()接受1个位置参数,但给出了2个

  • 本文向大家介绍Django ORM多对多查询方法(自定义第三张表&ManyToManyField),包括了Django ORM多对多查询方法(自定义第三张表&ManyToManyField)的使用技巧和注意事项,需要的朋友参考一下 对于多对多表 - 1.自定义第三张表,更加灵活 - 2.ManyToManyField 自动生成第3张表 只能 有3列数据 不能自己添加。 自定义第三张表 ManyTo

  • 减少图层数量     初始化图层,处理图层,打包通过IPC发给渲染引擎,转化成OpenGL几何图形,这些是一个图层的大致资源开销。事实上,一次性能够在屏幕上显示的最大图层数量也是有限的。     确切的限制数量取决于iOS设备,图层类型,图层内容和属性等。但是总得说来可以容纳上百或上千个,下面我们将演示即使图层本身并没有做什么也会遇到的性能问题。 裁切     在对图层做任何优化之前,你需要确定你

  • 问题 你有一个被其他python代码使用的callable对象,可能是一个回调函数或者是一个处理器, 但是它的参数太多了,导致调用时出错。 解决方案 如果需要减少某个函数的参数个数,你可以使用 functools.partial() 。 partial() 函数允许你给一个或多个参数设置固定的值,减少接下来被调用时的参数个数。 为了演示清楚,假设你有下面这样的函数: def spam(a, b,

  • 问题内容: 说我想对中的每个元素求和。 我有理由相信,斧头在某些时候是不确定的。 以下工作正常 我在第一个示例中做错了什么? 问题答案: 第一次迭代后,您将返回一个数字,然后尝试获取该数字的属性以将其添加到下一个对象中,该对象是和数学,其中涉及结果。 尝试返回一个对象,该对象包含一个属性,该属性与参数的x个属性之和: 从注释中添加了说明: 每次迭代的返回值在下一次迭代中用作变量。 迭代1: ,,