问题
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