Group by trong Django
Mình sẽ sử dụng User model đã hỗ trợ sẵn của Django nằm trong django.contrib.auth app.
Count
SQL:
SELECTCOUNT(*)FROM auth_user
Django ORM:
User.objects.count()
Aggregate Function
Để sử dụng được các aggregate functions, chúng ta cần import các function đó nằm trong mục from django.db.models import Count.
Trong ví dụ này mình sẽ sử dụng Count function, ngoài ra còn cách aggregate function khác như: Max, Min, Sum, Avg.
SQL:
SELECTCOUNT(id)AS id__count FROM auth_user
Django ORM:
from django.db.models import Count
User.objects.aggregate(Count('id'))
=> {"id__count": 318}
Bạn cũng có thể thay đổi tên của giá trị trả về. Ví dụ mình sẽ đổi từ id__count sang total.
SQL:
SELECTCOUNT(id)AS total FROM auth_user
Django ORM:
from django.db.models import Count
User.objects.aggregate(total=Count('id'))
=> {"total": 318}
Group by với aggregate function
SQL:
SELECT
is_active,COUNT(id)AS total
FROM
auth_user
GROUPBY
is_active
Django ORM:
User.objects
.values('is_active')
.annotate(total=Count('id'))
- values(‘is_active’): trường muốn group by.
- annotate(total=Count(‘id’)): group by theo aggregate function nào.
=> Thứ tự gọi là values trước annotate.
Filter a QuerySet với Group by
Ví dụ này sẽ đếm số lượng những user active hoặc inactive có role là staff.
SQL:
SELECT
is_active,COUNT(id)AS total
FROM
auth_user
WHERE
is_staff =TrueGROUPBY
is_active
Django ORM:
User.objects
.values('is_active')
.filter(is_staff=True)
.annotate(total=Count('id'))
Sort a QuerySet với Group by
SQL:
SELECT
is_active,COUNT(id)AS total
FROM
auth_user
GROUPBY
is_active
ORDERBY
is_active,
total
Django ORM:
User.objects
.values('is_active')
.annotate(total=Count('id'))
.order_by('is_active', 'total')
Kết hợp nhiều Aggregate Function với Group By
Ví dụ này sẽ đếm số lượng những user active hoặc inactive và với từng loại active hoặc inactive sẽ lấy ra last_joined.
SQL:
SELECT
is_active,COUNT(id)AS total,MAX(date_joined)AS last_joined
FROM
auth_user
GROUPBY
is_active
Django ORM:
from django.db.models import Max
User.objects
.values('is_active')
.annotate(
total=Count('id'),
last_joined=Max('date_joined'),
)
Group By nhiều trường
Kết quả của ví dụ này sẽ bao gồm is_active, is_staff và số lượng users với mỗi group.
SQL:
SELECT
is_active,
is_staff,COUNT(id)AS total
FROM
auth_user
GROUPBY
is_active,
is_staff
Django ORM:
User.objects
.values('is_active', 'is_staff')
.annotate(total=Count('id'))
Group By với Expression
**SQL:**
SELECT
EXTRACT('year'FROM date_joined),COUNT(id)AS total
FROM
auth_user
GROUPBY
EXTRACT('year'FROM date_joined)
Django ORM:
User.objects
.values('date_joined__year')
.annotate(total=Count('id'))
Sử dụng với Conditional Aggregation
**SQL:**
SELECT
EXTRACT('year'FROM date_joined),COUNT(id) FILTER (WHERE is_staff =True)AS staff_users,COUNT(id) FILTER (WHERE is_staff =False)AS non_staff_users
FROM
auth_user
GROUPBY
EXTRACT('year'FROM date_joined)
Django ORM:
from django.db.models import F, Q
User.objects
.values('date_joined__year')
.annotate(
staff_users=(
Count('id', filter=Q(is_staff=True))
),
non_staff_users=(
Count('id', filter=Q(is_staff=False))
),
)
Sử dụng với Having
**SQL:**
SELECT
is_active,COUNT(id)AS total
FROM
auth_user
GROUPBY
is_active
HAVINGCOUNT(id)>100
Django ORM:
User.objects
.annotate(year_joined=F('date_joined__year'))
.values('is_active')
.annotate(total=Count('id'))
.filter(total__gt=100)
Distinct với Group By
**SQL:**
SELECT
is_active,COUNT(id)AS total,COUNT(DISTINCT last_name)AS unique_names
FROM
auth_user
GROUPBY
is_active
Django ORM:
User.objects
.values('is_active')
.annotate(
total=Count('id'),
unique_names=Count('last_name', distinct=True),
)
Join với Group By
**SQL:**
SELECT
p.type,COUNT(u.id)AS total
FROM
auth_user u
JOIN user_profile p ON u.id = p.user_id
GROUPBY
p.type
Django ORM:
User.objects
.values('user_profile__type')
.annotate(total=Count('id'))
Group By với Many to Many Relationship
**SQL:**
SELECT
u.id,COUNT(ug.group_id)AS memberships
FROM
auth_user
LEFTOUTERJOIN auth_user_groups ug ON(
u.id = ug.user_id
)GROUPBY
u.id
Django ORM:
User.objects
.annotate(memberships=Count('groups'))
.values('id', 'memberships')
Hi vọng bài viết giúp ích được các bạn trong việc làm quen với Django ORM.
Mình có tham khảo và dịch lại bài viết tại blog:
https://hakibenita.com/django-group-by-sql
Nguồn: viblo.asia