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

Optimise django query when fetching information from multiple models

我是 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 %}      

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

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