# Django 6.0 năm 2026: Composite Primary Key, Background Task và Câu hỏi phỏng vấn
> Hướng dẫn toàn diện về Django 6.0 bao gồm composite primary key, framework background task tích hợp, template partial, CSP middleware cùng ví dụ code thực tế và chuẩn bị phỏng vấn.
- Published: 2026-06-09
- Updated: 2026-06-09
- Author: SharpSkill
- Tags: django, python, composite-primary-keys, background-tasks, interview
- Reading time: 8 min
---
Django 6.0, phát hành vào tháng 12 năm 2025, mang đến framework background task tích hợp, template partial và hỗ trợ Content Security Policy native cho framework web Python phổ biến nhất. Kết hợp với composite primary key được giới thiệu trong Django 5.2, hệ sinh thái Django năm 2026 cung cấp bộ công cụ mạnh mẽ hơn đáng kể để xây dựng ứng dụng production.
> **Dòng thời gian phiên bản Django năm 2026**
>
> Django 5.2 LTS (tháng 4/2025) giới thiệu composite primary key. Django 6.0 (tháng 12/2025) bổ sung background task, template partial và CSP middleware. Django 6.1 hiện đang được phát triển với field fetch mode.
## Composite Primary Key với CompositePrimaryKey
Trong suốt 18 năm, Django buộc mọi model phải sử dụng primary key đơn cột. Django 5.2 đã thay đổi điều đó với class [`CompositePrimaryKey`](https://docs.djangoproject.com/en/6.0/topics/composite-primary-key/), cho phép primary key đa cột trực tiếp trong ORM.
Composite primary key loại bỏ nhu cầu sử dụng cột surrogate `AutoField` trên các bảng junction và bất kỳ model nào có natural key trải rộng nhiều cột. Cơ sở dữ liệu thực thi tính duy nhất ở cấp primary key, giảm chi phí lưu trữ và cải thiện hiệu năng truy vấn trên các indexed lookup.
```python
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
sku = models.CharField(max_length=20, unique=True)
class Warehouse(models.Model):
code = models.CharField(max_length=10, primary_key=True)
location = models.CharField(max_length=200)
class Inventory(models.Model):
pk = models.CompositePrimaryKey("product_id", "warehouse_id")
product = models.ForeignKey(Product, on_delete=models.CASCADE)
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=0)
last_restocked = models.DateTimeField(auto_now=True)
```
Model `Inventory` ở trên tạo constraint `PRIMARY KEY (product_id, warehouse_id)` ở cấp cơ sở dữ liệu. Không có cột `id` bổ sung nào được tạo ra.
### Truy vấn Composite Key
Composite primary key được biểu diễn dưới dạng tuple trong Python. Việc filter, fetch và gán đều hoạt động thông qua giao diện tuple này.
```python
# views.py
from .models import Inventory, Product, Warehouse
# Tạo bản ghi
laptop = Product.objects.create(name="Laptop Pro", sku="LP-001")
warehouse_a = Warehouse.objects.create(code="WH-A", location="Berlin")
item = Inventory.objects.create(
product=laptop,
warehouse=warehouse_a,
quantity=50
)
# Truy cập composite pk dưới dạng tuple
print(item.pk) # (1, "WH-A")
# Filter theo composite pk
result = Inventory.objects.filter(pk=(1, "WH-A")).first()
# Gán composite pk trực tiếp
new_item = Inventory(pk=(2, "WH-B"))
print(new_item.product_id) # 2
print(new_item.warehouse_id) # "WH-B"
```
Ba hạn chế cần lưu ý hiện tại: `ForeignKey` không thể tham chiếu đến model có composite primary key (sử dụng `ForeignObject` thay thế), Django admin chưa hỗ trợ model composite key, và việc chuyển đổi giữa single và composite key sau khi tạo bảng đòi hỏi SQL thủ công.
## Background Task tích hợp trong Django 6.0
Trước Django 6.0, việc chạy code bên ngoài vòng request-response đòi hỏi [Celery](https://docs.celeryq.dev/en/stable/), Django-Q hoặc các task queue bên thứ ba tương tự. Django 6.0 cung cấp một [framework task](https://docs.djangoproject.com/en/6.0/topics/tasks/) native xử lý việc định nghĩa và enqueue task ngay trong framework.
Decorator `@task` đánh dấu bất kỳ hàm nào là có thể enqueue. Việc gọi `.enqueue()` trên hàm đã được decorate sẽ gửi nó đến backend để thực thi bất đồng bộ. Framework tách biệt việc định nghĩa task khỏi việc thực thi task: Django xử lý hàng đợi, nhưng một tiến trình worker riêng biệt xử lý việc chạy task.
```python
# tasks.py
from django.tasks import task
from django.core.mail import send_mail
@task
def send_welcome_email(user_email, username):
"""Send a welcome email after user registration."""
send_mail(
subject="Welcome to the platform",
message=f"Hello {username}, your account is ready.",
from_email=None, # uses DEFAULT_FROM_EMAIL
recipient_list=[user_email],
)
return f"Email sent to {user_email}"
@task
def generate_report(report_id, format="pdf"):
"""Generate an export report asynchronously."""
from .services import ReportService
report = ReportService.generate(report_id, format=format)
return report.file_path
```
```python
# views.py
from .tasks import send_welcome_email, generate_report
def register_user(request):
# ... logic tạo user ...
# Enqueue task để thực thi nền
send_welcome_email.enqueue(
user_email=user.email,
username=user.username
)
return redirect("dashboard")
def export_view(request, report_id):
generate_report.enqueue(report_id=report_id, format="csv")
return JsonResponse({"status": "processing"})
```
Cài đặt `TASKS` trong `settings.py` cấu hình backend. Django cung cấp hai backend tích hợp cho development và testing. Triển khai production đòi hỏi backend bên thứ ba hoặc triển khai tùy chỉnh kết nối đến message broker.
> **Background task vs Celery**
>
> Framework task tích hợp của Django phù hợp cho các trường hợp sử dụng đơn giản: fire-and-forget task, gửi email, tạo báo cáo. Đối với các tính năng nâng cao như task chaining, lập lịch định kỳ, rate limiting hoặc result backend, [Celery](/blog/django/django-celery-async-tasks-interview-2026) vẫn là lựa chọn tiêu chuẩn.
## Template Partial cho các Fragment tái sử dụng
Django 6.0 giới thiệu các tag template `{% partialdef %}` và `{% partial %}`. Chúng cho phép định nghĩa các fragment template có tên, có thể tái sử dụng trong một file duy nhất, giảm nhu cầu tạo nhiều file include nhỏ rải rác khắp thư mục template.
Partial được định nghĩa một lần với `{% partialdef %}` và render ở bất kỳ đâu trong cùng template (hoặc từ template khác) với `{% partial %}`. Partial cũng chấp nhận cú pháp tiêu chuẩn `template_name#partial_name` với `{% include %}`.
```html
{% partialdef product_card %}
{{ product.name }}
{{ product.price|floatformat:2 }} EUR
{% if product.in_stock %}In Stock{% else %}Sold Out{% endif %}
{% endpartialdef %}
{% partialdef product_row %}
| {{ product.name }} |
{{ product.price|floatformat:2 }} EUR |
{{ product.quantity }} |
{% endpartialdef %}
```
```html
{% extends "base.html" %}
{% block content %}
{% for product in products %}
{% include "components/cards.html#product_card" %}
{% endfor %}
{% endblock %}
```
Cách tiếp cận này giữ các markup liên quan ở cùng nhau. Thay vì tạo `_product_card.html` và `_product_row.html` dưới dạng file riêng biệt, cả hai partial đều nằm trong một file component `cards.html` duy nhất.
## CSP Middleware tích hợp
Django 6.0 bổ sung [hỗ trợ CSP tích hợp](https://docs.djangoproject.com/en/6.0/ref/middleware/#content-security-policy-middleware) thông qua `ContentSecurityPolicyMiddleware`. Trước đây, điều này đòi hỏi package bên thứ ba `django-csp`.
Header CSP thông báo cho trình duyệt biết nguồn nội dung nào (script, style, hình ảnh, font) được phép tải trên trang. Điều này giảm thiểu các cuộc tấn công cross-site scripting (XSS) và data injection.
```python
# settings.py
from django.utils.csp import CSP
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.middleware.security.ContentSecurityPolicyMiddleware",
# ... middleware khác
]
SECURE_CSP = {
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE],
"style-src": [CSP.SELF, "https://fonts.googleapis.com"],
"img-src": [CSP.SELF, "https:", "data:"],
"font-src": [CSP.SELF, "https://fonts.gstatic.com"],
"connect-src": [CSP.SELF],
}
# Chế độ report-only để testing (không chặn, chỉ báo cáo vi phạm)
SECURE_CSP_REPORT_ONLY = {
"default-src": [CSP.SELF],
"report-uri": ["/csp-report/"],
}
```
Hằng số `CSP.NONCE` hoạt động với context processor `csp()` để chèn nonce theo từng request vào template. Các script inline được gắn nonce này sẽ vượt qua kiểm tra CSP; tất cả các script khác bị chặn.
## Các thay đổi đáng chú ý khác trong Django 6.0
Ngoài các tính năng chính, Django 6.0 bao gồm một số thay đổi ảnh hưởng đến công việc phát triển hàng ngày.
**BigAutoField làm primary key mặc định.** Các dự án mới giờ sử dụng `BigAutoField` (64-bit) thay vì `AutoField` (32-bit) cho primary key tự động sinh. Các dự án hiện có không bị ảnh hưởng trừ khi `DEFAULT_AUTO_FIELD` được thay đổi rõ ràng. Điều này ngăn chặn vấn đề integer overflow mà các ứng dụng có lưu lượng truy cập cao cuối cùng sẽ gặp phải với key 32-bit.
**Phân trang async.** Các class `AsyncPaginator` và `AsyncPage` mới mang đến hỗ trợ async native cho phân trang, hữu ích trong các view async truy vấn cơ sở dữ liệu qua giao diện ORM async của Django.
**Auto-import trong shell.** Lệnh `manage.py shell` giờ tự động import tất cả model và các tiện ích Django phổ biến. Không cần phải gõ `from myapp.models import *` mỗi khi bắt đầu phiên shell.
**API email hiện đại.** Các class email của Django giờ sử dụng `email.message.EmailMessage` của Python thay vì các class MIME legacy, cải thiện xử lý Unicode và đơn giản hóa quản lý tệp đính kèm.
## Câu hỏi phỏng vấn Django năm 2026
Các cuộc phỏng vấn kỹ thuật năm 2026 ngày càng đề cập nhiều đến các tính năng mới của Django cùng với các kiến thức cơ bản về ORM, middleware và REST framework. Dưới đây là những câu hỏi phản ánh trạng thái hiện tại của framework.
**Composite primary key giải quyết vấn đề gì và có những hạn chế nào?**
Composite primary key loại bỏ các cột surrogate key trên các model có natural key trải rộng nhiều field (bảng junction, audit log, bản ghi có version). Cơ sở dữ liệu thực thi tính duy nhất và lập index ở cấp primary key. Các hạn chế hiện tại bao gồm không hỗ trợ `ForeignKey` đến model composite key, không tích hợp Django admin, và không có đường dẫn migration từ single sang composite key sau khi tạo bảng.
**Framework background task của Django 6.0 khác gì so với Celery?**
Decorator `@task` tích hợp của Django và method `.enqueue()` cung cấp task queue nhẹ cho các thao tác async đơn giản. Framework không bao gồm lập lịch task định kỳ, task chaining, rate limiting hoặc lưu trữ kết quả. Celery vẫn cần thiết cho việc điều phối workflow phức tạp. Framework tích hợp phù hợp cho fire-and-forget task như gửi email hoặc kích hoạt webhook.
**Giải thích thứ tự thực thi middleware của Django và CSP middleware đóng vai trò như thế nào.**
Django xử lý middleware theo thứ tự trong giai đoạn request (từ trên xuống dưới trong `MIDDLEWARE`) và theo thứ tự ngược lại trong giai đoạn response. `ContentSecurityPolicyMiddleware` chạy trong giai đoạn response, thêm header CSP trước khi response đến client. Đặt nó sau `SecurityMiddleware` đảm bảo redirect HTTPS xảy ra trước khi header CSP được áp dụng. Để tìm hiểu thêm về chủ đề này, tham khảo [câu hỏi phỏng vấn Django middleware](/technologies/django/interview-questions/django-middleware).
**Template partial là gì và khi nào nên thay thế `{% include %}`?**
Template partial (`{% partialdef %}` / `{% partial %}`) định nghĩa các fragment có tên trong một file template duy nhất. Chúng giảm sự phân tán file so với các file include riêng biệt. Partial lý tưởng cho các component nhỏ, liên quan chặt chẽ (các biến thể card, định dạng hàng bảng) thuộc cùng một template logic. Đối với các component lớn, độc lập được sử dụng trên các trang không liên quan, file template riêng biệt với `{% include %}` vẫn rõ ràng hơn.
> **Migration từ Django 5.2 lên 6.0**
>
> Django 6.0 ngừng hỗ trợ Python 3.10 và 3.11. Giá trị mặc định `DEFAULT_AUTO_FIELD` thay đổi thành `BigAutoField`. Các class email giờ sử dụng API email hiện đại của Python, có thể gây lỗi cho code phụ thuộc vào internal MIME legacy. Cần kiểm tra kỹ lưỡng trước khi nâng cấp ứng dụng production.
## Kết luận
- Composite primary key (`CompositePrimaryKey`) loại bỏ cột surrogate trên bảng junction — định nghĩa thuộc tính `pk` dưới dạng tuple tên field và truy vấn bằng tuple
- Framework `@task` / `.enqueue()` tích hợp xử lý background work đơn giản mà không cần Celery, dù Celery vẫn cần thiết cho lập lịch và chaining
- Template partial (`{% partialdef %}` / `{% partial %}`) nhóm các fragment template liên quan trong một file, truy cập qua cú pháp `template_name#partial_name`
- CSP middleware tích hợp (`ContentSecurityPolicyMiddleware`) thay thế `django-csp` cho hầu hết các trường hợp sử dụng, được cấu hình qua `SECURE_CSP` trong settings
- Django 6.0 mặc định dùng `BigAutoField`, bổ sung phân trang async, auto-import trong shell và áp dụng API email hiện đại của Python
- Chuẩn bị phỏng vấn nên bao gồm hạn chế của composite key, so sánh framework task vs Celery, và thứ tự thực thi middleware với layer CSP mới
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/vi/blog/django/django-6-composite-primary-keys-background-tasks-2026