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

Django Rest Framework自定义字段在create时未出现在attrs字典的问题

问题原因

你用的SerializerMethodField是只读字段,DRF只会在序列化(返回查询结果)时调用对应的get_teams方法生成数据,反序列化(处理POST请求)时会直接忽略这个字段,所以它不会被加入到validated_data(也就是validate方法里的attrs)中,自然没法做必填验证。

解决方案

把teams字段改成兼具读写能力的字段,用DictField(因为你的teams是字典结构),然后重写它的to_representation方法来实现原有的查询返回逻辑。这样POST时它会被正常解析到validated_data,GET时会返回你需要的自定义结构。

修改后的完整代码:

class MatchDaySerializer(serializers.ModelSerializer):
    # Validate if teams field exists in POST data
    def validate(self, attrs):
        if not "teams" in attrs:
            raise serializers.ValidationError({"teams": "This field is required"})
        # 可额外添加teams结构验证,比如检查是否包含blue/orange/colors键等
        return attrs

    # Serializer Fields
    matches = serializers.SerializerMethodField()
    # 替换SerializerMethodField为DictField,设置必填,重写序列化逻辑
    teams = serializers.DictField(required=True)

    class Meta:
        model = MatchDay
        fields = [
            'id',
            'date',
            'matches',
            'teams',
        ]

    # Returns match counter
    def get_matches(self, obj):
        if not hasattr(obj, 'id') or not isinstance(obj, MatchDay):
            return None
        return obj.match_counter

    # 重写teams字段的序列化方法,替代原来的get_teams
    def to_representation(self, instance):
        representation = super().to_representation(instance)
        # 原get_teams的逻辑移到这里
        tickets_dict = MatchDayTicket.objects.filter(matchday=instance).values('player_id', 'team')

        teams_dict = {
            "blue": [],
            "orange": [],
            "colors": [],
        }

        for ticket in tickets_dict:
            team = ticket.pop('team')
            if team in teams_dict:
                teams_dict[team].append(ticket)
        
        representation['teams'] = teams_dict
        return representation

    def create(self, validated_data):
        # 现在可以直接从validated_data拿teams数据,不用再取initial_data
        teams_data = validated_data.pop('teams')
        matchday = MatchDay.objects.create(**validated_data)

        for team, players in teams_data.items():
            for player_data in players:
                player = Player.objects.get(id=player_data['id'])
                MatchDayTicket.objects.create(matchday=matchday, player=player, team=team)
        return matchday
额外说明
  • 如果你的teams结构有特定格式要求,可以在validate方法里进一步验证,比如检查每个team对应的player列表是否包含有效的id,避免后续查询Player时报错。
  • 这种方式让同一个字段在读写阶段分别执行不同逻辑,既满足POST时的必填验证和数据接收,又保留了GET时的自定义返回结构。

内容的提问来源于stack exchange,提问作者Put3k

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:53:15