You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django QuerySet:如何基于价格字段标注并返回对应书籍名称?

Getting the Highest Price Book Name per Store with Django Annotate

Hey there! I get that you want to attach the name of the highest-priced book (or books, if there's a tie) to each Store object using Django's annotate, so you can pass the QuerySet straight to your template. Here's how to do it:

Single Book Name (Ignoring Ties)

If you don't need to handle multiple books with the same max price, this approach will grab one of them (the first one in the query results):

from django.db.models import Max, Subquery, OuterRef

# First, create a subquery to get the maximum price for each store
max_price_subquery = Book.objects.filter(
    store=OuterRef('pk')  # Reference the current Store's ID
).values('store').annotate(max_price=Max('price')).values('max_price')

# Then, get the name of a book that matches that max price for the store
top_book_name_subquery = Book.objects.filter(
    store=OuterRef('pk'),
    price=Subquery(max_price_subquery[:1])  # Use the max price from the first subquery
).values('name')[:1]

# Annotate each Store with both the max price and the top book name
stores = Store.objects.annotate(
    max_price=Max('books__price'),
    top_book_name=Subquery(top_book_name_subquery)
)

In your template, you can loop through the stores like this:

{% for store in stores %}
    <div class="store">
        <h3>{{ store.name }}</h3>
        <p>Most Expensive Book: {{ store.top_book_name }} (${{ store.max_price }})</p>
    </div>
{% endfor %}

Handling Multiple Books with the Same Max Price

If you need to show all books that share the highest price (and you're using PostgreSQL, which supports array aggregates), use ArrayAgg to collect all their names:

from django.db.models import Max, Subquery, OuterRef
from django.contrib.postgres.aggregates import ArrayAgg

# Reuse the max price subquery from above
max_price_subquery = Book.objects.filter(
    store=OuterRef('pk')
).values('store').annotate(max_price=Max('price')).values('max_price')

# Collect all book names with the max price using ArrayAgg
top_book_names_subquery = Book.objects.filter(
    store=OuterRef('pk'),
    price=Subquery(max_price_subquery[:1])
).values('store').annotate(names=ArrayAgg('name')).values('names')

# Annotate the Store queryset with the array of book names
stores = Store.objects.annotate(
    max_price=Max('books__price'),
    top_book_names=Subquery(top_book_names_subquery)
)

Then in your template, loop through the array of names:

{% for store in stores %}
    <div class="store">
        <h3>{{ store.name }}</h3>
        <p>Most Expensive Books (${{ store.max_price }}):</p>
        <ul>
            {% for book_name in store.top_book_names %}
                <li>{{ book_name }}</li>
            {% endfor %}
        </ul>
    </div>
{% endfor %}

How This Works

  • OuterRef lets us reference the ID of the current Store object we're annotating, so each store gets its own max price calculation.
  • Subquery runs the inner query once per Store, ensuring we get the correct max price and corresponding books for each.
  • Annotating these values directly onto the Store QuerySet means you can pass it straight to your template without extra processing.

内容的提问来源于stack exchange,提问作者Johnny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:18:17