You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:02:46