Выберите книгу с наименьшим количеством страниц для каждого автора в категории - PullRequest
0 голосов
/ 11 мая 2019

Это мои модели:

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

class Category(models.Model):
    name = models.CharField()

class Book(models.Model):
    pages = IntegerField()
    author = ForeignKey(Author)
    category = ForeignKey(Category)

Как выбрать книгу для автора с наименьшим количеством страниц в определенной категории? А потом упорядочить по количеству страниц

Если есть две книги с одинаковым количеством страниц, выберите любую из них. Если у автора нет книг в категории, этого автора можно игнорировать.

Спасибо

Ответы [ 2 ]

0 голосов
/ 11 мая 2019

Вы должны использовать предложение annotate () в django, чтобы определить наименьшее количество страниц. И тогда вы можете добавить order_by () в QuerySet. Проверить: https://docs.djangoproject.com/en/2.2/topics/db/aggregation/

попробуйте это:

x = Book.objects.all().values('author','category').annotate(pages = Sum('pages')).order_by('pages')
0 голосов
/ 11 мая 2019

Вы можете использовать следующий запрос:

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)
...