DJANGO
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.

Mối quan hệ Many-to-Many trong Django với Python

Một trong những mối quan hệ phổ biến mà bạn có thể gặp phải là mối quan hệ nhiều-nhiều (many-to-many). Trong bài viêt này, bạn sẽ học cách sử dụng ManyToManyField để mô hình hóa mối quan hệ nhiều-nhiều trong Django một cách hiệu quả. Mình sẽ được hướng dẫn từng bước, từ việc định nghĩa mô hình, tạo bảng liên kết trong cơ sở dữ liệu, cho đến cách truy vấn và quản lý dữ liệu liên quan. Bằng cách áp dụng các kỹ thuật này, bạn sẽ có thể xây dựng các ứng dụng Django mạnh mẽ và linh hoạt hơn.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Mối quan hệ Many-to-Many là gì?

Trong một mối quan hệ nhiều-nhiều, nhiều hàng trong một bảng có liên quan đến nhiều hàng trong một bảng khác.

Ví dụ, một nhân viên có thể tham gia nhiều chương trình đãi ngộ và một chương trình đãi ngộ có thể áp dụng cho nhiều nhân viên.

Do đó, nhiều hàng trong bảng nhân viên có liên quan đến nhiều hàng trong bảng chương trình đãi ngộ. Vì vậy, mối quan hệ giữa nhân viên và các chương trình đãi ngộ là một mối quan hệ nhiều-nhiều.

Bài viết này được đăng tại [free tuts .net]

Thông thường, các cơ sở dữ liệu quan hệ không triển khai trực tiếp mối quan hệ nhiều-nhiều giữa hai bảng. Thay vào đó, chúng sử dụng một bảng thứ ba, bảng liên kết, để thiết lập hai mối quan hệ một-nhiều giữa hai bảng và bảng liên kết.

Sơ đồ sau minh họa mối quan hệ nhiều-nhiều trong cơ sở dữ liệu giữa các bảng hr_employee hr_compensation:

Django many to many example png

Bảng hr_employee_compensations là một bảng liên kết. Nó có hai khóa ngoại là employee_id compensation_id.

Khóa ngoại employee_id tham chiếu đến id của bảng hr_employee và khóa ngoại compensation_id tham chiếu đến id trong bảng hr_compensation.

Thông thường, bạn không cần cột id trong bảng hr_employee_compensations làm khóa chính và sử dụng cả employee_id compensation_id làm khóa chính tổng hợp. Tuy nhiên, Django luôn tạo cột id làm khóa chính cho bảng liên kết.

Ngoài ra, Django tạo một ràng buộc duy nhất bao gồm các cột employee_id compensation_id. Nói cách khác, sẽ không có cặp giá trị employee_id compensation_id trùng lặp trong bảng hr_employee_compensations.

Để tạo mối quan hệ nhiều-nhiều trong Django, bạn sử dụng ManyToManyField. Ví dụ sau sử dụng ManyToManyField để tạo mối quan hệ nhiều-nhiều giữa các mô hình Employee và Compensation:

