Как мне получить доступ к объекту запроса или любой другой переменной в методе clean () формы? - PullRequest
90 голосов
/ 29 июня 2009

Я пытаюсь запросить .user для чистого метода формы, но как я могу получить доступ к объекту запроса? Могу ли я изменить метод clean, чтобы разрешить ввод переменных?

Ответы [ 10 ]

144 голосов
/ 29 июня 2009

Ответ Бер - хранение его в локальных потоках - очень плохая идея. Нет абсолютно никакой причины делать это таким образом.

Гораздо лучший способ - переопределить метод формы __init__, чтобы получить дополнительный аргумент ключевого слова, request. При этом запрос сохраняется в форме , где он требуется и откуда вы можете получить к нему доступ чистым методом.

class MyForm(forms.Form):

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


    def clean(self):
        ... access the request object via self.request ...

и по вашему мнению:

myform = MyForm(request.POST, request=request)
30 голосов
/ 19 мая 2011

ОБНОВЛЕНО 10/25/2011 : сейчас я использую это с метаклассом вместо метода, поскольку Django 1.3 отображает некоторые странности в противном случае.

class MyModelAdmin(admin.ModelAdmin):
    form = MyCustomForm
    def get_form(self, request, obj=None, **kwargs):
        ModelForm = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
        class ModelFormMetaClass(ModelForm):
            def __new__(cls, *args, **kwargs):
                kwargs['request'] = request
                return ModelForm(*args, **kwargs)
        return ModelFormMetaClass

Затем переопределите MyCustomForm.__init__ следующим образом:

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

Затем вы можете получить доступ к объекту запроса из любого метода ModelForm с помощью self.request.

27 голосов
/ 19 сентября 2014

Для чего стоит, если вы используете Представления на основе классов , вместо представлений на основе функций переопределите get_form_kwargs в представлении редактирования. Пример кода для пользовательского CreateView :

from braces.views import LoginRequiredMixin

class MyModelCreateView(LoginRequiredMixin, CreateView):
    template_name = 'example/create.html'
    model = MyModel
    form_class = MyModelForm
    success_message = "%(my_object)s added to your site."

    def get_form_kwargs(self):
        kw = super(MyModelCreateView, self).get_form_kwargs()
        kw['request'] = self.request # the trick!
        return kw

    def form_valid(self):
        # do something

Приведенный выше код представления сделает request доступным в качестве одного из ключевых аргументов функции конструктора __init__ формы. Поэтому в вашем ModelForm делайте:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        # important to "pop" added kwarg before call to parent's constructor
        self.request = kwargs.pop('request')
        super(MyModelForm, self).__init__(*args, **kwargs)
16 голосов
/ 29 июня 2009

Обычный подход заключается в сохранении объекта запроса в локальной ссылке потока с использованием промежуточного программного обеспечения. Затем вы можете получить к нему доступ из любого места вашего приложения, включая метод Form.clean ().

Изменение подписи метода Form.clean () означает, что у вас есть собственная модифицированная версия Django, которая может не соответствовать вашей.

Спасибо, подсчет промежуточного программного обеспечения выглядит примерно так:

import threading
_thread_locals = threading.local()

def get_current_request():
    return getattr(_thread_locals, 'request', None)

class ThreadLocals(object):
    """
    Middleware that gets various objects from the
    request object and saves them in thread local storage.
    """
    def process_request(self, request):
        _thread_locals.request = request

Зарегистрируйте это промежуточное ПО, как описано в Django документах

11 голосов
/ 17 ноября 2015

Для администратора Django, в Django 1.8

class MyModelAdmin(admin.ModelAdmin):
    ...
    form = RedirectForm

    def get_form(self, request, obj=None, **kwargs):
        form = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
        form.request = request
        return form
7 голосов
/ 14 мая 2011

Я столкнулся с этой конкретной проблемой при настройке администратора. Я хотел, чтобы определенное поле было проверено на основе учетных данных конкретного администратора.

Поскольку я не хотел изменять представление для передачи запроса в качестве аргумента в форму, я сделал следующее:

class MyCustomForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def clean(self):
        # make use of self.request here

class MyModelAdmin(admin.ModelAdmin):
    form = MyCustomForm
    def get_form(self, request, obj=None, **kwargs):
        ModelForm = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
        def form_wrapper(*args, **kwargs):
            a = ModelForm(*args, **kwargs)
            a.request = request
            return a
    return form_wrapper
5 голосов
/ 07 июня 2013

Ответ Даниэль Роузман по-прежнему лучший. Однако я бы использовал первый позиционный аргумент для запроса вместо ключевого аргумента по нескольким причинам:

  1. Вы не рискуете переопределить kwarg с тем же именем
  2. Запрос необязательный, что неверно. Атрибут запроса никогда не должен быть None в этом контексте.
  3. Вы можете аккуратно передать args и kwargs родительскому классу без необходимости их изменения.

Наконец, я бы использовал более уникальное имя, чтобы избежать переопределения существующей переменной. Таким образом, мой измененный ответ выглядит так:

class MyForm(forms.Form):

  def __init__(self, request, *args, **kwargs):
      self._my_request = request
      super(MyForm, self).__init__(*args, **kwargs)


  def clean(self):
      ... access the request object via self._my_request ...
5 голосов
/ 02 апреля 2010

Вы не можете всегда использовать этот метод (и, вероятно, это плохая практика), но если вы используете форму только в одном представлении, вы можете использовать его внутри самого метода представления.

def my_view(request):

    class ResetForm(forms.Form):
        password = forms.CharField(required=True, widget=forms.PasswordInput())

        def clean_password(self):
            data = self.cleaned_data['password']
            if not request.user.check_password(data):
                raise forms.ValidationError("The password entered does not match your account password.")
            return data

    if request.method == 'POST':
        form = ResetForm(request.POST, request.FILES)
        if form.is_valid():

            return HttpResponseRedirect("/")
    else:
        form = ResetForm()

    return render_to_response(request, "reset.html")
3 голосов
/ 02 апреля 2012

У меня есть другой ответ на этот вопрос, согласно вашему требованию, вы хотите получить доступ к пользователю в чистом методе формы. Вы можете попробовать это. View.py

person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)

forms.py

def __init__(self,*arg,**kwargs):
    self.instance=kwargs.get('instance',None)
    if kwargs['instance'] is not None:
        del kwargs['instance']
    super(Myform, self).__init__(*args, **kwargs)

Теперь вы можете получить доступ к self.instance любым чистым методом в form.py

3 голосов
/ 20 июня 2011

свежий сыр из чизбейкера @ pypi: django-requestprovider

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...