Code

Opened 4 years ago

Closed 4 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: simon29, 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@… 4 years ago.
Minimal test case
fix14283.patch (3.1 KB) - added by mk 4 years ago.

Download all attachments as: .zip

Change History (14)

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

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Summary changed from AttributeError: 'NoneType' object has no attribute 'user' on admin detail page to AttributeError 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 4 years ago by rene.puls@…

Minimal test case

comment:2 Changed 4 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 4 years ago by mk

  • Has patch set
  • Triage Stage changed from Unreviewed to Accepted

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

Changed 4 years ago by mk

comment:4 Changed 4 years ago by gabrielhurley

  • Component changed from Uncategorized to Contrib apps

comment:5 Changed 4 years ago by simon29

  • Cc simon29 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 4 years ago by simon29

  • Has patch unset
  • Patch needs improvement set
  • Triage Stage changed from Accepted to Unreviewed

comment:7 Changed 4 years ago by gabrielhurley

  • Has patch set
  • Triage Stage changed from Unreviewed to Accepted

@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 4 years ago by Jay States

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

comment:9 Changed 4 years ago by rokclimb15

  • Cc rokclimb15@… added
  • Owner changed from nobody to rokclimb15
  • Status changed from new to assigned

comment:10 Changed 4 years ago by rokclimb15

  • Owner changed from rokclimb15 to nobody
  • Status changed from assigned to new

comment:11 Changed 4 years ago by willhardy

  • Cc django@… added

comment:12 Changed 4 years ago by pwr

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

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

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.