Django: как получить доступ к текущему запросу пользователя в ModelForm? - PullRequest
9 голосов
/ 04 сентября 2011

В моей реализации ModelForm я хотел бы выполнять различные типы проверок достоверности на основе того, является ли текущий пользователь суперпользователем. Как я могу получить доступ к текущему запросу пользователя?

Ответы [ 3 ]

16 голосов
/ 15 июня 2015

Примечание: если вы используете представления на основе классов (CBV), то передача дополнительного аргумента в конструкторе формы (например, в get_forms_class) или в form_class не будет работать, так как будет отображаться <form> object is not callable.

Решением для CBV является использование get_form_kwargs, например:

views.py:

# Sending user object to the form, to verify which fields to display/remove (depending on group)
def get_form_kwargs(self):
    kwargs = super(MyView, 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']
16 голосов
/ 04 сентября 2011

Вы можете передать пользовательский объект в качестве дополнительного аргумента в конструкторе формы.

Например,

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 по своему желанию

2 голосов
/ 11 октября 2018

Мое небольшое дополнение,

У меня было требование, когда одно из полей выбора модели формы зависит от request.user, и мне потребовалось некоторое время, чтобы обдумать.

Идея в том, что

  1. вам необходим метод __init__ в классе формы модели,

  2. и вы получаете доступ к request или другим параметрам из аргументов метода __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 поля как нулевое, и его динамически назначается из конструктора позже ,

Взгляните на порядок операторов в приведенном выше коде

вы можете передать пользовательскую переменную из файла вида

form = CsvUploadForm(user=request.user)

или с другими данными POST, FILE, как показано ниже

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