[python] 양식의 clean () 메서드에서 요청 객체 또는 다른 변수에 어떻게 액세스합니까?

양식의 정리 메서드에 대한 request.user를 시도하고 있지만 요청 개체에 어떻게 액세스 할 수 있습니까? 변수 입력을 허용하도록 clean 메서드를 수정할 수 있습니까?



답변

Ber의 대답 (threadlocals에 저장)은 매우 나쁜 생각입니다. 이런 식으로 할 이유가 전혀 없습니다.

훨씬 더 좋은 방법은 __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)


답변

UPDATED 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 ModelFormWithRequest(ModelForm):
            def __new__(cls, *args, **kwargs):
                kwargs['request'] = request
                return ModelForm(*args, **kwargs)
        return ModelFormWithRequest

그런 다음 다음 MyCustomForm.__init__과 같이 재정의 합니다.

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

그런 다음 ModelFormwith의 모든 메소드에서 요청 객체에 액세스 할 수 있습니다 self.request.


답변

기능 기반 뷰 대신 클래스 기반 뷰를 사용하는 경우 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)


답변

일반적인 방법은 미들웨어를 사용하여 스레드 로컬 참조에 요청 객체를 저장하는 것입니다. 그런 다음 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 문서에 설명 된 대로이 미들웨어를 등록하십시오.


답변

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


답변

관리자를 사용자 정의 할 때이 특정 문제가 발생했습니다. 특정 관리자의 자격 증명을 기반으로 특정 필드의 유효성을 검사하기를 원했습니다.

요청을 양식에 대한 인수로 전달하도록보기를 수정하고 싶지 않았기 때문에 다음과 같이했습니다.

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


답변

항상이 방법을 사용할 수있는 것은 아니지만 (아마도 나쁜 습관 일 것입니다), 하나의 뷰에서만 양식을 사용하는 경우 뷰 메서드 자체 내에서 범위를 지정할 수 있습니다.

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")