Phân tích về Lớp Serializer và Lớp View trong Django REST Framework

Trong Django REST Framework (DRF), việc xử lý dữ liệu và logic nghiệp vụ được phân tách rõ ràng thông qua các lớp Serializer và View.

1. Lớp Serializer

Serializer là thành phần cốt lõi để chuyển đổi dữ liệu phức tạp (như Django models) thành các kiểu dữ liệu dễ dàng truyền qua API (như JSON) và ngược lại.

1.1. Lớp Serializer cơ bản

Khi sử dụng Serializer, bạn cần định nghĩa tường minh từng trường dữ liệu, bao gồm tên và kiểu dữ liệu.


from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=100)
    price = serializers.IntegerField()
    publication_date = serializers.DateField()
    

Các tham số quan trọng khi khởi tạo Serializer:

  • instance: Đối tượng dữ liệu lấy từ cơ sở dữ liệu, dùng để hiển thị hoặc cập nhật.
  • many=True: Chỉ định rằng dữ liệu đầu vào là một tập hợp (danh sách) các đối tượng.
  • data: Dữ liệu nhận được từ request (thường là POST, PUT), dùng để tạo mới hoặc cập nhật.

Phương thức .save() của Serializer sẽ gọi .create() hoặc .update() tùy thuộc vào việc có instance được cung cấp hay không. Bạn cần tự định nghĩa hai phương thức này để xử lý logic lưu trữ dữ liệu cụ thể:


def create(self, validated_data):
    # Logic tạo mới
    pass

def update(self, instance, validated_data):
    # Logic cập nhật
    pass
    

1.2. Lớp ModelSerializer

ModelSerializer giúp đơn giản hóa quá trình tạo serializer bằng cách tự động sinh các trường dựa trên một Django model.


from rest_framework import serializers
from .models import Book # Giả sử có model Book

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name', 'publication_date'] # Hoặc '__all__' để lấy tất cả trường
    

ModelSerializer đã tự động triển khai các phương thức .create().update(), loại bỏ nhu cầu định nghĩa thủ công.

2. Lớp View

Trong Django, View đóng vai trò là nơi chứa logic xử lý yêu cầu HTTP và trả về phản hồi. DRF cung cấp các lớp View mạnh mẽ hơn, dựa trên Class-Based Views (CBV).

2.1. Class-Based Views (CBV) gốc của Django

CBV giúp tổ chức code theo các phương thức HTTP (GET, POST, PUT, DELETE).

  • View.as_view(): Một phương thức class-level, trả về một hàm có thể được sử dụng trong urls.py.
  • View.dispatch(): Phương thức nội bộ, xử lý việc định tuyến yêu cầu đến phương thức HTTP tương ứng (get(), post(), v.v.).

Sự khác biệt chính so với Function-Based Views (FBV) là cách ánh xạ URL: CBV ánh xạ đến .as_view(), cho phép DRF tự động gọi các hàm xử lý theo phương thức HTTP.

2.2. Lớp APIView

APIView là lớp cơ sở của DRF cho các views API, kế thừa từ View của Django.

  • Cung cấp dispatch() được tùy chỉnh để xử lý các đối tượng request của DRF, bổ sung các tính năng như xác thực (authentication), phân quyền (permissions), và giới hạn tốc độ (rate limiting).
  • Vẫn yêu cầu bạn định nghĩa các phương thức xử lý HTTP như get(), post(), put(), delete().

2.3. Lớp GenericAPIView

GenericAPIView kế thừa từ APIView và cung cấp các thuộc tính cấu hình hữu ích:

  • queryset: Tập hợp các đối tượng từ model để làm việc.
  • serializer_class: Lớp serializer sẽ được sử dụng.

GenericAPIView thường được sử dụng kết hợp với các lớp Mixin thông qua đa kế thừa để cung cấp các hành động CRUD.

2.4. Lớp Mixin

Các lớp Mixin của DRF (CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin) cung cấp các phương thức triển khai logic cho từng hành động CRUD:

  • CreateModelMixin: Triển khai phương thức create().
  • ListModelMixin: Triển khai phương thức list().
  • RetrieveModelMixin: Triển khai phương thức retrieve().
  • UpdateModelMixin: Triển khai phương thức update().
  • DestroyModelMixin: Triển khai phương thức destroy().

Các phương thức này có tên khác với tên phương thức HTTP (get, post). Bạn cần định nghĩa các phương thức HTTP trong view của mình và gọi các phương thức Mixin tương ứng.


# views.py
from rest_framework import generics, mixins
from .models import HouseKu
from .serializers import HouseKuSerializer

class HouseKuListView(mixins.CreateModelMixin, 
                      mixins.ListModelMixin, 
                      generics.GenericAPIView):
    queryset = HouseKu.objects.all()
    serializer_class = HouseKuSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

# urls.py
# path('houseku/', views.HouseKuListView.as_view()),
    

2.5. Các lớp View tổng hợp (Generic Views)

DRF cung cấp các lớp View đã được đóng gói sẵn, kết hợp GenericAPIView với các Mixin tương ứng:

  • ListAPIView: Hiển thị danh sách (ListModelMixin + GenericAPIView).
  • CreateAPIView: Tạo mới (CreateModelMixin + GenericAPIView).
  • RetrieveAPIView: Lấy chi tiết (RetrieveModelMixin + GenericAPIView).
  • UpdateAPIView: Cập nhật (UpdateModelMixin + GenericAPIView).
  • DestroyAPIView: Xóa (DestroyModelMixin + GenericAPIView).
  • ListCreateAPIView: Kết hợp hiển thị danh sách và tạo mới.
  • RetrieveUpdateDestroyAPIView: Kết hợp lấy chi tiết, cập nhật và xóa.

