Django Rest Framework序列化器中to_representation的应用
1、嵌套序列化器中筛选列表数据
model
其中包含一个Project模型,另一个与之关联的Task模型
点击查看代码
class Project(models.Model):
name = models.CharField(max_length=200)
...
class Task(models.Model):
name = models.CharField(max_length=200)
project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True)
is_active = models.BooleanField(default=False)
...
serialize
class TaskSerializers(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('id', 'name', 'is_active')
class ProjectSerializer(serializers.ModelSerializer):
tasks = TaskSerializers(many=True)
class Meta:
model = Project
fields = ('id', 'name', 'tasks')
问题: 在上面嵌套的序列化中,检索到的是Project对应的所有Task,即使有些Task的is_active=False,但是我们希望只检索is_active=True的。
解决方案: 重写ListSerializers 中的to_represent(),对queryset进行过滤,同时在TaskSerializers中使用list_serializer_class = ActiveTaskSerializer
点击查看代码
class ActiveTaskSerializer(serializers.ListSerializer):
def to_representation(self, data):
data = data.filter(is_active=True)
super(ActiveTaskSerializer, self).to_representation(data)
class TaskSerializers(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('id', 'name', 'is_active')
list_serializer_class = ActiveTaskSerializer
2、移除返回数据中空的字段
问题:
点击查看代码
{
"meta": {
"title": null,
"name": "XYZ"
}
}
// 希望去掉序列化结果中为None的字段
{
"meta": {
"name": "XYZ"
}
}
解决方案: 定义NonNullModelSerializer,使序列化继承NonNullModelSerializer**
点击查看代码
class NonNullModelSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
result = super().to_representation(instance)
return OrderedDict(filter(lambda x: x[1] is not None, result.items()))
class ShipmentResponseSerializer(NonNullModelSerializer):
....
3、ChoiceField
点击查看代码
class Project(models.Model):
TYPE = [
(1, 'Person'),
(2, 'Team'),
]
type = models.PositiveSmallIntegerField(max_length=1, choices=TYPE, default=1)
name = models.CharField(max_length=200)
class ProjectSerializer(serializers.ModelSerializer):
type = serializers.CharField(source='get_type_display', read_only=True)
class Meta:
model = Project
fields = ['id', 'name', 'type']
上面序列化器我们可以使type字段显示值而不是数字
c = Project.objects.first()
ser = ProjectSerializer(instance=c)
print(ser.data)
{ 'id': 1,
'name': 'xxxx',
'type': 'Person',
# instead of 'type': '1'
}
问题: 但是对于POST / PUT,则会报错,并且希望在创建时type传递的是值而不是数字
data = {
'type': 'Team',
# instead of 'type': '2'
'name': 'xxx'
}
ser2 = ProjectSerializer(data=data)
ser2.is_valid(raise_exception=True)
instance = ser2.save()
# 错误
TypeError: Project() got an unexpected keyword argument 'get_type_display'
解决方案:
class MappedChoiceField(serializers.ChoiceField):
def to_representation(self, obj):
if obj == '' and self.allow_blank:
return ''
return self._choices[obj]
def to_internal_value(self, data):
# To support inserts with the value
if data == '' and self.allow_blank:
return ''
for key, val in self._choices.items():
if val == data:
return key
self.fail('invalid_choice', input=data)
class ProjectSerializer(serializers.ModelSerializer):
# type = serializers.CharField(source='get_type_display')
type = MappedChoiceField(choices=[
(1, 'Person'),
(2, 'Team'),
])
class Meta:
model = Project
fields = ['id', 'name', 'type']
#1、 获取数据
c = Project.objects.first()
ser = ProjectSerializer(instance=c)
print(ser.data)
# {'id': 1, 'name': 'xxxx', 'type': 'Person'}
# 2、创建数据
data = {
'type': 'Team',
'name': 'xxx'
}
ser2 = ProjectSerializer(data=data)
ser2.is_valid(raise_exception=True)
instance = ser2.save()
print(instance)
# Project object (75)
浙公网安备 33010602011771号