Python 用一个值标注每个结果,该值指示字段的最小值还是最大值

Python 用一个值标注每个结果,该值指示字段的最小值还是最大值,python,django,database,query-optimization,Python,Django,Database,Query Optimization,我有两个模型,作者和书籍: class Author(models.Model): name = models.CharField(max_length=256) class Book(models.Model): name = models.CharField(max_length=256) price = models.IntegerField() publication_date = models.DateField() author = mode

我有两个模型,
作者
书籍

class Author(models.Model):
    name = models.CharField(max_length=256)

class Book(models.Model):
    name = models.CharField(max_length=256)
    price = models.IntegerField()
    publication_date = models.DateField()
    author = models.ForeignKey(Author, related_name="books")
现在,当我得到一组作者和他们的书时,我想用两个值对每本书进行注释,指示它是同一作者筛选出的书中最便宜的还是最贵的

我使用
Exists
和注释得到了正确的结果

filtered_books = Book.objects.filter(publication_date__year=2010)

lower_price = filtered_books.only('id').filter(price__lt=OuterRef('price'), author=OuterRef('author'))
higher_price = filtered_books.only('id').filter(price__gt=OuterRef('price'), author=OuterRef('author'))

filtered_books = filtered_books.annotate(
    lowest_price=~Exists(lower_price),
    highest_price=~Exists(higher_price),
)

authors = Author.objects.annotate.prefetch_related(Prefetch('books', queryset=filtered_books))
它可以工作,但会导致执行三个非常相似的子查询(
lower_price
higher_price
和预取),而且速度不是很快。我如何优化它

现在,当我得到一组作者和他们的书时,我想要注释 每本书有两个值,表示它是最便宜的还是最便宜的 从同一作者的筛选出的书籍中提取

它可以工作,但会产生三种结果(较低的价格、较高的价格和 预取)执行非常相似的子查询,速度并没有那么快。 我如何优化它

  • 你无法逃避这3个问题,它们总是会被呈现出来 以这样或那样的形式

  • 拥有3个类似的查询并不意味着它们的速度比单个查询慢3倍,这需要更多的调查才能找到瓶颈所在,可能是缺少索引或smt

  • 指出一本书是最便宜的还是最贵的意味着您需要将书的价格与一些最低/最高价格进行比较。一旦有了这个最小/最大价格,比较就很容易了。由于您希望将本书与作者在queryset中的其他书进行比较,因此在Authors queryset中进行比较更有意义。例如:

    filtered_books = Book.objects.filter(publication_date__year=2010)
    
    min_price_subquery = (filtered_books
        .filter(author=OuterRef('pk'))
        .values('author')
        .annotate(min_price=Min('price'))
        .only('min_price')
    )
    
    max_price_subquery = (filtered_books
        .filter(author=OuterRef('pk'))
        .values('author')
        .annotate(max_price=Max('price'))
        .only('max_price')
    )
    
    authors = Author.objects.annotate(
        min_book_price=Subquery(min_price_subquery, output_field=models.IntegerField()),
        max_book_price=Subquery(max_price_subquery, output_field=models.IntegerField())
    ).prefetch_related(Prefetch('books', queryset=filtered_books))
    
    for author in authors:
        for book in author.books:
            if book.price == author.min_book_price:
                #cheapest price
            if book.price == author.max_book_price:
                #most expensive
    

为什么不按价格订购并获得.first()和.last()商品?我该怎么做?我想不出一种不需要为每个注释运行子查询的方法。是的,这样做会为每个不好的图书列表额外命中db 2次。也许您可以在一些原始sql上使用一个查询来完成这项工作,或者您可以检索列表并在内存上执行注释过程。我猜您不希望列表按默认价格排序,对吧?我希望避免使用原始SQL,因为我需要它来处理多个数据库后端。我甚至不确定它在原始sql中会是什么样子。在内存中做注释也不会起作用,因为我将来可能也会对注释应用一些过滤器。你知道Q对象吗?它用于复杂的查询,这些查询可以产生更高效的sql输出。我也在为您的场景考虑一个Q对象查询,但您可能还想查看它。