# views.py
from rest_framework import generics
from .models import User
from .serializers import UserSerializer

class UserListCreateView(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

# urls.py
# path('user/', views.UserListCreateView.as_view()),
# path('user//', views.UserRetrieveUpdateDestroyView.as_view()),
    

2.6. Lớp ViewSet

ViewSet giúp hợp nhất các view cho cùng một model, loại bỏ việc phải tạo hai lớp view riêng biệt cho danh sách và chi tiết.

  • ViewSetMixin: Cho phép ánh xạ các phương thức HTTP tới các hành động tùy chỉnh trong urls.py bằng cách truyền một dictionary vào .as_view().
  • GenericViewSet: Kết hợp ViewSetMixinGenericAPIView, cung cấp querysetserializer_class, nhưng không tự implement logic CRUD.
  • ModelViewSet: Là lớp mạnh mẽ nhất, kế thừa từ GenericViewSet và tất cả các lớp Mixin CRUD. Nó cung cấp đầy đủ các hành động CRUD mà không cần định nghĩa thêm phương thức HTTP.

# views.py
from rest_framework import viewsets
from .models import User
from .serializers import UserSerializer

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

# urls.py
# from django.urls import path
# from . import views
# 
# urlpatterns = [
#     path('users/', views.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
#     path('users//', views.UserViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
# ]
    

3. Tóm tắt

  • Django CBV (View): Cung cấp as_view()dispatch(), yêu cầu tách biệt view cho danh sách và chi tiết.
  • DRF APIView: Mở rộng View với request được đóng gói, vẫn cần tách biệt view.
  • DRF GenericAPIView: Thêm querysetserializer_class, cần kết hợp với Mixin để có chức năng.
  • DRF Mixins: Cung cấp các phương thức CRUD riêng lẻ (list, create, v.v.), cần được kế thừa cùng GenericAPIView.
  • DRF Generic Views (ListCreateAPIView, ...): Đóng gói sẵn các tổ hợp Mixin và GenericAPIView, tiện lợi cho các tác vụ CRUD tiêu chuẩn.
  • DRF ViewSetMixin: Cho phép ánh xạ phương thức HTTP tới hành động tùy chỉnh qua urls.py, giúp gộp view danh sách và chi tiết.
  • DRF GenericViewSet: Kết hợp ViewSetMixinGenericAPIView, tạo nền tảng cho ModelViewSet.
  • DRF ModelViewSet: Lớp toàn diện nhất, kết hợp tất cả Mixins và GenericViewSet, cung cấp đầy đủ chức năng CRUD cho một model chỉ với querysetserializer_class.

4. Ví dụ minh họa

4.1. Sử dụng APIView


# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User
from .serializers import UserSerializer

class UserAPIView(APIView):
    def get(self, request):
        all_users = User.objects.all()
        serializer = UserSerializer(all_users, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

class UserDetailAPIView(APIView):
    def get(self, request, user_id):
        user_instance = User.objects.get(pk=user_id)
        serializer = UserSerializer(user_instance)
        return Response(serializer.data)

    def put(self, request, user_id):
        user_instance = User.objects.get(pk=user_id)
        serializer = UserSerializer(user_instance, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=400)

    def delete(self, request, user_id):
        user_instance = User.objects.get(pk=user_id)
        user_instance.delete()
        return Response(status=204)

# urls.py
# path('api/users/', views.UserAPIView.as_view()),
# path('api/users//', views.UserDetailAPIView.as_view()),
    

4.2. Sử dụng GenericAPIView và Mixins


# views.py
from rest_framework import generics, mixins
from .models import User
from .serializers import UserSerializer

class UserMixinListView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        generics.GenericAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class UserMixinDetailView(mixins.RetrieveModelMixin,
                          mixins.UpdateModelMixin,
                          mixins.DestroyModelMixin,
                          generics.GenericAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

# urls.py
# path('mixin/users/', views.UserMixinListView.as_view()),
# path('mixin/users//', views.UserMixinDetailView.as_view()),
    

4.3. Sử dụng các lớp View tổng hợp (ListCreateAPIView, v.v.)


# views.py
from rest_framework import generics
from .models import User
from .serializers import UserSerializer

class UserGenericListCreateView(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserGenericRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

# urls.py
# path('generic/users/', views.UserGenericListCreateView.as_view()),
# path('generic/users//', views.UserGenericRetrieveUpdateDestroyView.as_view()),
    

4.4. Sử dụng ModelViewSet


# views.py
from rest_framework import viewsets
from .models import User
from .serializers import UserSerializer

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

# urls.py
# from django.urls import path, include
# from rest_framework.routers import DefaultRouter
# from . import views
# 
# router = DefaultRouter()
# router.register(r'users', views.UserViewSet, basename='user')
# urlpatterns = router.urls
# 
# # Hoặc định nghĩa thủ công trong urls.py
# # urlpatterns = [
# #     path('viewset/users/', views.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
# #     path('viewset/users//', views.UserViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
# # ]
    

Thẻ: Django REST Framework Serializer APIView GenericAPIView

Đăng vào ngày 24 tháng 7 lúc 20:57