276
Django 1.10 and above
Django documentation lists extra
as deprecated soon. (Thanks for pointing that out @seddonym, @Lucas03). I opened a ticket and this is the solution that jarshwah provided.
from django.db.models.functions import TruncMonth
from django.db.models import Count
Sales.objects
.annotate(month=TruncMonth('created')) # Truncate to month and add to select list
.values('month') # Group By month
.annotate(c=Count('id')) # Select the count of the grouping
.values('month', 'c') # (might be redundant, haven't tested) select month and count
Older versions
from django.db import connection
from django.db.models import Sum, Count
truncate_date = connection.ops.date_trunc_sql('month', 'created')
qs = Order.objects.extra({'month':truncate_date})
report = qs.values('month').annotate(Sum('total'), Count('pk')).order_by('month')
Edits
- Added count
- Added information for django >= 1.10
57
Just a small addition to @tback answer:
It didnβt work for me with Django 1.10.6 and postgres. I added order_by() at the end to fix it.
from django.db.models.functions import TruncMonth
Sales.objects
.annotate(month=TruncMonth('timestamp')) # Truncate to month and add to select list
.values('month') # Group By month
.annotate(c=Count('id')) # Select the count of the grouping
.order_by()
- [Django]-Sending an SMS to a Cellphone using Django
- [Django]-What's the recommended approach to resetting migration history using Django South?
- [Django]-How to override and extend basic Django admin templates?
14
Another approach is to use ExtractMonth
. I ran into trouble using TruncMonth due to only one datetime year value being returned. For example, only the months in 2009 were being returned. ExtractMonth fixed this problem perfectly and can be used like below:
from django.db.models.functions import ExtractMonth
Sales.objects
.annotate(month=ExtractMonth('timestamp'))
.values('month')
.annotate(count=Count('id'))
.values('month', 'count')
- [Django]-Are sessions needed for python-social-auth
- [Django]-Can you give a Django app a verbose name for use throughout the admin?
- [Django]-When to create a new app (with startapp) in Django?
4
metrics = {
'sales_sum': Sum('total'),
}
queryset = Order.objects.values('created__month')
.annotate(**metrics)
.order_by('created__month')
The queryset
is a list of Order, one line per month, combining the sum of sales: sales_sum
@Django 2.1.7
- [Django]-How to pass multiple values for a single URL parameter?
- [Django]-How to obtain a QuerySet of all rows, with specific fields for each one of them?
- [Django]-Add inline model to django admin site
1
Hereβs my dirty method. It is dirty.
import datetime, decimal
from django.db.models import Count, Sum
from account.models import Order
d = []
# arbitrary starting dates
year = 2011
month = 12
cyear = datetime.date.today().year
cmonth = datetime.date.today().month
while year <= cyear:
while (year < cyear and month <= 12) or (year == cyear and month <= cmonth):
sales = Order.objects.filter(created__year=year, created__month=month).aggregate(Count('total'), Sum('total'))
d.append({
'year': year,
'month': month,
'sales': sales['total__count'] or 0,
'value': decimal.Decimal(sales['total__sum'] or 0),
})
month += 1
month = 1
year += 1
There may well be a better way of looping years/months but thatβs not really what I care about
- [Django]-How do I raise a Response Forbidden in django
- [Django]-Django β Login with Email
- [Django]-Using Python's os.path, how do I go up one directory?
1
By month:
Order.objects.filter().extra({'month':"Extract(month from created)"}).values_list('month').annotate(Count('id'))
By Year:
Order.objects.filter().extra({'year':"Extract(year from created)"}).values_list('year').annotate(Count('id'))
By day:
Order.objects.filter().extra({'day':"Extract(day from created)"}).values_list('day').annotate(Count('id'))
Donβt forget to import Count
from django.db.models import Count
For django < 1.10
- [Django]-Django Reverse with arguments '()' and keyword arguments '{}' not found
- [Django]-Python Socket.IO client for sending broadcast messages to TornadIO2 server
- [Django]-Dynamically adding a form to a Django formset
1
Here is how you can group data by arbitrary periods of time:
from django.db.models import F, Sum
from django.db.models.functions import Extract, Cast
period_length = 60*15 # 15 minutes
# Annotate each order with a "period"
qs = Order.objects.annotate(
timestamp=Cast(Extract('date', 'epoch'), models.IntegerField()),
period=(F('timestamp') / period_length) * period_length,
)
# Group orders by period & calculate sum of totals for each period
qs.values('period').annotate(total=Sum(field))
- [Django]-Django β Website Home Page
- [Django]-How to customize activate_url on django-allauth?
- [Django]-Django β How to use decorator in class-based view methods?
0
i have orders table in my database . i am going to count orders per month in the last 3 months
from itertools import groupby
from dateutil.relativedelta import relativedelta
date_range = datetime.now()-relativedelta(months=3)
aggs =Orders.objects.filter(created_at=date_range)\
.extra({'date_created':"date(created_at)"}).values('date_created')
for key , group in groupby(aggs):
print(key,len(list(group)))
created_at is datetime field. by extra function what done is taking date from datetime values. when using datetime we may not get the count correct because objects are created at different time in a day.
The for loop will print date and number of count
- [Django]-OperationalError: database is locked
- [Django]-How to check if ManyToMany field is not empty?
- [Django]-Add additional options to Django form select widget