掌握DRF的serializer_class:高效API开发
在 Django REST Framework(DRF)中,serializer_class
是 GenericAPIView 或其子类视图 中用来指定序列化器(Serializer)的属性。
- 它的主要作用是告诉视图在进行数据序列化(输出)和反序列化(接收请求数据并验证)时使用哪个 Serializer 类。
1️⃣ 基本用法
from rest_framework import serializers, generics
from myapp.models import Book# 1. 定义 Serializer
class BookSerializer(serializers.ModelSerializer):class Meta:model = Bookfields = ['id', 'title', 'author', 'published_date']# 2. 在视图中使用 serializer_class
class BookListCreateView(generics.ListCreateAPIView):queryset = Book.objects.all()serializer_class = BookSerializer # 指定序列化器
解释:
serializer_class = BookSerializer
:告诉 DRF 视图使用BookSerializer
来序列化和反序列化数据。- 当客户端发送 GET 请求时,DRF 会使用
BookSerializer
将查询集queryset
转换为 JSON。 - 当客户端发送 POST 请求时,DRF 会使用
BookSerializer
验证并保存数据。
2️⃣ 与 get_serializer_class()
的关系
serializer_class
是一个 静态属性,如果你需要根据不同情况动态返回不同的 Serializer,可以重写 get_serializer_class()
方法。
class BookView(generics.GenericAPIView):queryset = Book.objects.all()def get_serializer_class(self):if self.request.method == 'GET':from myapp.serializers import BookListSerializerreturn BookListSerializerreturn BookSerializer
-
这样可以针对不同请求方法使用不同的序列化器,比如:
- GET 请求使用
BookListSerializer
(只显示部分字段) - POST 请求使用
BookSerializer
(包含完整字段验证)
- GET 请求使用
3️⃣ 用在 ModelViewSet
或 ViewSet
中
在 ViewSet
中同样可以使用 serializer_class
:
from rest_framework import viewsetsclass BookViewSet(viewsets.ModelViewSet):queryset = Book.objects.all()serializer_class = BookSerializer
- DRF 会根据不同的动作(list/retrieve/create/update)自动使用这个 Serializer。
- 同样可以通过重写
get_serializer_class()
来针对动作指定不同 Serializer:
class BookViewSet(viewsets.ModelViewSet):queryset = Book.objects.all()def get_serializer_class(self):if self.action == 'list':return BookListSerializerreturn BookSerializer
4️⃣ 总结
-
serializer_class
是静态属性:指定视图使用哪个 Serializer。 -
get_serializer_class()
是动态方法:可根据请求或动作返回不同的 Serializer。 -
主要用于:
- 数据输出序列化(queryset → JSON)
- 数据输入验证(JSON → 模型实例)
ModelSerializer 详细用法
基本用法
1. 最简单的 ModelSerializer
from rest_framework import serializers
from .models import User, Postclass UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = '__all__' # 包含所有字段
2. 指定特定字段
class UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ['id', 'username', 'email', 'date_joined']
3. 排除特定字段
class UserSerializer(serializers.ModelSerializer):class Meta:model = Userexclude = ['password', 'is_superuser'] # 排除敏感字段
高级用法
1. 添加额外字段
class UserSerializer(serializers.ModelSerializer):# 计算字段full_name = serializers.SerializerMethodField()# 关联字段post_count = serializers.IntegerField(source='posts.count', read_only=True)class Meta:model = Userfields = ['id', 'username', 'email', 'full_name', 'post_count']def get_full_name(self, obj):return f"{obj.first_name} {obj.last_name}"
2. 嵌套序列化
class CommentSerializer(serializers.ModelSerializer):class Meta:model = Commentfields = ['id', 'content', 'created_at']class PostSerializer(serializers.ModelSerializer):# 嵌套序列化author = UserSerializer(read_only=True)comments = CommentSerializer(many=True, read_only=True)class Meta:model = Postfields = ['id', 'title', 'content', 'author', 'comments', 'created_at']
3. 字段级别自定义
class UserSerializer(serializers.ModelSerializer):email = serializers.EmailField(required=False)username = serializers.CharField(max_length=50)class Meta:model = Userfields = ['id', 'username', 'email', 'date_joined']
4. 只读字段
class UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ['id', 'username', 'email', 'date_joined']read_only_fields = ['id', 'date_joined'] # 这些字段只读
验证和钩子方法
1. 字段级别验证
class UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ['username', 'email', 'age']def validate_username(self, value):if 'admin' in value.lower():raise serializers.ValidationError("用户名不能包含 'admin'")return valuedef validate(self, data):if data['age'] < 18 and data['username']:raise serializers.ValidationError("未成年人需要特殊处理")return data
2. 自定义创建和更新方法
class UserSerializer(serializers.ModelSerializer):class Meta:model = Userfields = ['username', 'email', 'password']extra_kwargs = {'password': {'write_only': True}}def create(self, validated_data):# 对密码进行加密password = validated_data.pop('password')user = User(**validated_data)user.set_password(password)user.save()return userdef update(self, instance, validated_data):# 处理密码更新if 'password' in validated_data:password = validated_data.pop('password')instance.set_password(password)return super().update(instance, validated_data)
深度控制 (depth)
class PostSerializer(serializers.ModelSerializer):class Meta:model = Postfields = '__all__'depth = 1 # 自动嵌套一层关联对象
完整示例
models.py
from django.db import modelsclass User(models.Model):username = models.CharField(max_length=150, unique=True)email = models.EmailField(unique=True)password = models.CharField(max_length=128)first_name = models.CharField(max_length=30, blank=True)last_name = models.CharField(max_length=30, blank=True)date_joined = models.DateTimeField(auto_now_add=True)is_active = models.BooleanField(default=True)class Post(models.Model):title = models.CharField(max_length=200)content = models.TextField()author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)is_published = models.BooleanField(default=False)
serializers.py
from rest_framework import serializers
from .models import User, Postclass UserSerializer(serializers.ModelSerializer):post_count = serializers.SerializerMethodField()full_name = serializers.SerializerMethodField()class Meta:model = Userfields = ['id', 'username', 'email', 'full_name', 'post_count', 'date_joined']read_only_fields = ['id', 'date_joined']def get_post_count(self, obj):return obj.posts.count()def get_full_name(self, obj):return f"{obj.first_name} {obj.last_name}".strip()class PostSerializer(serializers.ModelSerializer):author_name = serializers.CharField(source='author.username', read_only=True)author_email = serializers.EmailField(source='author.email', read_only=True)class Meta:model = Postfields = ['id', 'title', 'content', 'author', 'author_name', 'author_email', 'created_at', 'updated_at', 'is_published']read_only_fields = ['id', 'created_at', 'updated_at']def validate_title(self, value):if len(value) < 5:raise serializers.ValidationError("标题至少需要5个字符")return value
views.py
from rest_framework import viewsets
from .models import User, Post
from .serializers import UserSerializer, PostSerializerclass UserViewSet(viewsets.ModelViewSet):queryset = User.objects.all()serializer_class = UserSerializerclass PostViewSet(viewsets.ModelViewSet):queryset = Post.objects.all()serializer_class = PostSerializerdef perform_create(self, serializer):# 自动设置当前用户为作者serializer.save(author=self.request.user)
常用 Meta 选项
选项 | 描述 | 示例 |
---|---|---|
model | 关联的Django模型 | model = User |
fields | 包含的字段列表 | fields = ['id', 'name'] |
exclude | 排除的字段列表 | exclude = ['password'] |
read_only_fields | 只读字段列表 | read_only_fields = ['id'] |
extra_kwargs | 字段额外参数 | extra_kwargs = {'password': {'write_only': True}} |
depth | 关联对象嵌套深度 | depth = 1 |
最佳实践
- 不要使用
fields = '__all__'
:明确指定字段,避免意外暴露敏感数据 - 处理密码字段:使用
write_only=True
和自定义创建/更新方法 - 验证用户输入:添加字段级别和对象级别的验证
- 合理使用嵌套:避免过度嵌套导致性能问题
- 使用
read_only_fields
:保护不应该通过API修改的字段
这样使用 ModelSerializer
可以大大提高开发效率,同时保持代码的清晰和可维护性。