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