Джанго и условные агрегаты - PullRequest
4 голосов
/ 20 мая 2010

У меня есть две модели, авторы и статьи:

class Author(models.Model):
    name = models.CharField('name', max_length=100)

class Article(models.Model)
    title = models.CharField('title', max_length=100)
    pubdate = models.DateTimeField('publication date')
    authors = models.ManyToManyField(Author)

Теперь я хочу выбрать всех авторов и аннотировать их с соответствующим количеством статей. Это кусок пирога с агрегатами Django . Проблема в том, что следует учитывать только те статьи, которые уже опубликованы. Согласно билету 11305 в трекере Django, это пока невозможно. Я попытался использовать аннотацию CountIf, упомянутую в этом билете, но она не заключает в кавычки строку даты и времени и не делает все соединения, которые ей понадобятся.

Итак, что является лучшим решением, кроме написания собственного SQL?

Ответы [ 3 ]

5 голосов
/ 18 августа 2013

Вы можете использовать приложение django-aggregate-if , вдохновленное тикетом 11305 .Или вы можете просто использовать метод extra для набора запросов (предположим, что ваше приложение называется "article"):

Author.objects.all().extra(
    select={'article_count': 'SELECT COUNT(*) FROM "articles_article" '
                             'INNER JOIN "articles_article_authors" '
                             'ON "articles_article"."id" = '
                             '   "articles_article_authors"."article_id" '
                             'WHERE "articles_article_authors"."author_id" = '
                             '      "articles_author"."id" '
                             'AND "articles_article"."pubdate" IS NOT NULL'})
4 голосов
/ 19 марта 2017

Django 1.8+ решение

Начиная с Django 1.8, условные выражения доступны для построения наборов запросов.

Для получения более подробной информации обратитесь к документации, но быстрое решение для вашего вопроса будет выглядеть примерно так:

today = datetime.date.today()
authors = Author.objects.all().annotate(article_count=Sum(
    Case(When(articles__pubdate__lt=today, then=1),
         output_field=IntegerField())
))

Я не проверял это, хотя, но это должно работать.

1 голос
/ 24 мая 2010

Я решил свою проблему, создав представление SQL с необходимым оператором GROUP BY и модель для указанного представления с managed = False и OneToOneField для таблицы Author. Это не самое эффективное и элегантное решение, но оно работает нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...