Opened 6 years ago

Closed 6 years ago

#14283 closed (duplicate)

AttributeError on admin detail page after r13708

Reported by: rene.puls@… Owned by: nobody
Component: Contrib apps Version: 1.2
Severity: Keywords:
Cc: Simon Litchfield, rokclimb15@…, django@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: UI/UX:

Description

After updating to the latest Django version (r13840), I am getting strange errors when displaying the admin detail page for some of my models. I haven't touched my own admin or model classes for a while, so I suspect this could be a bug in a recent Django changeset. I am not very familiar with this part of Django, but it seems like the request object is not passed through correctly.

Here is the traceback:

Traceback (most recent call last):

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/core/handlers/base.py", line 100, in get_response
   response = callback(request, *callback_args, **callback_kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/admin/options.py", line 245, in wrapper
   return self.admin_site.admin_view(view)(*args, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/utils/decorators.py", line 76, in _wrapped_view
   response = view_func(request, *args, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/views/decorators/cache.py", line 69, in _wrapped_view_func
   response = view_func(request, *args, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 190, in inner
   return view(request, *args, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/utils/decorators.py", line 21, in _wrapper
   return decorator(bound_func)(*args, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/utils/decorators.py", line 76, in _wrapped_view
   response = view_func(request, *args, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/utils/decorators.py", line 17, in bound_func
   return func(self, *args2, **kwargs2)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/db/transaction.py", line 299, in _commit_on_success
   res = func(*args, **kw)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/admin/options.py", line 913, in change_view
   for FormSet, inline in zip(self.get_formsets(request, obj), self.inline_instances):

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/admin/options.py", line 421, in get_formsets
   yield inline.get_formset(request, obj)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/contenttypes/generic.py", line 403, in get_formset
   return generic_inlineformset_factory(self.model, **defaults)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/contenttypes/generic.py", line 369, in generic_inlineformset_factory
   fields=fields, exclude=exclude, max_num=max_num)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/forms/models.py", line 685, in modelformset_factory
   formfield_callback=formfield_callback)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/forms/models.py", line 423, in modelform_factory
   return ModelFormMetaclass(class_name, (form,), form_class_attrs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/forms/models.py", line 227, in __new__
   opts.exclude, opts.widgets, formfield_callback)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/forms/models.py", line 185, in fields_for_model
   formfield = formfield_callback(f, **kwargs)

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/admin/options.py", line 113, in formfield_for_dbfield
   related_modeladmin.has_add_permission(request))

 File "/usr/local/python-2.6/lib/python2.6/site-packages/django/contrib/admin/options.py", line 292, in has_add_permission
   return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())

AttributeError: 'NoneType' object has no attribute 'user'

Looking through the recent changes in Django trunk, I see that r13731 changed fields_for_model in django.forms.models, which is also in the traceback. Could this have something to do with it?

For reference, here is my model admin class:

class EventAdmin(dj_admin.ModelAdmin):
    model = my_models.Event
    inlines = [metadata_admin.CommentInline, metadata_admin.RatingInline, metadata_admin.TagInline]
    date_hierarchy = 'created'
    raw_id_fields = ['owner', 'image', 'address']
    list_display = ['title', 'owner', 'created', 'is_active', 'is_hidden', 'community']
    list_filter = ['is_highlighted', 'community']
    fieldsets = [
        (None, {'fields': ['owner', 'community', ('start', 'end'), 'title', 'description', 'address', 'image', ('is_hidden', 'is_active'), 'is_highlighted', 'license']}),
        (u'Statistiken', {'fields': ['views', 'num_comments', 'num_ratings', 'average_rating'], 'classes': ['collapse']})
    ]
    save_on_top = True
    search_fields = ['title']

Attachments (2)

testcase14283.tar.gz (2.7 KB) - added by rene.puls@… 6 years ago.
Minimal test case
fix14283.patch (3.1 KB) - added by Matthias Kestenholz 6 years ago.

Download all attachments as: .zip

Change History (14)

comment:1 Changed 6 years ago by rene.puls@…

Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset
Summary: AttributeError: 'NoneType' object has no attribute 'user' on admin detail pageAttributeError on admin detail page after r13708

This actually seems to be caused by r13708. When I revert this changeset, the detail page appears normally again.

Changed 6 years ago by rene.puls@…

Attachment: testcase14283.tar.gz added

Minimal test case

comment:2 Changed 6 years ago by rene.puls@…

I have spent some more time tracking down this problem. Here is what I have found out.

There are three model classes involved:

  • Model A, no fields required
  • Model B, no fields required
  • Model C, with a generic foreign key and a regular foreign key to model B

And there are also two admin classes involved:

  • ModelCInline, a GenericTabularInline for model C
  • ModelAAdmin, which includes ModelCInline
  • In addition, model B must be registered with the admin site, but does not need any special options

When I try to add or change instances of model A on the admin site, I get an AttributeError with the following traceback:

Environment:

Request Method: GET
Request URL: http://localhost:8000/admin/testapp/modela/add/
Django Version: 1.3 pre-alpha SVN-13865
Python Version: 2.7.0
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.admin',
 'testcase14283.testapp']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/Users/rpuls/Library/Python/django/core/handlers/base.py" in get_response
  100.                     response = callback(request, *callback_args, **callback_kwargs)
File "/Users/rpuls/Library/Python/django/contrib/admin/options.py" in wrapper
  245.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Users/rpuls/Library/Python/django/utils/decorators.py" in _wrapped_view
  76.                     response = view_func(request, *args, **kwargs)
File "/Users/rpuls/Library/Python/django/views/decorators/cache.py" in _wrapped_view_func
  78.         response = view_func(request, *args, **kwargs)
File "/Users/rpuls/Library/Python/django/contrib/admin/sites.py" in inner
  190.             return view(request, *args, **kwargs)
File "/Users/rpuls/Library/Python/django/utils/decorators.py" in _wrapper
  21.             return decorator(bound_func)(*args, **kwargs)
File "/Users/rpuls/Library/Python/django/utils/decorators.py" in _wrapped_view
  76.                     response = view_func(request, *args, **kwargs)
File "/Users/rpuls/Library/Python/django/utils/decorators.py" in bound_func
  17.                 return func(self, *args2, **kwargs2)
File "/Users/rpuls/Library/Python/django/db/transaction.py" in _commit_on_success
  299.                     res = func(*args, **kw)
File "/Users/rpuls/Library/Python/django/contrib/admin/options.py" in add_view
  822.                                        self.inline_instances):
File "/Users/rpuls/Library/Python/django/contrib/admin/options.py" in get_formsets
  421.             yield inline.get_formset(request, obj)
File "/Users/rpuls/Library/Python/django/contrib/contenttypes/generic.py" in get_formset
  403.         return generic_inlineformset_factory(self.model, **defaults)
File "/Users/rpuls/Library/Python/django/contrib/contenttypes/generic.py" in generic_inlineformset_factory
  369.                                    fields=fields, exclude=exclude, max_num=max_num)
