Django REST Framework JSON反序列化验证失败问题求助
问题分析与解决方案
错误原因
你当前的序列化器设计逻辑完全错误:
GameSerializer中错误地将white、white_rating、white_stars三个字段都绑定了PlayersSerializer。DRF 会因此认为输入数据中需要单独存在这三个字段,且每个字段都要符合PlayersSerializer的数据结构,但实际你的 JSON 数据里这些值都嵌套在players.white下,DRF 找不到对应字段,所以抛出「字段必填」的错误。PlayersSerializer的设计方向有误,它试图一次性提取三个字段,但却被绑定到单个模型字段上,完全不符合 DRF 的序列化器工作逻辑。
修复方案
下面提供两种可行的修复方式,你可以根据需求选择:
方式一:重写 GameSerializer 的反序列化逻辑
直接在 GameSerializer 中处理原始 JSON 结构的转换,同时自动完成 User 实例的创建或获取:
from rest_framework import serializers from .models import User, Game class GameSerializer(serializers.ModelSerializer): class Meta: model = Game fields = ["id", "white", "white_rating", "white_stars"] def to_internal_value(self, data): # 从原始JSON中提取所需数据 game_id = data.get("id") white_player = data.get("players", {}).get("white", {}) white_user = white_player.get("user", {}) white_rating = white_player.get("rating") white_stars = white_player.get("stars") # 验证核心字段是否存在 validation_errors = {} if not game_id: validation_errors["id"] = "该字段必填" if not white_user.get("id"): validation_errors["white"] = "玩家ID必填" if white_rating is None: validation_errors["white_rating"] = "该字段必填" if white_stars is None: validation_errors["white_stars"] = "该字段必填" if validation_errors: raise serializers.ValidationError(validation_errors) # 自动创建或获取User实例(避免重复创建) user, _ = User.objects.get_or_create( id=white_user["id"], defaults={"name": white_user.get("name", "")} ) # 返回符合Game模型要求的结构化数据 return { "id": game_id, "white": user, "white_rating": white_rating, "white_stars": white_stars }
方式二:使用嵌套序列化器拆分逻辑
通过嵌套序列化器清晰拆分不同层级的数据处理,更符合 DRF 的最佳实践:
from rest_framework import serializers from .models import User, Game # 处理User模型的序列化/反序列化 class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["id", "name"] # 处理单个玩家(white/black)的数据结构 class PlayerSerializer(serializers.Serializer): user = UserSerializer() rating = serializers.IntegerField() stars = serializers.IntegerField() # 处理Game模型的序列化/反序列化 class GameSerializer(serializers.ModelSerializer): # 声明players字段的结构 players = serializers.DictField(child=PlayerSerializer()) class Meta: model = Game fields = ["id", "players"] def create(self, validated_data): # 从验证后的数据中提取players信息 players_data = validated_data.pop("players") white_data = players_data["white"] # 提取并创建/获取User实例 user_data = white_data.pop("user") user, _ = User.objects.get_or_create(**user_data) # 创建Game实例 return Game.objects.create( id=validated_data["id"], white=user, white_rating=white_data["rating"], white_stars=white_data["stars"] )
视图层调用注意
确保视图中传入的是完整的原始 JSON 数据,示例:
# 假设你已经获取到API返回的JSON数据并存入api_data变量 serializer = GameSerializer(data=api_data) if serializer.is_valid(): game_instance = serializer.save() # 后续逻辑 else: print(serializer.errors)
内容的提问来源于stack exchange,提问作者Gribouille
相关产品推荐
相关产品推荐

