Вы можете использовать следующий запрос:
books = Book.objects.values('author__name')\
.filter(category=selected_category)\
.annotate( min_pages=Min('pages'))\
.order_by('min_pages')
Вот как это было проверено:
tests.py
class SampleTestCase(TestCase):
def setUp(self) -> None:
a = Author.objects.create(name='a')
b = Author.objects.create(name='b')
c = Author.objects.create(name='c') # Without a book in c1
c1 = Category.objects.create(name='1')
c2 = Category.objects.create(name='2')
Book.objects.create(pages=20, author=a, category=c1)
Book.objects.create(pages=10, author=a, category=c1)
Book.objects.create(pages=15, author=a, category=c1)
Book.objects.create(pages=10, author=a, category=c1)
Book.objects.create(pages=10, author=b, category=c1)
Book.objects.create(pages=5, author=b, category=c1)
Book.objects.create(pages=7, author=b, category=c1)
Book.objects.create(pages=1, author=a, category=c2)
Book.objects.create(pages=1, author=b, category=c2)
Book.objects.create(pages=1, author=c, category=c2)
def test_queryset(self) -> None:
selected_category = Category.objects.get(pk=1)
books = Book.objects.values('author__name')\
.filter(category=selected_category)\
.annotate( min_pages=Min('pages'))\
.order_by('min_pages')
for book in books:
print(book)
# {'author__name': 'b', 'min_pages': 5}
# {'author__name': 'a', 'min_pages': 10}
Обновление:
Если вам нужно получить Book
объектов - не совсем уверен, но я не думаю, что это можно сделать в 1 запрос. Вот как вы можете сделать это в 2:
selected_category = Category.objects.get(pk=1)
ids = Book.objects.values('author__pk') \
.filter(category=selected_category) \
.annotate(min_pages=Min('pages')) \
.annotate(id=Min('id'))\
.values('id')\
.order_by('min_pages')
books = Book.objects.filter(pk__in=ids)
for book in books:
print(book)
# Book object (1)
# Book object (5)