2010-02-17 190 views
39

que tiene un modelo similar al siguiente:Contar el número de registros por fecha en Django

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

me gustaría consultar la base de datos para obtener el número total de comentarios de un lugar agrupados por día. La consulta de MySQL sería:

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

¿Cuál es la mejor manera de lograr esto en Django? Podría simplemente usar

Review.objects.filter(venue__pk=2) 

y analizar los resultados en la vista, pero eso no me parece correcto.

+0

Posible duplicado de [Django: Agrupar por fecha (día, mes, año)] (http://stackoverflow.com/questions/8746014/django-group-by-date-day-month-year) – tback

Respuesta

79

Esto debería funcionar (usando la misma función específica de MySQL que utilizó):

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

Eso es como mi respuesta, pero mejor !! – Zach

+0

Faltaba tristemente el .extra() .. Muy poderoso. ¡Gracias! –

+0

Algo que no puedo obtener ,,, utilizando .extra() ANTES de que los .values ​​() tengan un resultado diferente al usarlo DESPUÉS de la cláusula .values ​​()? !! ¿Alguna explicación maestra? –

11

Si estaba almacenando un campo de fecha, podría utilizar esto:

from django.db.models import Count 

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

Debido a que usted está almacenando fecha y hora, que es un poco más complicado, pero esto debe ofrecer un buen punto de partida. Consulte los documentos de agregación here.

12

simplemente para la corrección, puesto adicional() está dirigido por depreciación, se podría utilizar este enfoque:

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

Me funcionó en django 1.8, tanto en las bases de datos sqlite como en MySql.

+0

Gracias, hombre, este es el negocio. – Dav3xor

+1

también puede utilizar django huso horario utils en lugar de pytz.timezone 'django.utils.timezone.get_default_timezone' –

+0

Esto parece haberse movido en [Extraer] (https://docs.djangoproject.com/en/1.10/ref /models/database-functions/#django.db.models.functions.datetime.Extract) en Django 1.10 –

4

También se puede definir la función personalizada:

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

Sólo asegúrese de que su motor de base de datos compatible con la función FECHA

1

Ahora se amortiza que Extra() una respuesta más apropiada sería utilizar Trunc como this accepted answer

Ahora la pregunta del OP sería respondida de la siguiente manera

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