class Compensation(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name
#Bài viết này được đăng tại freetuts.net
class Employee(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    contact = models.OneToOneField(
        Contact,
        on_delete=models.CASCADE,
        null=True
    )

    department = models.ForeignKey(
        Department,
        on_delete=models.CASCADE
    )
#Bài viết này được đăng tại freetuts.net
    compensations = models.ManyToManyField(Compensation)

    def __str__(self):
        return f'{self.first_name} {self.last_name}'

Cách thức hoạt động

Đầu tiên, định nghĩa một lớp mô hình Compensation mới mở rộng từ lớp models.Model.

Thứ hai, thêm trường compensations vào lớp Employee. Trường compensations sử dụng ManyToManyField để thiết lập mối quan hệ nhiều-nhiều giữa các lớp Employee và Compensation.

Để lan truyền các thay đổi của các mô hình vào cơ sở dữ liệu, bạn chạy lệnh makemigrations:

python manage.py makemigrations

Nó sẽ hiển thị thông tin như sau:

Migrations for 'hr':
  hr\migrations\0004_compensation_employee_compensations.py
    - Create model Compensation
    - Add field compensations to employee

Và thực hiện lệnh migrate:

python manage.py migrate

Django tạo hai bảng mới là hr_compensation và một bảng liên kết hr_employee_compensations như sau:

Django many to many example 20 1  png

Tạo dữ liệu trong Django

Đầu tiên, chạy lệnh shell_plus:

python manage.py shell_plus

Thứ hai, tạo ba chương trình đãi ngộ bao gồm Cổ phiếu, Thưởng và Chia sẻ Lợi nhuận:

>>> c1 = Compensation(name='Stock')
>>> c1.save()
#Bài viết này được đăng tại freetuts.net
>>> c2 = Compensation(name='Bonuses')
>>> c2.save()
>>> c3 = Compensation(name='Profit Sharing')
>>> c3.save()
>>> Compensation.objects.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>, <Compensation: Profit Sharing>]>

Lấy nhân viên có tên là freetuts và họ là .net:

>>> e = Employee.objects.filter(first_name='freetuts',last_name='.net').first()
>>> e
<Employee: freetut.net>

Thêm các chương trình đãi ngộ cho nhân viên

Đầu tiên, thêm .net freetuts vào các chương trình đãi ngộ cổ phiếu (c1) và thưởng (c2) sử dụng phương thức add() của thuộc tính compensations và phương thức save() của đối tượng Employee:

>>> e.compensations.add(c1)
>>> e.compensations.add(c2)
>>> e.save()

Thứ hai, truy cập tất cả các chương trình đãi ngộ của John Doe sử dụng phương thức all() của thuộc tính compensations:

>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>]>

Rõ ràng trong kết quả, John Doe có hai chương trình đãi ngộ.

Thứ ba, thêm .net freetuts vào ba chương trình đãi ngộ bao gồm cổ phiếu, thưởng và chia sẻ lợi nhuận:

>>> e = Employee.objects.filter(first_name='Jane',last_name='Doe').first()
>>> e
<Employee: Jane Doe>
>>> e.compensations.add(c1)
>>> e.compensations.add(c2)
#Bài viết này được đăng tại freetuts.net
>>> e.compensations.add(c3)
>>> e.save()
>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>, <Compensation: Profit Sharing>]>

Bên trong, Django đã chèn các id của nhân viên và các chương trình đãi ngộ vào bảng liên kết:

 id | employee_id | compensation_id
----+-------------+-----------------
  1 |           5 |               1
  2 |           5 |               2
  3 |           6 |               1
  4 |           6 |               2
  5 |           6 |               3
(5 rows)

ìm tất cả nhân viên đã tham gia chương trình cổ phiếu sử dụng thuộc tính employee_set của đối tượng Compensation:

>>> c1
<Compensation: Stock>
#Bài viết này được đăng tại freetuts.net
>>> c1.employee_set.all()
<QuerySet [<Employee: freetut.net>, <Employee: .net freetuts>]>

Nó trả về hai nhân viên như mong đợi.

Thứ năm, bạn có thể sử dụng thuộc tính employee_set để tìm tất cả nhân viên có chương trình chia sẻ lợi nhuận:

>>> c3
<Compensation: Profit Sharing>
>>> c3.employee_set.all()
#Bài viết này được đăng tại freetuts.net
<QuerySet [<Employee: .net freetuts>]>

Nó trả về một nhân viên.

Django cho phép bạn truy vấn qua mối quan hệ. Ví dụ, bạn có thể tìm tất cả nhân viên có chương trình đãi ngộ với id là 1:

>>> Employee.objects.filter(compensations__id=1)
<QuerySet [<Employee: freetuts .net>, <Employee: .net freetuts>]>

Hoặc với tên là "Profit Sharing":

>>> Employee.objects.filter(compensations__name="Profit Sharing")
<QuerySet [<Employee: .net freetuts>]>

Xóa chương trình đãi ngộ khỏi nhân viên

