【问题标题】:django: how to access current request user in ModelForm?django:如何在 ModelForm 中访问当前请求用户?
【发布时间】:2011-11-10 03:04:30
【问题描述】:

在我的 ModelForm 实现中,我想根据当前用户是否是超级用户来执行不同类型的验证检查。如何访问当前请求用户?

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    如果您使用基于类的视图 (CBV),则在表单构造函数中(例如在 get_forms_class 中)或 form_class 中传递额外的参数将不起作用,因为将显示 <form> object is not callable

    CBV 的解决方案是使用get_form_kwargs(),例如:

    views.py:

    class MyUpdateView(UpdateView):
    
        model = MyModel
        form_class = MyForm
    
        # Sending user object to the form, to verify which fields to display/remove (depending on group)
        def get_form_kwargs(self):
            kwargs = super(MyUpdateView, self).get_form_kwargs()
            kwargs.update({'user': self.request.user})
            return kwargs
    

    forms.py:

    class MyForm(forms.ModelForm):
    
        def __init__(self, *args, **kwargs):
            self.user = kwargs.pop('user')  # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
    
            super(MyForm, self).__init__(*args, **kwargs)
    
            # If the user does not belong to a certain group, remove the field
            if not self.user.groups.filter(name__iexact='mygroup').exists():
                del self.fields['confidential']
    

    【讨论】:

      【解决方案2】:

      您可以在表单构造函数中将用户对象作为额外参数传递。

      例如

      f = MyForm(user=request.user)
      

      构造函数看起来像:

      class MyForm(forms.ModelForm):
          def __init__(self, *args, **kwargs):
               self.user = kwargs.pop('user',None)
               super(MyForm, self).__init__(*args, **kwargs)
      

      然后根据需要在 clean_XX 表单中使用用户

      【讨论】:

      • 很抱歉没有在原始问题中澄清这一点,但我的 ModelForm 已连接到 ModelAdmin 子类。如何从 ModelAdmin 调用 ModelForm 的自定义构造函数?
      • 所以您想在 django 管理界面中执行此操作?没有尝试过,但我想你可以尝试覆盖表单的 call 方法。例如:stackoverflow.com/questions/727928/…
      【解决方案3】:

      我的小补充,

      我有一个需求,其中表单的模型选择字段之一依赖于request.user,我花了一段时间才考虑清楚。

      这个想法是

      1. 模型表单类中需要有__init__方法,

      2. 并且您从__init__ 方法的参数中访问request 或其他参数,

      3. 那么你需要调用超级构造函数来新建表单类
      4. 然后你设置必填字段的queryset

      代码示例

      class CsvUploadForm(forms.Form):
      
          def __init__(self, *args, **kwargs):
              user = kwargs.pop('user')
              super(CsvUploadForm, self).__init__(*args, **kwargs)
              self.fields['lists'].queryset = List.objects.filter(user=user)
      
          lists = forms.ModelChoiceField(queryset=None, widget=forms.Select, required=True)
      

      如您所见,lists 变量依赖于当前用户,可通过request 对象获得,因此我们将字段的queryset 设置为null,稍后从构造函数中动态分配.

      看看上面代码中语句的顺序

      你可以像这样从视图文件中传递用户变量

      form = CsvUploadForm(user=request.user)
      

      或与其他 POST、FILE 数据类似,如下所示

      form = CsvUploadForm(request.POST, request.FILES, user=request.user)
      

      【讨论】:

      • init 函数中不要忘记添加 (user=self.user) 只是为了节省一些时间。
      【解决方案4】:

      您可以在它自己的实例中使用实例属性来引用用户对象。

      前; self.instance.user

      class StatusForm(ModelForm):
      
          # def __init__(self, *args, **kwargs):
          #     self.user = kwargs.pop('user', None)
          #     super(StatusForm, self).__init__(*args, **kwargs)
      
          class Meta:
              model = Status
              fields = [
                  'user',
                  'content',
                  'image'
              ]
      
          def clean_content(self):
              content = self.cleaned_data.get("content", None)
              if len(content) > 240:
                  raise ValidationError(f"Hey {self.instance.user.username}, the content is too long")
              return content
      

      【讨论】:

        猜你喜欢
        • 2020-11-08
        • 2011-05-17
        • 1970-01-01
        • 2012-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-31
        相关资源
        最近更新 更多