DRF 模型序列化器 #

一、什么是ModelSerializer #

1.1 ModelSerializer简介 #

ModelSerializer是Serializer的子类,它能够自动根据模型创建字段,大大简化了序列化器的开发。

text
Serializer vs ModelSerializer
┌─────────────────────────────────────┐
│           Serializer                │
│  - 手动定义所有字段                  │
│  - 手动实现create/update方法        │
│  - 更灵活但代码量大                 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│         ModelSerializer             │
│  - 自动从模型生成字段                │
│  - 自动实现create/update方法        │
│  - 简洁高效                         │
└─────────────────────────────────────┘

1.2 基本用法 #

python
from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

二、Meta类配置 #

2.1 指定模型 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article

2.2 指定字段 #

包含所有字段:

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

指定特定字段:

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'author']

排除特定字段:

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        exclude = ['created_at', 'updated_at']

2.3 只读字段 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'
        read_only_fields = ['id', 'created_at', 'updated_at']

2.4 只写字段 #

python
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'password']
        extra_kwargs = {
            'password': {'write_only': True}
        }

2.5 深度控制 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'
        depth = 1  # 嵌套序列化深度

三、字段自定义 #

3.1 覆盖字段 #

python
class ArticleSerializer(serializers.ModelSerializer):
    title = serializers.CharField(max_length=200, min_length=5)
    author = serializers.CharField(source='author.username', read_only=True)

    class Meta:
        model = Article
        fields = '__all__'

3.2 添加额外字段 #

python
class ArticleSerializer(serializers.ModelSerializer):
    comment_count = serializers.IntegerField(read_only=True)
    author_name = serializers.CharField(source='author.username', read_only=True)

    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'author', 'author_name', 'comment_count']

3.3 SerializerMethodField #

python
class ArticleSerializer(serializers.ModelSerializer):
    comment_count = serializers.SerializerMethodField()
    is_recent = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = '__all__'

    def get_comment_count(self, obj):
        return obj.comments.count()

    def get_is_recent(self, obj):
        from django.utils import timezone
        from datetime import timedelta
        return obj.created_at > timezone.now() - timedelta(days=7)

3.4 SlugRelatedField #

python
class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.SlugRelatedField(
        slug_field='name',
        queryset=Category.objects.all()
    )

    class Meta:
        model = Article
        fields = '__all__'

3.5 StringRelatedField #

python
class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.StringRelatedField()

    class Meta:
        model = Article
        fields = '__all__'

四、关系字段处理 #

4.1 ForeignKey关系 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

默认输出:

json
{
    "id": 1,
    "title": "文章标题",
    "category": 1
}

4.2 嵌套序列化 #

python
class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ['id', 'name']

class ArticleSerializer(serializers.ModelSerializer):
    category = CategorySerializer()

    class Meta:
        model = Article
        fields = '__all__'

输出:

json
{
    "id": 1,
    "title": "文章标题",
    "category": {
        "id": 1,
        "name": "技术"
    }
}

4.3 反向关系 #

python
class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

class ArticleSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(many=True, read_only=True)

    class Meta:
        model = Article
        fields = '__all__'

4.4 ManyToMany关系 #

python
class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ['id', 'name']

class ArticleSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True, read_only=True)

    class Meta:
        model = Article
        fields = '__all__'

五、数据验证 #

5.1 字段级验证 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

    def validate_title(self, value):
        if len(value) < 5:
            raise serializers.ValidationError('标题至少需要5个字符')
        if '敏感词' in value:
            raise serializers.ValidationError('标题包含敏感词')
        return value

5.2 对象级验证 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

    def validate(self, data):
        if data.get('is_published') and not data.get('content'):
            raise serializers.ValidationError({
                'content': '发布文章必须有内容'
            })
        return data

5.3 唯一性验证 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'
        validators = [
            serializers.UniqueTogetherValidator(
                queryset=Article.objects.all(),
                fields=['title', 'author'],
                message='该作者已存在相同标题的文章'
            )
        ]

5.4 自定义验证器 #

python
from rest_framework.validators import ValidationError

def validate_title(value):
    forbidden_words = ['广告', '推销']
    for word in forbidden_words:
        if word in value:
            raise ValidationError(f'标题不能包含"{word}"')
    return value

class ArticleSerializer(serializers.ModelSerializer):
    title = serializers.CharField(validators=[validate_title])

    class Meta:
        model = Article
        fields = '__all__'

六、重写create和update #

6.1 重写create方法 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

    def create(self, validated_data):
        tags_data = validated_data.pop('tags', [])
        article = Article.objects.create(**validated_data)
        for tag in tags_data:
            article.tags.add(tag)
        return article

