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ệ ManyToManyField trong Django với Through
Trong Django, mối quan hệ nhiều-nhiều cho phép nhiều hàng trong một bảng liên kết với nhiều hàng trong một bảng khác. Để thiết lập mối quan hệ này, thường sử dụng một bảng liên kết trung gian. Tuy nhiên, có những tình huống yêu cầu bổ sung các trường thông tin vào bảng liên kết này để lưu trữ thêm dữ liệu về mối quan hệ. Trong bài viết này, bạn sẽ học cách sử dụng tham số through trong ManyToManyField của Django để thêm các trường bổ sung vào mối quan hệ nhiều-nhiều, giúp bạn quản lý dữ liệu một cách chi tiết và hiệu quả hơn.

Giới thiệu về ManyToManyField trong Django với Through
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. Để thiết lập mối quan hệ nhiều-nhiều, cơ sở dữ liệu quan hệ sử dụng một bảng thứ ba gọi là bảng liên kết và tạo ra hai mối quan hệ một-nhiều từ các bảng nguồn.
Thông thường, bảng liên kết chứa các giá trị id của các bảng nguồn để các hàng trong một bảng có thể liên quan đến các hàng trong bảng khác.
Đôi khi, bạn có thể muốn thêm các trường bổ sung vào bảng liên kết. Ví dụ, mỗi nhân viên có thể có nhiều công việc trong suốt sự nghiệp của họ.
Bài viết này được đăng tại [free tuts .net]
Để theo dõi thời gian khi một nhân viên bắt đầu và kết thúc một công việc, bạn có thể thêm các trường begin_date và end_date vào bảng liên kết.
Để làm điều đó trong Django, bạn sử dụng ManyToManyField với tham số through.
Ví dụ, sau đây cho thấy cách liên kết một nhân viên với nhiều công việc thông qua bảng assignments:
from django.db import models
class Employee(models.Model):
    # Các trường của Employee...
class Job(models.Model):
    title = models.CharField(max_length=255)
    employees = models.ManyToManyField(Employee, through='Assignment')
    def __str__(self):
        return self.title
#Bài viết này được đăng tại freetuts.net
class Assignment(models.Model):
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
    position = models.ForeignKey(Job, on_delete=models.CASCADE)
    begin_date = models.DateField()
    end_date = models.DateField(default=date(9999, 12, 31))
Cách hoạt động:
- Đầu tiên, định nghĩa mô hình Job, thêm thuộc tính employees sử dụng ManyToManyField và truyền Assignment làm tham số through.
 - Thứ hai, định nghĩa lớp Assignment có hai khóa ngoại, một liên kết đến mô hình Employee, và một liên kết đến mô hình Job. Cũng thêm các thuộc tính begin_date và end_date vào mô hình Assignment.
 - Chạy lệnh 
makemigrationsđể tạo các migrations mới: 
python manage.py makemigrations
Đầu ra sẽ như sau:
Migrations for 'hr':
  hr\migrations\0005_assignment_job_assignment_job.py
    - Create model Assignment
    - Create model Job
    - Add field job to assignment
Và thực thi lệnh migrate để áp dụng các thay đổi vào cơ sở dữ liệu:
python manage.py migrate
Đầu ra sẽ như sau:
Operations to perform: Apply all migrations: admin, auth, contenttypes, hr, sessions Running migrations: Applying hr.0005_assignment_job_assignment_job... OK
Phía sau, Django sẽ tạo các bảng hr_job và hr_assignment trong cơ sở dữ liệu.

