【问题标题】:Django: How to get current user in admin forms?Django:如何在管理表单中获取当前用户?
【发布时间】:2011-02-21 08:07:58
【问题描述】:

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

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

【问题讨论】:

    标签: django django-forms django-admin


    【解决方案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
          猜你喜欢
          • 2019-03-20
          • 1970-01-01
          • 2018-10-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-06-30
          • 2022-06-10
          • 2021-11-20
          相关资源
          最近更新 更多