6.2 重写update方法 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

    def update(self, instance, validated_data):
        tags_data = validated_data.pop('tags', None)
        
        instance.title = validated_data.get('title', instance.title)
        instance.content = validated_data.get('content', instance.content)
        instance.save()
        
        if tags_data is not None:
            instance.tags.set(tags_data)
        
        return instance

6.3 处理嵌套创建 #

python
class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

class ArticleSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(many=True)

    class Meta:
        model = Article
        fields = '__all__'

    def create(self, validated_data):
        comments_data = validated_data.pop('comments')
        article = Article.objects.create(**validated_data)
        for comment_data in comments_data:
            Comment.objects.create(article=article, **comment_data)
        return article

七、extra_kwargs配置 #

7.1 基本用法 #

python
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'
        extra_kwargs = {
            'title': {'required': True, 'min_length': 5},
            'content': {'required': False},
            'author': {'read_only': True},
        }

7.2 常用配置 #

python
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'password']
        extra_kwargs = {
            'password': {
                'write_only': True,
                'style': {'input_type': 'password'}
            },
            'email': {
                'required': True,
                'error_messages': {
                    'required': '邮箱不能为空',
                    'invalid': '请输入有效的邮箱地址'
                }
            }
        }

八、模型属性映射 #

8.1 字段类型映射 #

模型字段 序列化器字段
AutoField IntegerField(read_only=True)
CharField CharField
TextField CharField
BooleanField BooleanField
IntegerField IntegerField
FloatField FloatField
DecimalField DecimalField
DateTimeField DateTimeField
DateField DateField
EmailField EmailField
URLField URLField
ForeignKey PrimaryKeyRelatedField
ManyToManyField ManyToManyField

8.2 约束映射 #

模型约束 序列化器约束
null=True allow_null=True
blank=True required=False
default=value default=value
choices=… ChoiceField
unique=True UniqueValidator

九、实际应用示例 #

9.1 用户注册 #

python
class UserRegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    password_confirm = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['username', 'email', 'password', 'password_confirm']

    def validate(self, data):
        if data['password'] != data['password_confirm']:
            raise serializers.ValidationError('两次密码不一致')
        return data

    def create(self, validated_data):
        validated_data.pop('password_confirm')
        user = User.objects.create_user(**validated_data)
        return user

9.2 文章创建 #

python
class ArticleCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['title', 'content', 'category', 'tags']
        extra_kwargs = {
            'title': {'min_length': 5, 'max_length': 200},
            'content': {'min_length': 10},
        }

    def create(self, validated_data):
        request = self.context.get('request')
        validated_data['author'] = request.user
        return super().create(validated_data)

9.3 文章列表 #

python
class ArticleListSerializer(serializers.ModelSerializer):
    author_name = serializers.CharField(source='author.username')
    category_name = serializers.CharField(source='category.name')
    comment_count = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = ['id', 'title', 'author_name', 'category_name', 
                  'comment_count', 'created_at', 'is_published']

    def get_comment_count(self, obj):
        return obj.comments.count()

9.4 文章详情 #

python
class ArticleDetailSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    category = CategorySerializer(read_only=True)
    tags = TagSerializer(many=True, read_only=True)
    comments = CommentSerializer(many=True, read_only=True)

    class Meta:
        model = Article
        fields = '__all__'

十、多序列化器 #

10.1 不同场景使用不同序列化器 #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()

    def get_serializer_class(self):
        if self.action == 'list':
            return ArticleListSerializer
        elif self.action == 'create':
            return ArticleCreateSerializer
        return ArticleDetailSerializer

10.2 序列化器继承 #

python
class BaseArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content']

class ArticleListSerializer(BaseArticleSerializer):
    author_name = serializers.CharField(source='author.username')

    class Meta(BaseArticleSerializer.Meta):
        fields = BaseArticleSerializer.Meta.fields + ['author_name', 'created_at']

class ArticleDetailSerializer(BaseArticleSerializer):
    comments = CommentSerializer(many=True, read_only=True)

    class Meta(BaseArticleSerializer.Meta):
        fields = BaseArticleSerializer.Meta.fields + ['comments', 'author', 'created_at']

十一、总结 #

本章学习了ModelSerializer的核心用法:

  • 基本配置:Meta类的各种配置选项
  • 字段自定义:覆盖和添加字段
  • 关系处理:处理各种模型关系
  • 数据验证:字段级和对象级验证
  • 方法重写:自定义create和update逻辑

ModelSerializer大大简化了序列化器的开发,让我们继续学习字段验证的更多细节!

最后更新:2026-03-28