[Django ORM] Group By trong Django

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

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

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