Opened 16 years ago

Closed 14 years ago

Last modified 13 years ago

#8569 closed (fixed)

Admin fieldsets can cause "'str' object has no attribute '_default_manager'' under mod_wsgi

Reported by: Karen Tracey Owned by: Malcolm Tredinnick
Component: Uncategorized Version: dev
Severity: 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

As reported here: http://groups.google.com/group/django-users/browse_thread/thread/da39ac4b1e5c1751# (and earlier but never recreated/isolated), under some circumstances a fieldsets definition in a ModelAdmin definition can cause the exception:

'str' object has no attribute '_default_manager'

Today's poster isolated the problem to mod_wsgi, and I was able to recreate with an example project he sent to me. There are two apps: catalogue and simplepromo (listed in that order in INSTALLED_APPS, reversing them didn't change anything). catalogue has a single model in models.py:

class Maker(models.Model):
    dummy = models.CharField(blank=True, max_length=80)

    def __unicode__(self):
        return self.dummy

simplepromo (a simplified version of what Maciek sent me), also has a single model in models.py:

class SimplePromo(models.Model):
    
    name = models.CharField(blank=False, max_length=250, help_text="Displayed in overlay tooltip")
    slug = models.SlugField()
    promo_maker = models.ForeignKey("catalogue.Maker", null=True, blank=False)
    def __unicode__(self):
        return self.name

and an admin.py file:

from django.contrib import admin
from simplepromo.models import *
class SimplePromoAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}
    
    fieldsets = (
        ("Base", {
            "fields": ["name","slug","promo_maker",],
        }),
    )
    
admin.site.register(SimplePromo, SimplePromoAdmin)

The call to admin.autodiscover() in urls.py is what generates the exception. If I remove the catch/transform to ImproperlyConfigured done by urlresolvers.py (ref #7524) I can get the actual traceback:

Environment:

Request Method: GET
Request URL: http://localhost/admin/
Django Version: 1.0-beta_1-SVN-8582
Python Version: 2.5.2
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.humanize',
 'django.contrib.markup',
 'django.contrib.sessions',
 'django.contrib.sites',
 'catalogue',
 'simplepromo']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.middleware.doc.XViewMiddleware')


Traceback:
File "c:\u\kmt\django\trunk\django\core\handlers\base.py" in get_response
  77.                     request.path_info)
File "c:/u/kmt/django/trunk\django\core\urlresolvers.py" in resolve
  238.             for pattern in self.urlconf_module.urlpatterns:
File "c:/u/kmt/django/trunk\django\core\urlresolvers.py" in _get_urlconf_module
  257.              self._urlconf_module = __import__(self.urlconf_name, {}, {}, [''])
File "c:/u/kmt/software/web/ppi-test\urls.py" in <module>
  9. admin.autodiscover()
File "c:\u\kmt\django\trunk\django\contrib\admin\__init__.py" in autodiscover
  19.         __import__("%s.admin" % app)
File "c:/u/kmt/software/web/ppi-test\simplepromo\admin.py" in <module>
  12. admin.site.register(SimplePromo, SimplePromoAdmin)
File "c:\u\kmt\django\trunk\django\contrib\admin\sites.py" in register
  91.             validate(admin_class, model)
File "c:\u\kmt\django\trunk\django\contrib\admin\validation.py" in validate
  19.     _validate_base(cls, model)
File "c:\u\kmt\django\trunk\django\contrib\admin\validation.py" in _validate_base
  201.             _check_form_field_existsw("fieldsets[%d][1]['fields']" % idx, field)
File "c:\u\kmt\django\trunk\django\contrib\admin\validation.py" in _check_form_field_existsw
  162.         return _check_form_field_exists(cls, model, opts, label, field)
File "c:\u\kmt\django\trunk\django\contrib\admin\validation.py" in _check_form_field_exists
  282.         fields = fields_for_model(model)
File "c:\u\kmt\django\trunk\django\forms\models.py" in fields_for_model
  145.         formfield = formfield_callback(f)
