Django:如何在管理表单中获取当前用户?
Posted
技术标签:
【中文标题】Django:如何在管理表单中获取当前用户?【英文标题】:Django: How to get current user in admin forms? 【发布时间】:2011-02-21 08:07:58 【问题描述】:在 Django 的ModelAdmin
中,我需要显示根据用户拥有的权限自定义的表单。有没有办法将当前用户对象放入表单类中,以便我可以在其__init__
方法中自定义表单?
我认为将当前请求保存在本地线程中是可能的,但这将是我最后的手段,因为我认为这是一种糟糕的设计方法。
【问题讨论】:
【参考方案1】:此用例记录在 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)
【讨论】:
【参考方案2】:解决此问题的另一种方法是使用 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)
【讨论】:
我喜欢这个,但遗憾的是它不起作用,因为下游代码需要一个表单类而不是 curry 函数。这样做会导致以下错误“'function' object has no attribute 'base_fields'” 可以直接添加到kwargs吗?【参考方案3】:这是我最近为博客所做的:
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 将如何被使用?
这不是将用户设置在表单类而不是特定的表单实例上吗?好像有点危险……【参考方案4】:
偶然发现了同样的事情,这是我页面上的第一个谷歌结果。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
【讨论】:
【参考方案5】: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
【讨论】:
【参考方案6】:我想我找到了一个适合我的解决方案:创建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
以上是关于Django:如何在管理表单中获取当前用户?的主要内容,如果未能解决你的问题,请参考以下文章