1. Custom Serializer Fields
from rest_framework import serializers
class ProductSerializer(serializers.ModelSerializer):
category_name = serializers.SlugRelatedField(
source='category', slug_field='name', read_only=True
)
total_reviews = serializers.SerializerMethodField()
discount_price = serializers.SerializerMethodField()
class Meta:
model = Product
fields = ['id', 'name', 'price', 'category_name',
'total_reviews', 'discount_price']
def get_total_reviews(self, obj):
return obj.reviews.count()
def get_discount_price(self, obj):
if obj.discount_percent:
return obj.price * (1 - obj.discount_percent / 100)
return obj.price
2. Object-Level Validation
from rest_framework.validators import UniqueTogetherValidator
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
validators = [
UniqueTogetherValidator(
queryset=Order.objects.all(),
fields=['customer', 'order_number'],
)
]
def validate(self, attrs):
if attrs['start_date'] >= attrs['end_date']:
raise serializers.ValidationError(
'Ngày kết thúc phải sau ngày bắt đầu')
return attrs
3. Dynamic Serializers
class DynamicFieldsSerializer(serializers.ModelSerializer):
"""Cho phép chọn fields qua query params: ?fields=id,name"""
def __init__(self, *args, **kwargs):
fields = kwargs.pop('fields', None)
super().__init__(*args, **kwargs)
if fields is not None:
allowed = set(fields)
for field_name in set(self.fields) - allowed:
self.fields.pop(field_name)
class ProductSerializer(DynamicFieldsSerializer):
class Meta:
model = Product
fields = '__all__'
# Sử dụng
serializer = ProductSerializer(products, many=True, fields=['id', 'name', 'price'])
4. Performance Optimization
class ProductViewSet(viewsets.ModelViewSet):
serializer_class = ProductSerializer
def get_queryset(self):
return Product.objects.select_related(
'category', 'brand'
).prefetch_related(
'tags', 'images',
Prefetch('reviews', queryset=Review.objects.select_related('user'))
).annotate(
avg_rating=Avg('reviews__rating'),
review_count=Count('reviews'),
)
def get_serializer_class(self):
if self.action == 'list':
return ProductListSerializer
return ProductDetailSerializer
5. Writable Nested Serializers
class ProductSerializer(serializers.ModelSerializer):
images = ProductImageSerializer(many=True, required=False)
class Meta:
model = Product
fields = '__all__'
def create(self, validated_data):
images_data = validated_data.pop('images', [])
product = Product.objects.create(**validated_data)
for img in images_data:
ProductImage.objects.create(product=product, **img)
return product
def update(self, instance, validated_data):
images_data = validated_data.pop('images', None)
instance = super().update(instance, validated_data)
if images_data is not None:
instance.images.all().delete()
for img in images_data:
ProductImage.objects.create(product=instance, **img)
return instance
Next article: Versioning, Throttling & API Docs.