11

I have this strange problem with one of my Django models and I was able to fix it but don't understand what is happening.

These are the models:

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()])

Whenever I make a new (empty) Team object and want to get players from it, I got a RuntimeError: maximum recursion depth exceeded. For example:

>>> 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()])
...

Why is this happening? I was able to fix it by checking for pk and only generate the name then, but what I think it should work the way is returning only the name because ", ".join... would be an empty list. Instead, some recursion occurs which I don't understand.

1 Answer 1

21
+50

The problem is that you can't access the team.players field when the Team instance is not yet saved to the database. Trying to do this will raise a ValueError.

However, while trying to raise this ValueError, the code will try to get a representation of your team object which will indirectly call unicode(team). This will try to access self.players, which will try to raise another ValueError before the first one is raised. This goes on until the maximum recursion depth is reached, but there is still no ValueError thrown. Therefore, you'll only see the RuntimeError.

The same would (should?) happen if you did either of the following:

>>> team
>>> repr(team)
>>> unicode(team)
Sign up to request clarification or add additional context in comments.

2 Comments

Accessing the many-to-many relationship before the instance is saved will raise a ValueError and lead to the scenario described. If the instance is saved (and has a primary key) then the relationship would be an empty list.
@AndrewS You're right, updated my answer. Thanks for noticing!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.