Подтвердить что ты не робот

Подсчитать количество записей по дате в Django

У меня есть модель, подобная следующей:

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

Я хотел бы запросить базу данных, чтобы получить общее количество отзывов для места, сгруппированного по дням. Запрос MySQL:

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

Каков наилучший способ выполнить это в Django? Я мог бы просто использовать

Review.objects.filter(venue__pk=2)

и проанализировать результаты в представлении, но это не кажется мне правильным.

4b9b3361

Ответ 1

Это должно работать (используя ту же самую специфическую функцию MySQL, которую вы использовали):

Review.objects.filter(venue__pk=2)
    .extra({'date_created' : "date(datetime_created)"})
    .values('date_created')
    .annotate(created_count=Count('id'))

Ответ 2

Просто для полноты, поскольку extra() предназначен для устаревания, можно использовать этот подход:

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

Он работал у меня в django 1.8, как в sqlite, так и в базе данных MySql.

Ответ 3

Если вы сохранили поле даты, вы можете использовать это:

from django.db.models import Count

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

Поскольку вы храните datetime, это немного сложнее, но это должно стать хорошей отправной точкой. Ознакомьтесь с документацией агрегации здесь.

Ответ 4

Также вы можете определить пользовательскую функцию:

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

Просто убедитесь, что ваш механизм DB поддерживает функцию DATE

Ответ 5

Теперь, когда Extra() обесценивается, более подходящий ответ будет использовать Trunc, например этот принятый ответ

Теперь вопрос OP будет отвечать следующим образом

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