django:如何在 ModelForm 中访问当前请求用户?

发布于 2024-12-03 01:11:01 字数 64 浏览 0 评论 0原文

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

In my implementation of ModelForm, I would like to perform different types of validation checks based on whether current user is superuser. How can I access the current request user?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

痴情换悲伤 2024-12-10 01:11:01

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

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']

If you're using Class Based Views (CBVs) then passing an extra argument in the form constructor (e.g. in get_forms_class) or in form_class will not work, as <form> object is not callable will be shown.

The solution for CBVs is to use get_form_kwargs(), e.g.:

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']
信仰 2024-12-10 01:11:01

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

例如

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 表单中使用 user

you can pass the user object as an extra argument in the form constructor.

e.g.

f = MyForm(user=request.user)

and the constructor will look like:

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

and then use user in the clean_XX forms as you wish

岁吢 2024-12-10 01:11:01

我的一个小补充是,

我有一个要求,其中表单的模型选择字段之一依赖于 request.user,我花了一段时间才明白。

这个想法是,

  1. 您需要在模型表单类中有一个 __init__ 方法,

  2. 并且您可以从__init__方法的参数访问请求或其他参数,

  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)

My small addition,

I had a requirement where one of the model choice fields of the form is dependent on the request.user, and it took a while to take my head around.

The idea is that

  1. you need to have a __init__ method in the model form class,

  2. and you access the request or other parameters from the arguments of the __init__ method,

  3. then you need to call the super constructor to new up the form class
  4. and then you set the queryset of the required field

code sample

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)

as you can see, the lists variable is dependent on the current user, which is available via request object, so we set the queryset of the field as null, and its assigned dynamically from the constructor later.

Take a look into the order of the statements in the above code

you can pass the user variable like this from the view file

form = CsvUploadForm(user=request.user)

or with other POST, FILE data like below

form = CsvUploadForm(request.POST, request.FILES, user=request.user)
梦里°也失望 2024-12-10 01:11:01

您可以使用实例本身的实例属性来引用用户对象。

前任; 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

You may reference the user object using the instance attribute within the instance it self.

Ex; 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
两个我 2024-12-10 01:11:01

这对我有用,当我没有在 get_context_data 中显式发送上下文中的表单时:

views.py

class MyView(FormView):
    model = MyModel
    form_class = MyForm

    def get_form_kwargs(self):
       kwargs = super(MyView, self).get_form_kwargs()
       kwargs.update({'user': self.request.user})
       return kwargs

form.py

class MyForm(forms.ModelForm):

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

       if not self.user.groups.filter(name__iexact='t1_group').exists():
          del self.fields['test_obj']

当在 get_context_data 中显式发送表单时,我们可以使用,这是 forms.Form :

views.py
类 MyView(FormView):
模型=我的模型
form_class = MyForm

    def get_context_data(self, **kwargs):
       context = super(MyView, self).get_context_data(**kwargs)
       context['form'] = self.form_class(self.request.user)
       return context

forms.py

class MyForm(forms.Form):

    def __init__(self, user,*args, **kwargs):
       super(MyForm, self).__init__(*args, **kwargs)

       if not user.groups.filter(name__iexact='t1_group').exists():
          del self.fields['test_obj']

This worked for me, when I am not sending form in context explicitly in get_context_data:

views.py

class MyView(FormView):
    model = MyModel
    form_class = MyForm

    def get_form_kwargs(self):
       kwargs = super(MyView, self).get_form_kwargs()
       kwargs.update({'user': self.request.user})
       return kwargs

form.py

class MyForm(forms.ModelForm):

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

       if not self.user.groups.filter(name__iexact='t1_group').exists():
          del self.fields['test_obj']

When sending form explicitly in get_context_data we can use and this is forms.Form :

views.py
class MyView(FormView):
model = MyModel
form_class = MyForm

    def get_context_data(self, **kwargs):
       context = super(MyView, self).get_context_data(**kwargs)
       context['form'] = self.form_class(self.request.user)
       return context

forms.py

class MyForm(forms.Form):

    def __init__(self, user,*args, **kwargs):
       super(MyForm, self).__init__(*args, **kwargs)

       if not user.groups.filter(name__iexact='t1_group').exists():
          del self.fields['test_obj']
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文