Policz ilość rekordów według daty w Django

Mam model podobny do następującego:

class Review(models.Model):
    venue = models.ForeignKey(Venue, db_index=True)
    review = models.TextField()  
    datetime_created = models.DateTimeField(default=datetime.now)

Chciałbym przeszukać bazę danych, aby uzyskać całkowitą liczbę recenzji dla miejsca pogrupowanego według dnia. Zapytanie MySQL będzie:

SELECT DATE(datetime_created), count(id) 
FROM REVIEW 
WHERE venue_id = 2
GROUP BY DATE(datetime_created);

Jaki jest najlepszy sposób na osiągnięcie tego w Django? I could just use

Review.objects.filter(venue__pk=2)

I analizować wyniki w widoku, ale to nie wydaje mi się właściwe.

Author: Serjik, 2010-02-17

5 answers

To powinno działać (używając tej samej funkcji MySQL, której użyłeś):

Review.objects.filter(venue__pk=2)
    .extra({'date_created' : "date(datetime_created)"})
    .values('date_created')
    .annotate(created_count=Count('id'))
 81
Author: ara818,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-13 21:46:14

Tylko dla kompletności, ponieważ extra() ma na celu deprecjację, można użyć takiego podejścia:

from django.db.models.expressions import DateTime

Review.objects.all().\
    annotate(month=DateTime("timestamp", "month", pytz.timezone("Etc/UTC"))).\
    values("month").\
    annotate(created_count=Count('id')).\
    order_by("-month")

Zadziałało u mnie w django 1.8, zarówno w bazach SQLite jak i MySql.

 13
Author: avikam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-24 19:25:57

Jeśli przechowywałeś pole daty, Możesz użyć tego:

from django.db.models import Count

Review.objects.filter(venue__pk = 2)
    .values('date').annotate(event_count = Count('id'))

Ponieważ przechowujesz datetime, jest to trochę bardziej skomplikowane, ale powinno to stanowić dobry punkt wyjścia. Sprawdź dokumenty agregacji tutaj .

 11
Author: Zach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-13 21:47:08

Teraz, gdy Extra() jest deprecjonowana, bardziej odpowiednia odpowiedź użyłaby Trunc , np. ta akceptowana odpowiedź

Teraz odpowiedź na pytanie OP będzie następująca

from django.db.models.functions import TruncDay

Review.objects.all()
    .annotate(date=TruncDay('datetime_created')
    .values("date")
    .annotate(created_count=Count('id'))
    .order_by("-date")
 5
Author: Anthony Manning-Franklin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:46

Można również zdefiniować funkcję niestandardową:

from django.db.models.expressions import Func

# create custom sql function
class ExtractDateFunction(Func):
    function = "DATE" # thats the name of function, the way it mapped to sql

# pass this function to annotate
Review.objects.filter(venue__pk=2)
      .annotate(date_created=ExtractDateFunction("datetime_created"))
      .values('date_created')
      .annotate(created_count=Count('id'))

Po prostu upewnij się, że twój silnik DB obsługuje funkcję daty

 4
Author: MadisonTrash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-11 05:56:25