Jawaban:
Jawaban oleh Ber - menyimpannya di threadlocals - adalah ide yang sangat buruk. Sama sekali tidak ada alasan untuk melakukannya dengan cara ini.
Cara yang jauh lebih baik adalah mengganti metode formulir __init__untuk mengambil argumen kata kunci tambahan request,. Ini menyimpan permintaan dalam bentuk , jika diperlukan, dan dari mana Anda dapat mengaksesnya dalam metode bersih Anda.
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 ...
dan menurut pandangan Anda:
myform = MyForm(request.POST, request=request)
DIPERBARUI 25/10/2011 : Saya sekarang menggunakan ini dengan kelas yang dibuat secara dinamis daripada metode, karena Django 1.3 menampilkan beberapa keanehan sebaliknya.
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
Kemudian timpa MyCustomForm.__init__sebagai berikut:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Anda kemudian dapat mengakses objek permintaan dari metode apa pun ModelFormdengan self.request.
__new__kwargs yang nantinya akan diteruskan ke metode kelas __init__. Penamaan kelas ModelFormWithRequestmenurut saya jauh lebih jelas dalam maknanya daripada ModelFormMetaClass.
Untuk apa nilainya, jika Anda menggunakan Tampilan Berbasis Kelas , alih-alih tampilan berbasis fungsi, timpa get_form_kwargsdalam tampilan pengeditan Anda. Contoh kode untuk CreateView kustom :
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
Kode tampilan di atas akan requesttersedia sebagai salah satu argumen kata kunci untuk __init__fungsi konstruktor formulir . Karena itu dalam pekerjaan Anda 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)
requestobjek get_form_kwargssecara otomatis.
self.get_object? The CreateViewmemperpanjang SingleObjectMixin. Tetapi apakah ini berfungsi atau memunculkan pengecualian bergantung pada apakah Anda membuat objek baru atau memperbarui yang sudah ada; yaitu menguji kedua kasus (dan tentu saja penghapusan).
Pendekatan biasa adalah menyimpan objek permintaan dalam referensi lokal-thread menggunakan middleware. Kemudian Anda bisa mengakses ini dari mana saja di aplikasi Anda, termasuk metode Form.clean ().
Mengubah tanda tangan dari metode Form.clean () berarti Anda memiliki versi Django yang telah Anda modifikasi, yang mungkin bukan yang Anda inginkan.
Terima middleware count terlihat seperti ini:
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
Daftarkan middleware ini seperti yang dijelaskan dalam dokumen Django
**kwargs, yang berarti Anda harus meneruskan objek permintaan sebagai MyForm(request.POST, request=request).
Untuk admin Django, di 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
Saya mengalami masalah khusus ini saat menyesuaikan admin. Saya ingin bidang tertentu divalidasi berdasarkan kredensial admin tertentu.
Karena saya tidak ingin mengubah tampilan untuk meneruskan permintaan sebagai argumen ke formulir, berikut ini yang saya lakukan:
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=objtidak obj=Nonedi baris 11.
'function' object has no attribute 'base_fields'. Namun, jawaban @ François yang lebih sederhana (tanpa penutupan) bekerja dengan lancar.
Anda tidak dapat selalu menggunakan metode ini (dan mungkin praktiknya yang buruk), tetapi jika Anda hanya menggunakan formulir dalam satu tampilan, Anda dapat mencakupnya di dalam metode tampilan itu sendiri.
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_classmetode CBV , jika saya tahu saya perlu melakukan banyak hal dengan permintaan tersebut. Mungkin ada beberapa overhead dalam membuat kelas berulang kali, tetapi itu hanya memindahkannya dari waktu impor ke waktu proses.
Jawaban Daniel Roseman masih yang terbaik. Namun, saya akan menggunakan argumen posisi pertama untuk permintaan tersebut, bukan argumen kata kunci karena beberapa alasan:
Terakhir, saya akan menggunakan nama yang lebih unik untuk menghindari menimpa variabel yang ada. Jadi, jawaban saya yang dimodifikasi terlihat seperti:
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 ...
keju segar dari cheesebaker @ pypi: django-requestprovider
Saya punya jawaban lain untuk pertanyaan ini sesuai kebutuhan Anda, Anda ingin mengakses pengguna ke metode bersih formulir. Anda bisa mencoba ini. 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)
Sekarang Anda dapat mengakses self.instance dalam metode bersih apa pun di form.py
Ketika Anda ingin mengaksesnya melalui tampilan kelas Django yang "disiapkan" seperti CreateViewada trik kecil untuk diketahui (= solusi resmi tidak bekerja di luar kotak). Di Anda sendiri, CreateView Anda harus menambahkan kode seperti ini:
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
= singkatnya ini adalah solusi untuk meneruskan requestke formulir Anda dengan tampilan Buat / Perbarui Django.