Code

Opened 6 years ago

Closed 6 years ago

Last modified 3 years ago

#7107 closed (fixed)

ManyToMany self-referential models *need* a related_name

Reported by: tsouanas Owned by: mtredinnick
Component: Uncategorized Version: master
Severity: Keywords: qsrf-cleanup manytomany, infinite loop
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Without a related_name, self-referential ManyToMany models seem cause an infinite loop when trying to insert new objects.

Attachments (0)

Change History (9)

comment:1 Changed 6 years ago by mtredinnick

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

I cannot repeat this problem. Can you please provide a short example model and instructions for how to trigger the problem?

I've been using this model for testing and I can insert, query and remove things from the m2m field without any problems.

class M2MSelfRef(models.Model):
    name = models.CharField(max_length=10)
    similar = models.ManyToManyField('self')

    def __unicode__(self):
        return '%s - %s' % (self.name, ', '.join(self.similar.values_list('name', flat=True)))

comment:2 Changed 6 years ago by anonymous

Using this model, when I try to edit it from the admin interface (newforms-admin) without the related_name attribute, I get a

Infinite loop caused by ordering.

error.

(I also used to have an "order_with_respect_to = 'parents'" inside the Meta class but I removed it.)

class Topic(models.Model):
    topic = models.CharField(max_length=128)
    parents = models.ManyToManyField('self', related_name='topic_parents', null=True, blank=True)

    class Meta:
        ordering = ('topic',)

    def ancestors(self):
        if not self.parents:
            return [self]
        else:
            return sum([parent.ancestors() for parent in self.parents], [self])

    def subtopic_of(self, topic):
        return topic in self.ancestors()

    def related_with(self, topic):
        return self.subtopic_of(topic) or topic.subtopic_of(self)

comment:3 Changed 6 years ago by gav

  • Keywords qsrf-cleanup added

comment:4 Changed 6 years ago by jacob

  • milestone set to 1.0

comment:5 Changed 6 years ago by mtredinnick

  • Component changed from Documentation to Uncategorized
  • Version changed from SVN to newforms-admin

I'm going to reassign this to the newforms-admin branch, since it doesn't seem to be core-related. The normal core code will not be using parent anywhere in the ordering querying, since it's just not specified. If newforms-admin is somehow introducing an implicit ordering on that many-to-many relation, it needs to work out how it's going to avoid the infinite loop problem. I haven't looked at the newforms-admin code to see what's going on here, but, as indicated in the first comment, I can't repeat it with normal code on trunk.

So Brian or Karen ... any big ideas what's going on here?

comment:6 Changed 6 years ago by Karen Tracey <kmtracey@…>

  • Version changed from newforms-admin to SVN

I don't think the problem is in the admin. I can recreate the problem by just doing a Topic.objects.all() in a python shell with the given model. The problem seems to relate to having specified an ordering on a field that is identical except for case to the name of the Model. If I change the model name so that is different than the field name then the problem goes away. That is, given these models:

class Topic(models.Model):
    topic = models.CharField(max_length=128)
    parents = models.ManyToManyField('self', null=True, blank=True)

    class Meta:
        ordering = ('topic',)

class TopicModel(models.Model):
    topic = models.CharField(max_length=128)
    parents = models.ManyToManyField('self', null=True, blank=True)

    class Meta:
        ordering = ('topic',)

this is what I see:

Python 2.5.1 (r251:54863, Mar  7 2008, 04:10:12)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import django
>>> django.get_version()
u'0.97-pre-SVN-7739'
>>> from m2m.models import Topic,TopicModel
>>> Topic.objects.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/homedir/django/trunk/django/db/models/query.py", line 129, in __repr__
    return repr(list(self))
  File "/homedir/django/trunk/django/db/models/query.py", line 141, in __len__
    self._result_cache.extend(list(self._iter))
  File "/homedir/django/trunk/django/db/models/query.py", line 248, in iterator
    for row in self.query.results_iter():
  File "/homedir/django/trunk/django/db/models/sql/query.py", line 200, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/homedir/django/trunk/django/db/models/sql/query.py", line 1464, in execute_sql
    sql, params = self.as_sql()
  File "/homedir/django/trunk/django/db/models/sql/query.py", line 247, in as_sql
    ordering = self.get_ordering()
  File "/homedir/django/trunk/django/db/models/sql/query.py", line 583, in get_ordering
    self.model._meta, default_order=asc):
  File "/homedir/django/trunk/django/db/models/sql/query.py", line 627, in find_ordering_name
    order, already_seen))
  File "/homedir/django/trunk/django/db/models/sql/query.py", line 621, in find_ordering_name
    raise FieldError('Infinite loop caused by ordering.')
FieldError: Infinite loop caused by ordering.
>>> TopicModel.objects.all()
[]
>>>

comment:7 Changed 6 years ago by mtredinnick

  • Owner changed from nobody to mtredinnick
  • Triage Stage changed from Unreviewed to Accepted

Right, my bad then. I'll fix it.

comment:8 Changed 6 years ago by mtredinnick

  • Resolution set to fixed
  • Status changed from new to closed

(In [7764]) Fixed the way symmetrical many-to-many relations are recorded in the Options class.

These types of relations don't have reverse accessor names, so that name can be
used by a normal field on the model. Fixed #7107.

comment:9 Changed 3 years ago by jacob

  • milestone 1.0 deleted

Milestone 1.0 deleted

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.