Opened 8 years ago

Closed 8 years ago

#26768 closed Bug (duplicate)

Using a ManyToMany field in a model's __unicode__/__str__ method can cause infinite recursion

Reported by: Lakin Wecker Owned by: nobody
Component: Database layer (models, ORM) Version: 1.9
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If you define a model with a unicode/str method and use ManyToMany field - accessing the ManyToMany description can raise a value error in its constructor:

https://github.com/django/django/blob/master/django/db/models/fields/related_descriptors.py#L804

When that value error is raise, it attempts to get a string representation of that instance again, which causes infinite recursion.

Change History (5)

comment:1 by Lakin Wecker, 8 years ago

I have (yet) had time to create a working test case although I would like to do so. The basic model pattern I am using is:

class Contact(models.Model):
    name = models.CharField(max_length=255)
    def __unicode__(self):
        return self.name
class ArtObject(models.Model):
    name = models.CharField(max_length=255)
class ArtObjectArtists(models.Model):
    art_object = model.ForeignKey(ArtObject)
    artists = models.ManyToManyField(Contact)
    def __unicode__(self):
        return u", ".join([a.name for a in self.artists.allI()])

Then I have an admin where the ArtObjectArtist is edit_inline on the ArtObject page, and I am trying to delete one of two ArtObjectArtists from a particular art object.

I haven't tracked down exactly what in that flow is causing the ValueError to be raised, but it is definitely coming from attempting to access self.artists .

comment:2 by Lakin Wecker, 8 years ago

It seems that the django admin is attempting to log which objects it has deleted, and it does this by calling their unicode/str method. However, the deleted object no longer has a pk set so it can't use its ManyToManyField anymore.

surrounding the access to the self.artists.all() with a: if self.pk: seems to work - but this definitely isn't the behavior I expect.

Not sure what the appropriate fix is within django, if any.

comment:3 by Simon Charette, 8 years ago

surrounding the access to the self.artists.all() with a: if self.pk: seems to work - but this definitely isn't the behavior I expect.

Not sure what the appropriate fix is within django, if any.

Hi lakinwecker,

You should make sure your object instance string representation method account for the fact self.pk can be None.

Another example where this could be required is str(ArtObjectArtists()).

comment:4 by Lakin Wecker, 8 years ago

I guess I just expect self.artists.all() to return an empty list when self.pk is None rather than raising an exception which possibly causes an infinite recursion.

comment:5 by Tim Graham, 8 years ago

Resolution: duplicate
Status: newclosed

The behavior will change as you expect in #19580.

Note: See TracTickets for help on using tickets.
Back to Top