1. 序列化器概述
在 Django REST Framework(DRF)中,序列化器(Serializer)用于将复杂的数据类型(如模型实例)转换为 JSON 格式,以便于 API 返回给客户端。此外,序列化器还可以用于验证请求数据。
2. 基本的 ModelSerializer 使用
- 在 models.py 中定义了一个 Department 模型,用来表示部门的信息。在这个模型中,我们包括了 full_name 字段(存储部门的完整名称),以及 level 字段(表示部门的层级)。
# models.py
from django.db import modelsclass Department(models.Model):# 部门的全名,使用 `CharField` 存储full_name = models.CharField(max_length=255)# 部门的层级,默认为 0level = models.IntegerField(default=0)def __str__(self):return self.full_name
ModelSerializer
是Serializer
的一个子类,专门用于将 Django 模型实例转化为 JSON 格式,且支持自动化字段映射。
例子:
from rest_framework import serializers
from .models import Departmentclass DepartmentSerializer(serializers.ModelSerializer):class Meta:model = Departmentfields = '__all__'
这里,DepartmentSerializer
会自动根据 Department
模型的字段生成相应的序列化字段。
3. 使用 SerializerMethodField 动态计算字段
SerializerMethodField
是 DRF 提供的一种特殊字段类型,用于动态计算某个字段的值。你可以定义一个方法,方法名称是 get_<field_name>
,该方法会自动被调用来计算字段的值。
示例:
假设 Department
模型有一个字段 full_name
,表示部门的全名(例如:“公司-技术-后端”),我们希望计算一个 level
字段,表示该部门的层级。
from rest_framework import serializersclass DepartmentSerializer(serializers.ModelSerializer):# level 字段会动态计算level = serializers.SerializerMethodField(read_only=True)class Meta:model = Departmentfields = '__all__'# 动态计算 level 字段def get_level(self, obj):full_name = obj.full_name# 按照 '-' 分割 full_namefull_name_split = full_name.split('-')# 计算层级:忽略第一个部分(例如“公司”)return len(full_name_split) - 1
在这个示例中:
level
字段是一个SerializerMethodField
,它不会直接从模型中读取,而是通过get_level
方法动态计算。get_level
方法接收obj
(即当前的Department
实例),根据full_name
字段来计算层级。full_name.split('-')
会将部门的全名拆分为多个部分,然后计算层级。
4. 使用自定义 __init__
方法动态控制字段
有时,我们可能需要根据外部条件来动态修改序列化器中的字段。例如,某些字段可能在某些情况下不需要序列化。我们可以通过重写 __init__
方法来实现这一点。
示例:
class DepartmentSerializer(serializers.ModelSerializer):level = serializers.SerializerMethodField(read_only=True)def __init__(self, *args, **kwargs):fields = kwargs.pop('fields', [])super().__init__(*args, **kwargs)if fields:# 删除未指定的字段allowed = set(fields)existing = set(self.fields)for field_name in existing - allowed:self.fields.pop(field_name)def get_level(self, obj):full_name = obj.full_namefull_name_split = full_name.split('-')return len(full_name_split) - 1class Meta:model = Departmentfields = '__all__'depth = 1read_only_fields = ('id',)
在上面的代码中:
__init__
方法接受一个fields
参数,该参数是一个字段列表,表示要包含的字段。- 如果
fields
参数不为空,它会从已有的字段中删除未指定的字段,从而控制序列化器返回的字段。
5. 实战案例:使用 SerializerMethodField 和自定义字段控制
背景:
假设我们要设计一个 API,返回部门的层级结构,并且根据不同的条件返回不同的字段。我们需要动态计算部门的层级,并且能够根据请求控制返回哪些字段。
模型:
# models.py
from django.db import modelsclass Department(models.Model):full_name = models.CharField(max_length=255)level = models.IntegerField(default=0)def __str__(self):return self.full_name
视图:
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Department
from .serializers import DepartmentSerializerclass DepartmentView(APIView):def get(self, request):# 假设我们根据参数决定返回哪些字段fields = request.query_params.getlist('fields', [])# 获取所有部门数据departments = Department.objects.all()# 使用序列化器返回数据serializer = DepartmentSerializer(departments, many=True, fields=fields)return Response(serializer.data, status=status.HTTP_200_OK)
URL 配置:
# urls.py
from django.urls import path
from .views import DepartmentViewurlpatterns = [path('departments/', DepartmentView.as_view(), name='departments-list'),
]
6. 测试:
假设我们有以下部门数据:
full_name | level |
---|---|
公司-技术-后端 | 2 |
公司-财务 | 1 |
公司-人力资源 | 1 |
请求 1:返回所有字段
GET /departments/
返回:
[{"full_name": "公司-技术-后端","level": 2},{"full_name": "公司-财务","level": 1},{"full_name": "公司-人力资源","level": 1}
]
请求 2:仅返回 full_name
和 level
字段
GET /departments/?fields=full_name&fields=level
返回:
[{"full_name": "公司-技术-后端","level": 2},{"full_name": "公司-财务","level": 1},{"full_name": "公司-人力资源","level": 1}
]
7. 总结
SerializerMethodField
:用来动态计算字段的值,可以根据模型实例的内容或请求参数来决定字段的值。get_<field_name>
方法:定义字段的计算逻辑。- 动态字段控制:通过在序列化器的
__init__
方法中动态修改字段来控制序列化器返回哪些字段。 - 实战案例:通过
fields
参数控制返回字段,并动态计算层级。
这个案例展示了如何在 Django REST Framework 中灵活地使用序列化器来动态计算和控制返回字段,适用于多种 API 场景。