Cơ chế View và Routing trong Django REST Framework

Hệ thống View trong Django REST Framework

1. Lớp APIView

APIView là lớp cơ sở cho tất cả các view trong DRF, kế thừa trực tiếp từ lớp View của Django nhưng được bổ sung các tính năng quan trọng để xây dựng Web API:

  • Request và Response mới: DRF đóng gói HttpRequest của Django thành đối tượng Request linh hoạt hơn, cho phép truy cập dữ liệu qua request.data thay vì phải phân biệt giữa POST hay PUT.
  • Xử lý định dạng: Sử dụng parser_classes để giải mã dữ liệu đầu vào và renderer_classes để định dạng dữ liệu đầu ra.
  • Chính sách bảo mật: Tự động loại bỏ kiểm tra CSRF (vì REST thường dùng Token/Session riêng) và thực thi chu kỳ: Xác thực (Authentication) -> Phân quyền (Permission) -> Giới hạn lưu lượng (Throttling).
# Cấu trúc cơ bản của APIView nội bộ
def dispatch(self, request, *args, **kwargs):
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    try:
        self.initial(request, *args, **kwargs) # Thực hiện 3 đại xác thực
        # ... xử lý method (GET, POST, ...)
    except Exception as exc:
        response = self.handle_exception(exc)
    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

2. Lớp GenericAPIView

Kế thừa từ APIView, GenericAPIView cung cấp các thuộc tính và phương thức hỗ trợ làm việc với Model và Serializer một cách hệ thống hơn thông qua querysetserializer_class.

from rest_framework.generics import GenericAPIView
from .models import Product
from .serializers import ProductSerializer, ProductDetailSerializer

class ProductManagementView(GenericAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    def get_serializer_class(self):
        # Thay đổi serializer dựa trên phương thức yêu cầu
        if self.request.method == 'GET':
            return ProductDetailSerializer
        return super().get_serializer_class()

    def get(self, request, *args, **kwargs):
        objs = self.get_queryset()
        serializer = self.get_serializer(objs, many=True)
        return Response(serializer.data)

3. Mixins và View con (Concrete View Classes)

DRF cung cấp 5 Mixin cơ bản tương ứng với các thao tác CRUD:

  • ListModelMixin: Cung cấp phương thức list().
  • CreateModelMixin: Cung cấp phương thức create().
  • RetrieveModelMixin: Cung cấp phương thức retrieve().
  • UpdateModelMixin: Cung cấp phương thức update().
  • DestroyModelMixin: Cung cấp phương thức destroy().

Các lớp View con (như ListCreateAPIView, RetrieveUpdateDestroyAPIView) đơn giản là sự kết hợp giữa GenericAPIView và các Mixin này để rút ngắn mã nguồn.

ViewSet và ViewSetMixin

ViewSet không cung cấp các trình xử lý phương thức (get, post), thay vào đó nó cung cấp các hành động (list, create, retrieve, update, destroy). Việc ánh xạ hành động vào phương thức HTTP chỉ diễn ra khi View được định nghĩa trong URL.

from rest_framework import viewsets

class TaskViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

    # custom action
    @action(detail=True, methods=['post'])
    def mark_completed(self, request, pk=None):
        task = self.get_object()
        task.status = 'completed'
        task.save()
        return Response({'status': 'task marked as done'})

Hệ thống Routing tự động

Khi sử dụng ViewSet, chúng ta không cần khai báo từng URL thủ công mà sử dụng các lớp Router.

1. SimpleRouter và DefaultRouter

  • SimpleRouter: Tạo ra các đường dẫn cơ bản cho tập hợp dữ liệu và từng mục riêng lẻ.
  • DefaultRouter: Tương tự như SimpleRouter nhưng bổ sung một trang API Root mặc định giúp kiểm tra các endpoint trên trình duyệt dễ dàng hơn.
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'tasks', TaskViewSet, basename='task')

urlpatterns = [
    # Các route khác
]
urlpatterns += router.urls

2. Decorator @action

Để thêm các endpoint tùy chỉnh ngoài các thao tác CRUD mặc định, DRF cung cấp decorator @action.

  • methods: Danh sách các phương thức HTTP (GET, POST...).
  • detail: Nếu là True, URL sẽ bao gồm ID (ví dụ: /tasks/1/mark_completed/). Nếu False, nó áp dụng cho toàn bộ danh sách (ví dụ: /tasks/export_csv/).
  • url_path: Tên đường dẫn trên URL (mặc định lấy tên hàm).
class OrderViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    @action(detail=False, methods=['get'], url_path='recent-orders')
    def get_recent(self, request):
        recent_orders = self.get_queryset().order_by('-created_at')[:5]
        serializer = self.get_serializer(recent_orders, many=True)
        return Response(serializer.data)

Thẻ: django-rest-framework python web-api Routing viewsets

Đăng vào ngày 17 tháng 8 lúc 18:33