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

Django模型保存时修改ManyToManyField触发递归错误求助

Django保存Profile模型时递归错误的解决方法

问题根源

你的代码触发RecursionError是因为在save方法内部再次调用了self.save(),这会导致无限递归调用,直到超出Python的递归深度限制。此外,硬写好友数量的逻辑也不够灵活,后续修改类型对应的人数时需要改动代码。

解决方案

  1. 移除递归调用:修改ManyToManyField的关联关系不需要额外调用模型的save()方法,Django会自动处理关联表的更新,直接调用父类的save()即可。
  2. 动态获取最大好友数:用字典存储各Profile类型对应的最大好友数,避免硬编码,提升代码可维护性。

修正后的完整代码

# 直接存储各类型允许的最大好友数,逻辑更直观
MAX_FRIENDS_FOR_TYPE = {"X": 10, "Y": 20}

class ProfileType(models.TextChoices):
    X = "X", "x"
    Y = "Y", "y"
    # 原代码默认值为ProfileType.BASIC,但未定义,这里补充或调整为已有类型
    BASIC = "X", "x"

class Profile(models.Model):
    type = models.TextField(choices=ProfileType.choices, default=ProfileType.BASIC, max_length=1)
    friends = models.ManyToManyField(User, blank=True, related_name="friends")
    __currently_type = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__currently_type = self.type

    def save(self, *args, **kwargs) -> None:
        # 检查Profile类型是否降级(新类型允许的好友数更少)
        if self.type != self.__currently_type:
            old_max = MAX_FRIENDS_FOR_TYPE[self.__currently_type]
            new_max = MAX_FRIENDS_FOR_TYPE[self.type]
            if new_max < old_max:
                # 获取超出新上限的好友列表
                excess_friends = self.friends.all()[new_max:]
                if excess_friends.exists():
                    self.friends.remove(*excess_friends)
        
        # 调用父类方法保存模型本身的字段更新
        super().save(*args, **kwargs)
        # 更新类型缓存,用于下次保存时对比
        self.__currently_type = self.type

关键修改说明

  • 替换POWER_OF_PROFILE_TYPE为MAX_FRIENDS_FOR_TYPE,直接映射类型与最大好友数,逻辑更清晰
  • 删除了引发递归的self.save()调用
  • 修正了原代码中未定义的type_of_profile属性,直接使用self.type
  • 增加excess_friends.exists()判断,避免对空列表执行无意义的移除操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 21:23:22