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 = BlogPostFormget_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:如何在管理表单中获取当前用户?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 中使用当前用户的邮件地址初始化电子邮件模型表单

如何在 django 表单中获取员工用户的用户名

如何在不完整的 Django 表单字段中获取用户输入?

Django formset 设置当前用户

如何从 django 的表单中获取数据?

Django:如何获取当前用户的组 ID