Để xóa một chương trình đãi ngộ khỏi nhân viên, bạn sử dụng phương thức remove() của thuộc tính compensations của đối tượng Employee. Ví dụ:

Đầu tiên, lấy nhân viên có tên là .net freetuts:

>>> e = Employee.objects.filter(first_name='.net',last_name='freetuts').first()
>>> e
<Employee: .net freetuts>

Thứ hai, xóa chương trình chia sẻ lợi nhuận (c3) khỏi .net freetuts và lưu thay đổi vào cơ sở dữ liệu:

>>> e.compensations.remove(c3)
>>> e.save()

Lấy tất cả các chương trình đãi ngộ của .net freetuts:

>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>]>

Kết bài

Trong một mối quan hệ nhiều-nhiều, nhiều hàng trong một bảng có liên quan đến nhiều hàng trong một bảng khác. Các cơ sở dữ liệu quan hệ sử dụng bảng liên kết để thiết lập mối quan hệ nhiều-nhiều giữa hai bảng, cho phép quản lý và truy xuất dữ liệu một cách hiệu quả. Việc sử dụng ManyToManyField trong Django giúp bạn mô hình hóa một cách trực quan và dễ dàng các mối quan hệ phức tạp này giữa các mô hình. Bằng cách nắm vững cách thiết lập và quản lý mối quan hệ nhiều-nhiều, bạn có thể xây dựng các ứng dụng Django mạnh mẽ và linh hoạt, đáp ứng tốt các yêu cầu phức tạp của dự án.

Cùng chuyên mục:

Cách tạo thư mục lồng nhau (nested directory) trong Python

Cách tạo thư mục lồng nhau (nested directory) trong Python

Cách thêm số 0 vào đầu chuỗi trong Python

Cách thêm số 0 vào đầu chuỗi trong Python

Sự khác biệt giữa @classmethod, @staticmethod và instance methods trong Python

Sự khác biệt giữa @classmethod, @staticmethod và instance methods trong Python

Sự khác biệt giữa str và repr trong Python

Sự khác biệt giữa str và repr trong Python

Các cách nối hai danh sách trong Python

Các cách nối hai danh sách trong Python

Sự khác biệt giữa append() và extend() trong list Python

Sự khác biệt giữa append() và extend() trong list Python

5 lỗi thường gặp trong Python

5 lỗi thường gặp trong Python

Các tính năng mới trong Python 3.10

Các tính năng mới trong Python 3.10

Tạo app ghi chú trong Python với nhận dạng giọng nói và API Notion

Tạo app ghi chú trong Python với nhận dạng giọng nói và API Notion

Làm chủ Pattern Matching trong Python 3.10

Làm chủ Pattern Matching trong Python 3.10

Cách yêu cầu người dùng nhập liệu đến khi nhận được phản hồi hợp lệ trong Python

Cách yêu cầu người dùng nhập liệu đến khi nhận được phản hồi hợp lệ trong Python

8 Mẹo Refactor Code Python nhanh gọn (Phần 2)

8 Mẹo Refactor Code Python nhanh gọn (Phần 2)

Cách sao chép file trong Python

Cách sao chép file trong Python

31 Phương thức xử lý chuỗi (String) quan trọng trong Python

31 Phương thức xử lý chuỗi (String) quan trọng trong Python

Cách xóa file và thư mục trong Python

Cách xóa file và thư mục trong Python

Tìm hiểu về *args và **kwargs trong Python

Tìm hiểu về *args và **kwargs trong Python

Cách làm phẳng danh sách lồng nhau trong Python

Cách làm phẳng danh sách lồng nhau trong Python

Phân tích dữ liệu Apple Health bằng Python

Phân tích dữ liệu Apple Health bằng Python

Cách loại bỏ phần tử trùng lặp khỏi danh sách (List) trong Python

Cách loại bỏ phần tử trùng lặp khỏi danh sách (List) trong Python

Cách cắt (slicing) chuỗi trong Python

Cách cắt (slicing) chuỗi trong Python

Top