【发布时间】:2011-02-21 08:07:58
【问题描述】:
在 Django 的ModelAdmin 中,我需要显示根据用户拥有的权限自定义的表单。有没有办法将当前用户对象放入表单类中,以便我可以在其__init__ 方法中自定义表单?
我认为将当前请求保存在本地线程中是可能的,但这将是我最后的手段,因为我认为这是一种糟糕的设计方法。
【问题讨论】:
标签: django django-forms django-admin
在 Django 的ModelAdmin 中,我需要显示根据用户拥有的权限自定义的表单。有没有办法将当前用户对象放入表单类中,以便我可以在其__init__ 方法中自定义表单?
我认为将当前请求保存在本地线程中是可能的,但这将是我最后的手段,因为我认为这是一种糟糕的设计方法。
【问题讨论】:
标签: django django-forms django-admin
此用例记录在 ModelAdmin.get_form
[...] 如果您想为超级用户提供额外的字段,您可以换成不同的基本形式,如下所示:
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
kwargs['form'] = MySuperuserForm
return super().get_form(request, obj, **kwargs)
如果你只需要保存一个字段,那么你可以直接覆盖ModelAdmin.save_model
from django.contrib import admin
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
super().save_model(request, obj, form, change)
【讨论】:
解决此问题的另一种方法是使用 Django currying,这比将请求对象附加到表单模型更简洁。
from django.utils.functional import curry
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, **kwargs)
return curry(form, current_user=request.user)
这有一个额外的好处,使表单上的 init 方法更加清晰,因为其他人会理解它是作为 kwarg 传递的,而不仅仅是在初始化之前随机附加到类对象的属性。
class BlogPostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.current_user = kwargs.pop('current_user')
super(BlogPostForm, self).__init__(*args, **kwargs)
【讨论】:
这是我最近为博客所做的:
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, **kwargs)
form.current_user = request.user
return form
我现在可以通过访问self.current_user 访问我的forms.ModelForm 中的当前用户
编辑:这是一个旧答案,最近看它我意识到应该将get_form 方法修改为:
def get_form(self, request, *args, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, *args, **kwargs)
form.current_user = request.user
return form
(注意添加*args)
【讨论】:
form = BlogPostForm,get_form 实际返回什么? BlogPostForm 或 BlogPostAdmin 的父类的 ModelForm ...?如果您使用 get_form,BlogPostForm 将如何被使用?
偶然发现了同样的事情,这是我页面上的第一个谷歌结果。Dint 帮助了,更多的谷歌搜索和工作!
这对我来说是这样的(django 1.7+):
class SomeAdmin(admin.ModelAdmin):
# This is important to have because this provides the
# "request" object to "clean" method
def get_form(self, request, obj=None, **kwargs):
form = super(SomeAdmin, self).get_form(request, obj=obj, **kwargs)
form.request = request
return form
class SomeAdminForm(forms.ModelForm):
class Meta(object):
model = SomeModel
fields = ["A", "B"]
def clean(self):
cleaned_data = super(SomeAdminForm, self).clean()
logged_in_email = self.request.user.email #voila
if logged_in_email in ['abc@abc.com']:
raise ValidationError("Please behave, you are not authorised.....Thank you!!")
return cleaned_data
【讨论】:
Joshmaker 的回答在 Django 1.7 上对我不起作用。这是我必须为 Django 1.7 做的事情:
class BlogPostAdmin(admin.ModelAdmin):
form = BlogPostForm
def get_form(self, request, obj=None, **kwargs):
form = super(BlogPostAdmin, self).get_form(request, obj, **kwargs)
form.current_user = request.user
return form
有关此方法的更多详细信息,请参阅this relevant Django documentation
【讨论】:
我想我找到了一个适合我的解决方案:创建ModelForm Django 使用管理员的formfield_for_db_field-方法作为回调。
所以我在我的管理员中覆盖了这个方法,并将当前用户对象作为属性传递给每个字段(这可能不是最有效的,但对我来说似乎比使用 threadlocals 更干净:
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(MyAdmin, self).formfield_for_dbfield(db_field, **kwargs)
field.user = kwargs.get('request', None).user
return field
现在我可以使用__init__ 的形式访问当前用户对象,例如:
current_user=self.fields['fieldname'].user
【讨论】:
AttributeError: kwargs.get('request', None).user