답변:
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)
그런 다음 ModelForm
with의 모든 메소드에서 요청 객체에 액세스 할 수 있습니다 self.request
.
__new__
나중에 클래스의 __init__
메서드에 전달되는의 kwargs 에 요청을 추가 합니다. 클래스 이름을 지정하는 ModelFormWithRequest
것보다 의미가 훨씬 더 명확하다고 생각 ModelFormMetaClass
합니다.
기능 기반 뷰 대신 클래스 기반 뷰를 사용하는 경우 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)
request
객체를 get_form_kwargs
자동으로 포함 하는지 여부는 확실하지 않습니다 .
self.get_object
합니까? 는 CreateView
을 확장합니다 SingleObjectMixin
. 그러나 이것이 작동하는지 아니면 예외가 발생하는지 여부는 새 객체를 생성하는지 또는 기존 객체를 업데이트하는지에 따라 다릅니다. 즉, 두 경우 모두 테스트 (물론 삭제).
일반적인 방법은 미들웨어를 사용하여 스레드 로컬 참조에 요청 객체를 저장하는 것입니다. 그런 다음 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 문서에 설명 된 대로이 미들웨어를 등록하십시오.
**kwargs
요청 객체를 MyForm(request.POST, request=request)
.
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
obj=obj
아닙니다 obj=None
.
'function' object has no attribute 'base_fields'
합니다. 그러나 더 간단한 (닫지 않고) @ François 대답은 원활하게 작동합니다.
항상이 방법을 사용할 수있는 것은 아니지만 (아마도 나쁜 습관 일 것입니다), 하나의 뷰에서만 양식을 사용하는 경우 뷰 메서드 자체 내에서 범위를 지정할 수 있습니다.
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")
get_form_class
요청에 대해 많은 일을해야한다는 것을 안다면 CBV 방법 으로이 작업을 자주 수행합니다 . 클래스를 반복적으로 생성하는 데 약간의 오버 헤드가있을 수 있지만 가져 오기 시간에서 런타임으로 이동합니다.
Daniel Roseman 의 대답 은 여전히 최고입니다. 그러나 몇 가지 이유로 키워드 인수 대신 요청에 첫 번째 위치 인수를 사용합니다.
마지막으로 기존 변수를 덮어 쓰지 않도록보다 고유 한 이름을 사용합니다. 따라서 내 수정 된 대답은 다음과 같습니다.
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 ...
cheesebaker @ pypi의 신선한 치즈 : django-requestprovider
사용자가 양식의 깨끗한 방법에 액세스하려는 요구 사항에 따라이 질문에 대한 또 다른 답변이 있습니다. 이것을 시도 할 수 있습니다. 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)
이제 form.py의 깨끗한 메소드에서 self.instance에 액세스 할 수 있습니다.
CreateView
알아야 할 작은 트릭이있는 것처럼 "준비된"Django 클래스 뷰를 통해 액세스하려고 할 때 (= 공식 솔루션은 즉시 작동하지 않습니다). 다음 CreateView
과 같은 코드를 직접 추가해야합니다.
class MyCreateView(LoginRequiredMixin, CreateView):
form_class = MyOwnForm
template_name = 'my_sample_create.html'
def get_form_kwargs(self):
result = super().get_form_kwargs()
result['request'] = self.request
return result
= 간단히 말해 이것은 request
Django의 Create / Update 뷰를 사용하여 양식 에 전달하는 솔루션 입니다.