﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
15062	r14389 breaks getattr on Manager subclasses	Ian Clelland	nobody	"I've been using Simon Willison's [http://djangosnippets.org/snippets/734/ QuerySetManager] pattern for a while now, and since upgrading to Django 1.2.4, it has been breaking when I try to call a method on a !RelatedManager constructed from it.

There was a change in r14389 (r14390 in the 1.2.X branch) which causes this code to break -- where there was a simple delegation before from the !RelatedManager to the !QuerySetManager to the model, there now appears to be an infinite recursion, with the !RelatedManager and !QuerySetManager trying to call each other's get_query_set methods.

!QuerySetManager is just a simple subclass of `django.db.models.Manager`, which overrides `__getattr__` to proxy custom method calls on the manager to a class attached to the underlying model.

The simplest test case I can get to reproduce this problem looks like this:

{{{
from django.db import models
from django.contrib.auth.models import User
from helpers import QuerySetManager

class TestModel(models.Model):
   user = models.ForeignKey(User)
   string = models.CharField(max_length=64, null=True, blank=True)
   objects = QuerySetManager()
   class QuerySet(models.query.QuerySet):
       pass
}}}

Using it gives a traceback like this:

{{{
>>> user = User.objects.get(username='testuser')
>>> user.testmodel_set.create(string=""test"")
Traceback (most recent call last):
 File ""<stdin>"", line 1, in <module>
   user.testmodel_set.create(string=""test"")
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/fields/related.py"", line 423, in create
   return super(RelatedManager, self.db_manager(db)).create(**kwargs)
 File ""/Users/ian/.virtualenvs/egather/lib/python2.6/site-packages/django/db/models/manager.py"", line 138, in create
   return self.get_query_set().create(**kwargs)
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/fields/related.py"", line 410, in get_query_set
   return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
 File ""/Users/ian/Code/Tests/related_test/test_app/models.py"", line 17, in __getattr__
   return getattr(self.get_query_set(), attr, *args)
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/fields/related.py"", line 410, in get_query_set
   return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
 File ""/Users/ian/Code/Tests/related_test/test_app/models.py"", line 17, in __getattr__
   return getattr(self.get_query_set(), attr, *args)
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/fields/related.py"", line 410, in get_query_set
   return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
 File ""/Users/ian/Code/Tests/related_test/test_app/models.py"", line 17, in __getattr__
   return getattr(self.get_query_set(), attr, *args)
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/fields/related.py"", line 410, in get_query_set
   return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
 File ""/Users/ian/Code/Tests/related_test/test_app/models.py"", line 17, in __getattr__
   return getattr(self.get_query_set(), attr, *args)
...
Lots snipped
...
 File ""/Users/ian/.virtualenvs/egather/lib/python2.6/site-packages/django/db/models/fields/related.py"", line 410, in get_query_set
   return superclass.get_query_set(self).using(db).filter(**(self.core_filters))
 File ""/Users/ian/Code/Tests/related_test/test_app/models.py"", line 14, in get_query_set
   return self.model.QuerySet(self.model)
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/query.py"", line 33, in __init__
   self.query = query or sql.Query(self.model)
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/db/models/sql/query.py"", line 138, in __init__
   self.aggregates = SortedDict() # Maps alias -> SQL aggregate function
 File ""/Users/ian/.virtualenvs/testcode/lib/python2.6/site-packages/django/utils/datastructures.py"", line 97, in __init__
   super(SortedDict, self).__init__(data)
RuntimeError: maximum recursion depth exceeded while calling a Python object
}}}"		closed	Documentation	dev		fixed	blocker		Accepted	0	0	0	0	0	0
