Как выполнить этот запрос GROUP BY в ORM Джанго с аннотацией и агрегированием - PullRequest
5 голосов
/ 15 декабря 2009

Я не очень умел переводить GROUP BY и HAVING на QuerySet.annotate и QuerySet.aggregate Джанго. Я пытаюсь перевести этот SQL-запрос в ORM говорить

SELECT EXTRACT(year FROM pub_date) as year, EXTRACT(month from pub_date) as month, COUNT(*) as article_count FROM articles_article GROUP BY year,month;

который выводит это:

[(2008.0, 10.0, 1L), # year, month, number of articles
(2009.0, 2.0, 1L),
(2009.0, 7.0, 1L),
(2008.0, 5.0, 3L),
(2008.0, 9.0, 1L),
(2008.0, 7.0, 1L),
(2009.0, 5.0, 1L),
(2008.0, 8.0, 1L),
(2009.0, 12.0, 2L),
(2009.0, 3.0, 1L),
(2007.0, 12.0, 1L),
(2008.0, 6.0, 1L),
(2009.0, 4.0, 2L),
(2008.0, 3.0, 1L)]

Моя модель Django:

class Article(models.Model):
    title = models.CharField(max_length=150, verbose_name=_("title"))
    # ... more 
    pub_date = models.DateTimeField(verbose_name=_('publishing date'))

Этот проект должен выполняться на нескольких разных системах БД, поэтому я стараюсь как можно больше держаться подальше от чистого SQL.

Ответы [ 2 ]

14 голосов
/ 15 декабря 2009

Я думаю, что для выполнения одного запроса у вас могут быть месяц и год как отдельные поля ...

Article.objects.values('pub_date').annotate(article_count=Count('title'))

Это будет group by по pub_date. Но я никак не могу придумать, чтобы сделать эквивалент встроенного здесь * функционального предложения extract.

Если бы ваша модель была:

class Article(models.Model):
    title = models.CharField(max_length=150, verbose_name=_("title"))
    # ... more 
    pub_date = models.DateTimeField(verbose_name=_('publishing date'))
    pub_year = models.IntegerField()
    pub_month = models.IntegerField()

Тогда вы могли бы сделать:

Article.objects.values('pub_year', 'pub_month').annotate(article_count=Count('title'))

Если вы собираетесь это сделать, я бы рекомендовал автоматически заполнять pub_year и pub_month путем переопределения метода save() для Article и извлечения значений из pub_date.


Edit:

Один из способов сделать это - использовать extra ; но это не даст вам независимость от базы данных ...

models.Issue.objects.extra(select={'year': "EXTRACT(year FROM pub_date)", 'month': "EXTRACT(month from pub_date)"}).values('year', 'month').annotate(Count('title'))

Хотя это будет работать, я думаю (не проверено), вам потребуется изменить поля extra, если вы когда-либо будете менять серверы баз данных. Например, в SQL Server вы должны сделать year(pub_date) вместо extract(year from pub_date) ...

Это может быть не так уж плохо, если вы придумали собственный менеджер моделей, который вы бы пометили как требующий таких зависимых от ядра базы данных изменений.

2 голосов
/ 16 декабря 2009

Вы можете сделать выписку с датами: http://docs.djangoproject.com/en/dev/ref/models/querysets/#dates-field-kind-order-asc

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