File "c:\u\kmt\django\trunk\django\forms\models.py" in <lambda>
  124. def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
File "c:\u\kmt\django\trunk\django\db\models\fields\related.py" in formfield
  726.         defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)}

Exception Type: AttributeError at /admin/
Exception Value: 'str' object has no attribute '_default_manager'

I added a couple of local variables so I could see what's what and the local vars in that last routine are:

kwargs  {}
self  <django.db.models.fields.related.ForeignKey object at 0x01EC8390>
self_rel <django.db.models.fields.related.ManyToOneRel object at 0x01EC83B0>
self_rel_to 'catalogue.Maker'

Running the exact same app code under the development server plus putting a stop exception where the exception is generated under wsgi, I can see the local vars are different when running under the dev server:

kwargs  {}
self  <django.db.models.fields.related.ForeignKey object at 0x01067BB0>
self_rel  <django.db.models.fields.related.ManyToOneRel object at 0x01067BD0>
self_rel_to  <class 'catalogue.models.Maker'>

So somehow when running under the dev server (and anything other than wsgi, according to Maciek) self.rel.to has been transformed from a string to an actual class reference before this code is called. I haven't a clue how this happens or why it isn't happening when running under mod_wsgi, so that's about as far as I can go with this one. Hopefully someone else can shed some light?

Change History (9)

comment:1 by Eric B <ebartels@…>, 16 years ago

Seems this happens under mod_python as well. Importing the related model directly instead of using the string form, "catalogue.Maker", is a workaround.

comment:2 by Malcolm Tredinnick, 16 years ago

Owner: changed from nobody to Malcolm Tredinnick
Status: newassigned

in reply to:  1 comment:3 by Karen Tracey, 16 years ago

Replying to Eric B <ebartels@gmail.com>:

Seems this happens under mod_python as well. Importing the related model directly instead of using the string form, "catalogue.Maker", is a workaround.

Yeah, I thought that might work, but also thought the string form needs to be supported for the case where you've actually got a circular reference?

comment:4 by Malcolm Tredinnick, 16 years ago

Resolution: fixed
Status: assignedclosed

(In [8605]) Fixed #8569 -- Ensure that apps are correctly set up before introspecting them
in admin validation.

comment:5 by Matthias Kestenholz, 16 years ago

I don't have the time to do further analysis currently, but the same problem still shows up with GenericRelations:

items = generic.GenericRelation('items.Item') produced errors from time to time

comment:6 by Karen Tracey, 16 years ago

When you get time, a new ticket with a reproducible test case would help in tracking down whatever problem you are seeing.

comment:7 by BEBABUM, 14 years ago

Resolution: fixed
Status: closedreopened

Hi there,
I have the following code:

"""
app firstApp
models.py
"""
class Model1(models.Model):
   name = models.CharField(max_length = 100)

"""
app SecondApp
models.py
"""
class Model2(models.Model):
   model1 = models.ForeignKey("firstApp.Model1", null = True, blank = True)
   date_time = models.DateTimeField()

#Forms
class Model2AdminForm(forms.ModelForm)
   class Meta:
      model = Model2

It crashes when I do something like a = MOdel2AdminForm()

for some reason "from project.firsApp.models import Model1" does not work, just throw an error saying that the model "Model1" can't be imported
When form is like above example throw an error saying "'str' object has no attribute '_default_manager'"
When form is like Model2AdminForm(forms.Form) all seems to work fine but the form is not what I want.

Regards,

GPB - BEBABUM

comment:8 by Karen Tracey, 14 years ago

Resolution: fixed
Status: reopenedclosed

This problem was fixed over a year ago, really. What you are seeing is caused by some other problem, and what you've posted here is too far simplified to recreate whatever the actual problem is -- if you try given just what you have posted, no error is raised. Given the error raised when you try to import Model1, likely the problem is a circular import, which you should be able to track down by looking closely at the full stack trace when the error is raised. If not please post on django-users for help.

comment:9 by Jacob, 13 years ago

milestone: 1.0

Milestone 1.0 deleted

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