Bảng hr_assignment là bảng liên kết. Ngoài các trường employee_id và position_id, nó còn có các trường begin_date và end_date.
Tạo dữ liệu mới trong Django
Đầu tiên, chạy lệnh shell_plus:
python manage.py shell_plus
Thứ hai, tạo ba công việc mới:
>>> j1 = Job(title='Software Engineer I') >>> j1.save() #Bài viết này được đăng tại freetuts.net >>> j2 = Job(title='Software Engineer II') >>> j2.save() >>> j3 = Job(title='Software Engineer III') >>> j3.save() >>> Job.objects.all() <QuerySet [<Job: Software Engineer I>, <Job: Software Engineer II>, <Job: Software Engineer III>]>
Tạo các thực thể cho models trung gian trong Django
Đầu tiên, tìm nhân viên có tên freetuts .net và .net freetuts:
>>> e1 = Employee.objects.filter(first_name='freetuts',last_name='.net').first() >>> e1 <Employee: freetuts .net> #Bài viết này được đăng tại freetuts.net >>> e2 = Employee.objects.filter(first_name='.net', last_name='freetuts').first() >>> e2 <Employee: .net freetuts>
Thứ hai, tạo các thực thể của mô hình trung gian (Assignment):
>>> from datetime import date >>> a1 = Assignment(employee=e1,job=j1, begin_date=date(2019,1,1), end_date=date(2021,12,31)) >>> a1.save() #Bài viết này được đăng tại freetuts.net >>> a2 = Assignment(employee=e1,job=j2, begin_date=date(2022,1,1)) >>> a2.save() >>> a3 = Assignment(employee=e2, job=j1, begin_date=date(2019, 3, 1)) >>> a3.save()
Tìm các nhân viên giữ vị trí Software Engineer I (j1):
>>> j1.employees.all() <QuerySet [<Employee: freetuts .net>, <Employee: .net freetuts>]>
Phía sau, Django thực hiện truy vấn sau:
SELECT
  "hr_employee"."id",
  "hr_employee"."first_name",
  "hr_employee"."last_name",
  "hr_employee"."contact_id",
  "hr_employee"."department_id"
FROM "hr_employee"
#Bài viết này được đăng tại freetuts.net
INNER JOIN "hr_assignment"
  ON ("hr_employee"."id" = "hr_assignment"."employee_id")
WHERE "hr_assignment"."job_id" = 1
Tương tự, bạn có thể tìm tất cả nhân viên giữ vị trí Software Engineer II:
>>> j2.employees.all() <QuerySet [<Employee: freetuts .net>]>
Xóa các thực thể của models trung gian trong Django
Đầu tiên, xóa .net freetuts (e2) khỏi công việc Software Engineer II bằng cách sử dụng phương thức remove():
>>> j2.employees.remove(e2)
Thứ hai, xóa tất cả nhân viên khỏi công việc Software Engineer I bằng cách sử dụng phương thức clear():
>>> j1.employees.clear()
Công việc j1 sẽ không có nhân viên nào nữa:
>>> j1.employees.all() <QuerySet []>
Kết bài
Việc sử dụng tham số through trong ManyToManyField của Django giúp bạn mở rộng khả năng lưu trữ và quản lý dữ liệu trong mối quan hệ nhiều-nhiều. Bạn có thể dễ dàng thêm các trường bổ sung vào bảng liên kết để lưu trữ thông tin chi tiết hơn về mối quan hệ giữa các bảng. Điều này không chỉ giúp cải thiện cấu trúc dữ liệu mà còn tăng tính linh hoạt và hiệu quả trong việc quản lý và truy vấn dữ liệu. Hy vọng hướng dẫn này đã cung cấp cho bạn những kiến thức cần thiết để áp dụng tham số through trong dự án Django của mình.

            Các kiểu dữ liệu trong C ( int - float - double - char ...)        
            Thuật toán tìm ước chung lớn nhất trong C/C++        
            Cấu trúc lệnh switch case trong C++ (có bài tập thực hành)        
            ComboBox - ListBox trong lập trình C# winforms        
            Random trong Python: Tạo số random ngẫu nhiên        
            Lệnh cin và cout trong C++        
                Cách khai báo biến trong PHP, các loại biến thường gặp            
                Download và cài đặt Vertrigo Server            
                Thẻ li trong HTML            
                Thẻ article trong HTML5            
                Cấu trúc HTML5: Cách tạo template HTML5 đầu tiên            
                Cách dùng thẻ img trong HTML và các thuộc tính của img            
                Thẻ a trong HTML và các thuộc tính của thẻ a thường dùng