在创建Django模型时,出现了最大递归深度超过的错误。

11

我在Django模型中遇到一个奇怪的问题,虽然已经修复了,但是不明白发生了什么。

以下是这些模型:

class Player(models.Model):
    facebook_name = models.CharField(max_length=100)
    nickname = models.CharField(max_length=40, blank=True)

    def __unicode__(self):
        return self.nickname if self.nickname else self.facebook_name


class Team(models.Model):
    name = models.CharField(max_length=50, blank=True)
    players = models.ManyToManyField(Player)

    def __unicode__(self):
        name = '(' + self.name + ') ' if self.name else ''
        return name + ", ".join([unicode(player) for player in self.players.all()])
每当我创建一个新的(空的)Team对象并想要从中获取players时,我会得到一个RuntimeError: maximum recursion depth exceeded错误。 例如:
>>> team = Team()
>>> team.players
    Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/walkman/Projects/fociadmin/venv/lib/python2.7/site-packages/django/db/models/fields/related.py", line 897, in __get__
    through=self.field.rel.through,
  File "/Users/walkman/Projects/fociadmin/venv/lib/python2.7/site-packages/django/db/models/fields/related.py", line 586, in __init__
    (instance, source_field_name))
  File "/Users/walkman/Projects/fociadmin/venv/lib/python2.7/site-packages/django/db/models/base.py", line 421, in __repr__
    u = six.text_type(self)
  File "/Users/walkman/Projects/fociadmin/fociadmin/models.py", line 69, in __unicode__
    return name + ", ".join([unicode(player) for player in self.players.all()])
  File "/Users/walkman/Projects/fociadmin/venv/lib/python2.7/site-packages/django/db/models/fields/related.py", line 897, in __get__
    through=self.field.rel.through,
  File "/Users/walkman/Projects/fociadmin/venv/lib/python2.7/site-packages/django/db/models/fields/related.py", line 586, in __init__
    (instance, source_field_name))
  File "/Users/walkman/Projects/fociadmin/venv/lib/python2.7/site-packages/django/db/models/base.py", line 421, in __repr__
    u = six.text_type(self)
  File "/Users/walkman/Projects/fociadmin/fociadmin/models.py", line 69, in __unicode__
    return name + ", ".join([unicode(player) for player in self.players.all()])
...

为什么会发生这种情况?我通过检查pk并仅在此时生成名称来解决了它,但我认为它应该只返回名称,因为", ".join...将成为空列表。相反,发生了一些我不理解的递归。

1个回答

21
问题在于在 Team 实例尚未保存到数据库时,无法访问 team.players 字段。尝试这样做将引发 ValueError
但是,在尝试引发此 ValueError 时,代码将尝试获取您的 team 对象的表示形式,这将间接调用 unicode(team)。这将尝试访问 self.players,并在第一个 ValueError 抛出之前尝试引发另一个 ValueError。这将继续进行,直到达到最大递归深度,但仍未抛出任何 ValueError。因此,您只会看到 RuntimeError
如果您执行以下操作中的任何一项,情况将(应该)相同:
>>> team
>>> repr(team)
>>> unicode(team)

2
在实例保存之前访问多对多关系将会引发ValueError并导致所描述的情况。如果该实例已保存(并具有主键),则关系将是一个空列表。 - AndrewS
@AndrewS 你是对的,我更新了我的答案。谢谢你的注意! - knbk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接