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

Django Rest Framework嵌套序列化器返回响应时出现AttributeError错误求助

Django Rest Framework嵌套序列化器返回响应时出现AttributeError错误求助

兄弟,我一眼就瞅出问题所在了:当DRF返回响应的时候,它正尝试用LineupPlayerSerializer去序列化Player实例,但positionOnPitch是中间表LineupPlayer的字段,Player模型里根本没这个属性,所以才会报这个错!

为啥会出现这种乌龙?因为你的Lineup模型里的players是关联到Player的ManyToManyField,而LineupSerializer里的players字段直接用了LineupPlayerSerializer——默认情况下DRF会从Lineup.players取Player对象,而不是中间表LineupPlayer的对象,这就完全对不上号了!

给你几个具体的修复步骤,按顺序来:

1. 先修正LineupPlayer模型的关联名称

你给lineup字段设的related_name是lineup,这名字太容易和模型本身混淆了,改成更清晰的:

class LineupPlayer(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # 把related_name改成lineup_players,这样Lineup实例能通过这个属性直接访问中间表对象
    lineup = models.ForeignKey(Lineup, on_delete=models.CASCADE, related_name='lineup_players')
    player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='player_lineups')
    positionOnPitch = models.PositiveSmallIntegerField()

    # 其他代码保持不变

2. 修改LineupSerializer,让它序列化中间表对象

把LineupSerializer里的players字段指向中间表的关联,而不是原来的ManyToMany关联:

class LineupSerializer(serializers.ModelSerializer):
    # 用source指定从lineup_players(中间表关联)取数据,这样序列化的是LineupPlayer实例
    players = LineupPlayerSerializer(many=True, source='lineup_players')

    class Meta:
        model = Lineup
        fields = ['id', 'formation', 'players']

    # 这里可以优化下create方法,用save更规范
    def create(self, validated_data):
        try:
            players_data = validated_data.pop('players')
            lineup = Lineup.objects.create(**validated_data)

            for player_data in players_data:
                LineupPlayerSerializer(data={**player_data, 'lineup': lineup}).save()
            
            return lineup
        except Exception as e:
            print(f"Error: {e}")
            raise e

3. 确认LineupPlayerSerializer的字段正确性

你的LineupPlayerSerializer本身没问题,positionOnPitch是LineupPlayer模型的字段,不需要额外指定source,保持原样就行:

class LineupPlayerSerializer(serializers.ModelSerializer):
    id = serializers.UUIDField(write_only=True)
    name = serializers.CharField(source='player.name', read_only=True)
    positionType = serializers.CharField(source='player.positionType.name', read_only=True)
    alternativePositions = serializers.CharField(source='player.alternativePositions.name', read_only=True, required=False, allow_blank=True)
    shirtNumber = serializers.IntegerField(source='player.shirtNumber', read_only=True, required=False, allow_null=True)
    positionOnPitch = serializers.IntegerField(required=True)

    class Meta:
        model = LineupPlayer
        fields = ['id', 'positionType', 'alternativePositions', 'name', 'shirtNumber', 'positionOnPitch']

    # create方法保持不变

为啥之前加write_only=True能临时解决?

因为加了这个参数后,DRF返回响应时不会去序列化这个字段,自然不会傻呵呵去Player实例上找它,但这只是规避问题,不是根本解决办法。

按上面的步骤改完再测试,应该就能正常返回包含positionOnPitch的响应了!

备注:内容来源于stack exchange,提问作者Robo Gore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 16:53:07