2009-12-15 15 views
5

GROUP BY ve HAVING’yi Django’nun QuerySet.annotate ve QuerySet.aggregate’una nasıl çevireceğimi pek bilmiyorum. Bu SQL sorgusunu ORM'ye çevirmeye çalışıyorumDjango'nun ORM'deki bu GROUP BY sorgusunu açıklama notu ve toplu olarak nasıl yaparsınız

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; 

bunu verir:

[(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)] 

Benim Django modelim:

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

Bu proje birkaç farklı şekilde çalışmalıdır. DB sistemleri, bu yüzden mümkün olduğunca saf SQL'den uzak durmaya çalışıyorum.

cevap

14

zaman ... ayrı alanlar olarak ay ve yıl olması gerekebilir tek sorguda bunu yapmak için düşünüyorum

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

O PUB_DATE tarafından olur group by. Ama orada extract fonksiyon maddesinin eşdeğerini yapmak için düşünmem mümkün değil. Modeliniz

olsaydı:

Sonra
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() 

bunu yapabilirsiniz: Bunu yapacaksanız

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

, ben otomatik save() geçersiz kılarak doldurulur pub_year ve pub_month sahip öneriyoruz Makale ve pub_date değerlerini ayıklama yöntemi.


Düzenleme: extra kullanmaktır yapmak

bir yolu; Hiç veritabanı sunucuları değiştirirseniz bu durumda da çalışır ancak ... size

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

veritabanı bağımsızlık vermeyeceğini olacak, ben (denenmemiş) düşünüyorum, extra alanlarının değiştirilmesine gerektirir. Örneğin, SQL Server size belirgin böyle veritabanı altyapısı bağımlı değişiklikler gerektiren olarak etiketlemek, özel bir modeli yöneticisi ile gelip eğer öyleyse kötü olmayabilir year(pub_date) yerine extract(year from pub_date) ...

Bu yapardı. http://docs.djangoproject.com/en/dev/ref/models/querysets/#dates-field-kind-order-asc

+0

Güzel hile, teşekkürler: Sen tarihleri ​​ile bir özü yapabilirsiniz

+0

Gönderdiğiniz "extra" örnek harika çalışıyor. Keşke bu cevabı daha fazla kazanabilseydim! –

2
! Bu sorguya yalnızca tek bir sayfa için ihtiyacım var, bu da iki ekstra alanı haklı çıkarmak için biraz zor. Fakat 'extra' kullanmak şu anki işi yapacak :)