Django:如何在管理表单中获取当前用户?

问题描述 投票:0回答:7

在Django的

ModelAdmin
中,我需要显示根据用户拥有的权限定制的表单。有没有办法将当前用户对象放入表单类中,以便我可以在其
__init__
方法中自定义表单?

我认为将当前请求保存在本地线程中是可能的,但这将是我的最后手段,因为我认为这是一种糟糕的设计方法。

django django-forms django-admin
7个回答
73
投票

这是我最近为博客所做的事情:

class BlogPostAdmin(admin.ModelAdmin):
    form = BlogPostForm

    def get_form(self, request, *args, **kwargs):
        form = super(BlogPostAdmin, self).get_form(request, *args, **kwargs)
        form.current_user = request.user
        return form

我现在可以通过访问

forms.ModelForm
 来访问我的 
self.current_user

中的当前用户

22
投票

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

有关此方法的更多详细信息,请参阅相关的 Django 文档


9
投票

此用例记录在 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)

5
投票

我想我找到了一个适合我的解决方案:要创建一个

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

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 ['[email protected]']:
            raise ValidationError("Please behave, you are not authorised.....Thank you!!")
        return cleaned_data

4
投票

解决此问题的另一种方法是使用 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)

0
投票

使用此函数作为表单类的代理,允许我们在表单实例上注入请求,以便我们可以在干净的方法中访问它。

通过使用如下解决方案(get_form_class_with_request),您可以将请求注入隔离到表单实例创建的时刻。这确保了每个表单实例都有自己的请求数据,从而降低了共享状态导致的冲突和意外行为的风险。

def get_form_class_with_request(
        form_class: type[forms.ModelForm], request: HttpRequest
) -> Callable[[tuple[Any, ...], dict[str, Any]], ModelForm]:
    
        def init_form(*args, **kwargs) -> ModelForm:
            form_instance = form_class(*args, **kwargs)
            form_instance.request = request
            form_instance.current_user = request.user
    
            return form_instance
    
        init_form.base_fields = form_class.base_fields
    
        return init_form


class CustomModelAdmin(admin.ModelAdmin):
    form = YourForm    
    def get_form(self, request, *args, **kwargs):
        form = super().get_form(request, *args, **kwargs)
        form_proxy = get_form_class_with_request(form, request)

        return form_proxy

总体而言,最佳实践是将特定于请求的数据保留在请求范围内,并避免将其直接存储在表单类或其他共享对象中,以保持适当的隔离并防止潜在问题。

© www.soinside.com 2019 - 2024. All rights reserved.