从多个模型中获取信息时优化 django 查询

Posted

技术标签:

【中文标题】从多个模型中获取信息时优化 django 查询【英文标题】:Optimise django query when fetching information from multiple models 【发布时间】:2020-10-17 21:54:19 【问题描述】:

我是 Django 新手并使用 Django 3.0.6。

通过以下代码,我已经能够达到预期的效果,并将详细的图书信息显示到模板上。然而,平均而言,ORM 会进行 8 到 9 次数据库查询以获取有关该书的详细信息。我正在寻求专家帮助来优化我的数据库查询,以便我可以用更少的查询获取与图书相关的信息。

我尝试使用 select_related()prefetch_related() 但没有任何运气,也许我做得不正确。是否有使用Q objectunion() 的范围,只是我的想法?如何以最少的数据库查询获得相同的结果?

如果可能的话,请帮我提供详细的代码。

models.py

class Publisher(models.Model):
    publisher_name = models.CharField(max_length=50)

class Author(models.Model):
    author_name = models.CharField(max_length=50)

class Booktype(models.Model):
    book_type = models.CharField(max_length=20) # Hard Cover, Soft Cover, Kindle Edition, Digital PDF etc.

class Book(models.Model):
    book_title = models.TextField()
    slug = models.SlugField(max_length=50, unique=False)
    published_date = models.DateField(auto_now=False, auto_now_add=False)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    book_type = models.ManyToManyField(Booktype, through='BookPrice', through_fields=('book', 'book_type'))

# I created this separate model due to havy content and to keep Book model light
class BookDetail(models.Model): 
    a = models.TextField(null=True, blank=True)
    b = models.TextField(null=True, blank=True)
    c = models.TextField(null=True, blank=True)
    book = models.OneToOneField(Book, on_delete=models.CASCADE)

class BookPrice(models.Model):
    book_type = models.ForeignKey(Booktype, on_delete=models.CASCADE)
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    price = models.DecimalField(max_digits=7, decimal_places=2)

view.py

def get_book_details(request, book_id, slug):
    book = Book.objects.get(id=book_id, slug=slug)
    context = 'book': book
    return render(request, 'products/book_detail.html', context)

book_detail.html 模板

# 1st databse query
 book.book_title 
 book.id 
 book.published_date 

# 2nd databse query
 book.publisher.publisher_name 

# 3rd databse query
 book.author.author_name 

# 4th databse query
 book.bookdetail.a 
 book.bookdetail.b 
 book.bookdetail.c 

# 5th to 9th databse query depending upon avaialble Book Types
% for x in book.bookprice_set.all %
     x.book_type   x.price|floatformat 
% endfor %      

【问题讨论】:

【参考方案1】:

您可以使用.select_related(…) [Django-doc] 获取publisherauthorbookdetail。我们可以使用prefetch_related

def get_book_details(request, book_id, slug):
    book = Book.objects.select_related(
        'publisher', 'author', 'bookdetail'
    ).prefetch_related(
        'bookprice_set', 'bookprice_set__book_type'
    ).get(id=book_id, slug=slug)
    context = 'book': book
    return render(request, 'products/book_detail.html', context)

【讨论】:

您好,谢谢您的回答。我在我的代码中尝试过它,你知道它就像一个魅力,靶心!!!使用您的代码或建议,我只需 3 次数据库查询就能够获得相同的结果。非常感谢你,我真的很感谢你的帮助。你让我开心!!!

以上是关于从多个模型中获取信息时优化 django 查询的主要内容,如果未能解决你的问题,请参考以下文章

Django - 显示结果信息,同时使用具有多个外键关系的模型优化数据库查询

在 Graphene Django 中查询多个模型

Django - 如何从多个模型中获取所需的数据

Django中模型

Django - 如何从模型实例中获取管理员 URL

如何从 Django 中的复选框中获取多个值