Django Admin Issue - 'NoneType' object has no attribute 'user'

天涯浪子 提交于 2021-01-29 08:25:13

问题


Writing a blog engine with Django 1.5 and using the Django Admin. Everything was fine, until I added a ManyToManyField to a model, and added that field to the ModelAdmin's fieldsets, then I started to get this mysterious error when trying to load the admin page:

'NoneType' object has no attribute 'user'

(Full stack trace further on below.) Why would the response object suddenly be None? If I remove the field from the fieldset, everything's fine again.

My models look something a bit like this (lots of fields removed):

class Tag(models.Model):
    name = models.CharField(max_length=30)

class Post(models.Model):
    title = models.CharField(max_length=300)
    tags = models.ManyToManyField(Tag)
    author = models.CharField(max_length=100)

And the ModelAdmin looks a bit like this:

class PostAdmin(admin.ModelAdmin):
    # Order
    fieldsets = (
        ('Content', {
            'fields': ('title', 'tags')
        }),
    )

    def formfield_for_dbfield(self, db_field, request, **kwargs):
        # Pre-fill 'author' with logged in name
        if db_field.name == "author":
            kwargs['initial'] = "%s %s" % (request.user.first_name, request.user.last_name)
            return db_field.formfield(**kwargs)
        return super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs)

And it's when I remove 'tag's from the fieldsets that all is well again. It could be that I'm making some simple Django Admin mistake, I haven't used it much before, but the best I could find googling was some bug that was fixed three years ago, and I'm sure I'm running 1.5.1.

Here's the full stack trace:

Internal Server Error: /theadmin/blog/post/1/
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\django\core\handlers\base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "C:\Python27\lib\site-packages\django\contrib\admin\options.py", line 372, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "C:\Python27\lib\site-packages\django\utils\decorators.py", line 91, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "C:\Python27\lib\site-packages\django\views\decorators\cache.py", line 89, in _wrapped_view_
unc
    response = view_func(request, *args, **kwargs)
  File "C:\Python27\lib\site-packages\django\contrib\admin\sites.py", line 202, in inner
    return view(request, *args, **kwargs)
  File "C:\Python27\lib\site-packages\django\utils\decorators.py", line 25, in _wrapper
    return bound_func(*args, **kwargs)
  File "C:\Python27\lib\site-packages\django\utils\decorators.py", line 91, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "C:\Python27\lib\site-packages\django\utils\decorators.py", line 21, in bound_func
    return func(self, *args2, **kwargs2)
  File "C:\Python27\lib\site-packages\django\db\transaction.py", line 223, in inner
    return func(*args, **kwargs)
  File "C:\Python27\lib\site-packages\django\contrib\admin\options.py", line 1081, in change_view
    ModelForm = self.get_form(request, obj)
  File "C:\Python27\lib\site-packages\django\contrib\admin\options.py", line 465, in get_form
    return modelform_factory(self.model, **defaults)
  File "C:\Python27\lib\site-packages\django\forms\models.py", line 424, in modelform_factory
    return type(form)(class_name, (form,), form_class_attrs)
  File "C:\Python27\lib\site-packages\django\forms\models.py", line 212, in __new__
    opts.exclude, opts.widgets, formfield_callback)
  File "C:\Python27\lib\site-packages\django\forms\models.py", line 170, in fields_for_model
    formfield = formfield_callback(f, **kwargs)
  File "E:\Dropbox\PassionateAbout\PassionateAboutJustice\blog\admin.py", line 35, in formfield_for
dbfield
    return super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs)
  File "C:\Python27\lib\site-packages\django\contrib\admin\options.py", line 125, in formfield_for_
bfield
    related_modeladmin.has_add_permission(request))
  File "C:\Python27\lib\site-packages\django\contrib\admin\options.py", line 284, in has_add_permis
ion
    return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
AttributeError: 'NoneType' object has no attribute 'user'

回答1:


Your swallowing the request. Here you take it:

def formfield_for_dbfield(self, db_field, request, **kwargs):

but then you don't pass it on:

return super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs)

However the original - https://github.com/django/django/blob/stable/1.5.x/django/contrib/admin/options.py#L88 is defined as:

def formfield_for_dbfield(self, db_field, **kwargs):

So you should keep the same signature when you override. Please note: the original will do:

request = kwargs.pop("request", None)

If you want to access the request, don't do the same, because "pop()" will remove it from kwargs. Just access without deleting:

request = kwargs['request']

so your super call still passes the request through.

It only came to light with the M2M field because that needs the request to look up permissions of the current user (for the related model) whereas CharField doesn't really need the request, so doesn't mind that it's None. (which the above pop() call will do if request is not found)

End result:

def formfield_for_dbfield(self, db_field, **kwargs):
    # Pre-fill 'author' with logged in name
    if db_field.name == "author":
        request = kwargs['request']
        kwargs['initial'] = "%s %s" % (request.user.first_name, request.user.last_name)
        return db_field.formfield(**kwargs)
    return super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs)


来源:https://stackoverflow.com/questions/18212320/django-admin-issue-nonetype-object-has-no-attribute-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!