Bir formun temiz yöntemi için request.user yapmaya çalışıyorum, ancak istek nesnesine nasıl erişebilirim? Değişken girdisine izin vermek için temiz yöntemi değiştirebilir miyim?
Yanıtlar:
Ber'in cevabı - bunu threadlocals'da saklamak - çok kötü bir fikir. Bunu bu şekilde yapmak için kesinlikle hiçbir neden yok.
Çok daha iyi bir yol, __init__
ekstra bir anahtar kelime argümanı almak için formun yöntemini geçersiz kılmaktır request
. Bu, isteği formda , gerektiği yerde ve temiz yönteminizde erişebileceğiniz yerden depolar .
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 ...
ve size göre:
myform = MyForm(request.POST, request=request)
GÜNCELLENMİŞ 10/25/2011 : Şimdi bunu yöntem yerine dinamik olarak oluşturulmuş bir sınıfla kullanıyorum, çünkü Django 1.3 başka türlü bazı tuhaflıklar gösteriyor.
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
Ardından MyCustomForm.__init__
aşağıdaki gibi geçersiz kılın :
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Daha sonra herhangi yönteminden istek nesnesi erişebilirsiniz ModelForm
ile self.request
.
__new__
kılınır, daha sonra sınıfın __init__
yöntemine geçecek olan 's kwargs'a istek eklersiniz . Sınıfı adlandırmaktan ModelFormWithRequest
çok daha net olduğunu düşünüyorum ModelFormMetaClass
.
Değeri ne olursa olsun , işlev tabanlı görünümler yerine Sınıf Tabanlı Görünümler kullanıyorsanız get_form_kwargs
, düzenleme görünümünüzde geçersiz kılın . Özel bir CreateView için örnek kod :
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
Yukarıdaki görünüm kodu request
, formun __init__
yapıcı işlevi için anahtar sözcük bağımsız değişkenlerinden biri olarak kullanılabilir hale getirecektir . Bu nedenle sizin işinizde 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
nesnenin get_form_kwargs
otomatik olarak içinde olmasını sağlayıp sağlamadığından emin değilim .
self.get_object
? CreateView
Uzanır SingleObjectMixin
. Ancak bunun işe yarayıp yaramayacağı veya bir istisnayı ortaya çıkarması, yeni bir nesne oluşturmanıza veya mevcut bir nesneyi güncellemenize bağlıdır; yani her iki durumu da test edin (ve tabii ki silme).
Genel yaklaşım, istek nesnesini bir ara yazılım kullanarak yerel bir evre başvurusunda depolamaktır. Ardından buna, Form.clean () yöntemi dahil olmak üzere uygulamanızın herhangi bir yerinden erişebilirsiniz.
Form.clean () yönteminin imzasını değiştirmek, Django'nun sizin istediğiniz, değiştirilmiş bir sürümüne sahip olduğunuz anlamına gelir.
Teşekkür ederim ara yazılım sayısı şuna benzer:
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
Bu ara yazılımı Django belgelerinde açıklandığı gibi kaydedin
**kwargs
, anahtar kelime argümanları kullandığını , bu da istek nesnesini olarak iletmeniz gerektiği anlamına gelir MyForm(request.POST, request=request)
.
Django yöneticisi için, Django 1.8'de
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
Yöneticiyi özelleştirirken bu sorunla karşılaştım. Belirli bir alanın, belirli yöneticinin kimlik bilgilerine göre doğrulanmasını istedim.
İsteği forma bir argüman olarak iletmek için görünümü değiştirmek istemediğim için, şunu yaptım:
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
değil obj=None
.
'function' object has no attribute 'base_fields'
. Ancak, daha basit (sonuçsuz) @ François cevabı sorunsuz çalışıyor.
Bu yöntemi her zaman kullanamazsınız (ve muhtemelen kötü uygulamasıdır), ancak formu yalnızca tek bir görünümde kullanıyorsanız, onu görünüm yönteminin kendi içinde kapsama alabilirsiniz.
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
birçok şey yapmam gerektiğini biliyorsam, bunu genellikle bir CBV yönteminde yapıyorum. Sınıfı tekrar tekrar oluşturmanın bazı ek yükleri olabilir, ancak bu onu içeri aktarma zamanından çalışma zamanına taşır.
Daniel Roseman'ın cevabı hala en iyisidir. Ancak, birkaç nedenden ötürü anahtar kelime argümanı yerine istek için ilk konumsal argümanı kullanırdım:
Son olarak, mevcut bir değişkeni geçersiz kılmaktan kaçınmak için daha benzersiz bir ad kullanacağım. Böylece, değiştirilmiş cevabım şöyle görünür:
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'dan taze peynir @ pypi: django-requestprovider
Gereksiniminize göre bu soruya başka bir cevabım var, kullanıcıya formun temiz yöntemine erişmek istersiniz. Bunu deneyebilirsiniz. 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)
Artık self.instance'e form.py'deki herhangi bir temiz yöntemle erişebilirsiniz.
Buna CreateView
, bilinmesi gereken küçük bir numara varmış gibi "hazırlanmış" Django sınıfı görünümleri aracılığıyla erişmek istediğinizde (= resmi çözüm kutudan çıkmaz). Kendi başınıza aşağıdaki CreateView
gibi bir kod eklemeniz gerekecek:
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
= kısaca bu, request
Django'nun Oluştur / Güncelle görünümleri ile formunuza geçmenin çözümüdür .