如何在DRF序列化器中用同一Key写入关联ID并读取序列化对象
实现同一
city字段兼具写入UUID与返回嵌套数据的方案 方案1:重写序列化器核心处理方法
移除原有的city_id字段,通过重写to_internal_value(处理请求输入)和to_representation(处理响应输出)方法,让city字段同时承担两种功能:
from rest_framework.serializers import ModelSerializer from rest_framework.exceptions import ValidationError from .models import Street, City from rest_framework.fields import UUIDField class StreetSerializer(ModelSerializer): class Meta: model = Street fields = ('id', 'city', 'name') def to_internal_value(self, data): # 处理请求输入:将传入的city UUID转为对应City实例 internal_data = super().to_internal_value(data) city_uuid = data.get('city') if city_uuid: # 验证UUID格式合法性 uuid_field = UUIDField() try: validated_uuid = uuid_field.to_internal_value(city_uuid) except ValidationError: raise ValidationError({'city': '请传入有效的城市UUID'}) # 验证城市是否存在 try: internal_data['city'] = City.objects.get(id=validated_uuid) except City.DoesNotExist: raise ValidationError({'city': '指定的城市不存在'}) return internal_data def to_representation(self, instance): # 处理响应输出:将City实例序列化为嵌套字典 representation = super().to_representation(instance) from .serializers import CitySerializer # 避免循环导入,可根据实际调整导入位置 representation['city'] = CitySerializer(instance.city).data return representation
方案2:自定义可复用复合字段
如果需要在多个序列化器中复用该逻辑,可以自定义字段类,封装UUID验证、实例查询和嵌套序列化逻辑:
from rest_framework import serializers from rest_framework.fields import UUIDField from .models import City class CityUUIDNestedField(serializers.Field): def __init__(self, nested_serializer, **kwargs): self.nested_serializer = nested_serializer super().__init__(**kwargs) def to_internal_value(self, data): # 验证UUID格式 try: validated_uuid = UUIDField().to_internal_value(data) except serializers.ValidationError: raise serializers.ValidationError('必须传入有效的UUID字符串') # 验证并返回对应City实例 try: return City.objects.get(id=validated_uuid) except City.DoesNotExist: raise serializers.ValidationError('指定的城市不存在') def to_representation(self, value): # 使用传入的嵌套序列化器输出数据 return self.nested_serializer(value).data # 在StreetSerializer中使用自定义字段 class StreetSerializer(ModelSerializer): city = CityUUIDNestedField(nested_serializer=CitySerializer) class Meta: model = Street fields = ('id', 'city', 'name')
效果验证
- 创建请求发送的JSON:
{"name": "Elm", "city": "cc96aabf-a6e9-48fa-a3b4-6c487b8f3366"}
- 201响应返回内容:
{"id": "街道的UUID", "name": "Elm", "city": {"name": "Dallas"}}
内容的提问来源于stack exchange,提问作者Vassily
相关产品推荐
相关产品推荐

