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() và .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 trongurls.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ượngrequestcủ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ứccreate().ListModelMixin: Triển khai phương thứclist().RetrieveModelMixin: Triển khai phương thứcretrieve().UpdateModelMixin: Triển khai phương thứcupdate().DestroyModelMixin: Triển khai phương thứcdestroy().
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 trongurls.pybằng cách truyền một dictionary vào.as_view().GenericViewSet: Kết hợpViewSetMixinvàGenericAPIView, cung cấpquerysetvàserializer_class, nhưng không tự implement logic CRUD.ModelViewSet: Là lớp mạnh mẽ nhất, kế thừa từGenericViewSetvà 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ấpas_view()vàdispatch(), yêu cầu tách biệt view cho danh sách và chi tiết. - DRF
APIView: Mở rộngViewvới request được đóng gói, vẫn cần tách biệt view. - DRF
GenericAPIView: Thêmquerysetvàserializer_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ùngGenericAPIView. - 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 quaurls.py, giúp gộp view danh sách và chi tiết. - DRF
GenericViewSet: Kết hợpViewSetMixinvàGenericAPIView, tạo nền tảng choModelViewSet. - 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ớiquerysetvàserializer_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'})),
# # ]