File "/Users/rpuls/Library/Python/django/forms/models.py" in modelformset_factory
  685.                              formfield_callback=formfield_callback)
File "/Users/rpuls/Library/Python/django/forms/models.py" in modelform_factory
  423.     return ModelFormMetaclass(class_name, (form,), form_class_attrs)
File "/Users/rpuls/Library/Python/django/forms/models.py" in __new__
  227.                                       opts.exclude, opts.widgets, formfield_callback)
File "/Users/rpuls/Library/Python/django/forms/models.py" in fields_for_model
  185.             formfield = formfield_callback(f, **kwargs)
File "/Users/rpuls/Library/Python/django/contrib/admin/options.py" in formfield_for_dbfield
  113.                             related_modeladmin.has_add_permission(request))
File "/Users/rpuls/Library/Python/django/contrib/admin/options.py" in has_add_permission
  292.         return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())

Exception Type: AttributeError at /admin/testapp/modela/add/
Exception Value: 'NoneType' object has no attribute 'user'

One interesting thing is that the error goes away as soon as I remove the line that registers model B with the admin site.

For a minimal test case, you can use the attached project, which is basically just a models.py:

import django.db.models as dj_models
import django.contrib.admin as dj_admin
import django.contrib.contenttypes.models as dj_ct_models
import django.contrib.contenttypes.generic as dj_generic


# model classes

class ModelC(dj_models.Model):
    relation_b = dj_models.ForeignKey('ModelB')
    
    tagged_object = dj_generic.GenericForeignKey()
    content_type = dj_models.ForeignKey(dj_ct_models.ContentType)
    object_id = dj_models.PositiveIntegerField()


class ModelA(dj_models.Model):
    pass


class ModelB(dj_models.Model):
    pass


# admin classes

class ModelCInline(dj_generic.GenericTabularInline):
    model = ModelC


class ModelAAdmin(dj_admin.ModelAdmin):
    inlines = [ModelCInline]


dj_admin.site.register(ModelA, ModelAAdmin)

# remove the following line to make the error go away
dj_admin.site.register(ModelB)

comment:3 Changed 6 years ago by Matthias Kestenholz

Has patch: set
Triage Stage: UnreviewedAccepted

Need to curry formfield_for_dbfield in contenttypes/generic.py. Patch attached.

Changed 6 years ago by Matthias Kestenholz

Attachment: fix14283.patch added

comment:4 Changed 6 years ago by Gabriel Hurley

Component: UncategorizedContrib apps

comment:5 Changed 6 years ago by Simon Litchfield

Cc: Simon Litchfield added

Same error, same stacktrace exactly.

This time with an inline that has two keys back to the "parent" model and uses "fk_name" to select which one to link by.

So, this isn't just a GenericForeignKey issue. Somehow, formfield_for_dbfield() is getting a None request object in other instances also (haven't dug any deeper just yet).

comment:6 Changed 6 years ago by Simon Litchfield

Has patch: unset
Patch needs improvement: set
Triage Stage: AcceptedUnreviewed

comment:7 Changed 6 years ago by Gabriel Hurley

Has patch: set
Triage Stage: UnreviewedAccepted

@simon29: there was no need to reset the status to "Unreviewed". The ticket is still accepted. Also, there is still a patch, even if it needs improvement, so unchecking the "has patch" box is also unnecessary.

If you're still seeing failures after applying the latest patch, the best thing to do is to provide a failing unit test. Thanks!

comment:8 Changed 6 years ago by Jay States

I want to confirm that I had the same problem and the patch works.

comment:9 Changed 6 years ago by rokclimb15

Cc: rokclimb15@… added
Owner: changed from nobody to rokclimb15
Status: newassigned

comment:10 Changed 6 years ago by rokclimb15

Owner: changed from rokclimb15 to nobody
Status: assignednew

comment:11 Changed 6 years ago by Will Hardy

Cc: django@… added

comment:12 Changed 6 years ago by René Puls

Resolution: duplicate
Status: newclosed

Fixed in [14555], see also ticket #14670.

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