Risposte:
La risposta di Ber - memorizzandola in threadlocals - è una pessima idea. Non c'è assolutamente alcun motivo per farlo in questo modo.
Un modo migliore è quello di ignorare del form __init__metodo per prendere un argomento in più parole chiave, request. Questo memorizza la richiesta nel modulo , dove è richiesto e da dove puoi accedervi nel tuo metodo pulito.
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 ...
e secondo te:
myform = MyForm(request.POST, request=request)
AGGIORNATO 25/10/2011 : ora lo sto usando con una classe creata dinamicamente al posto del metodo, altrimenti Django 1.3 mostra alcune stranezze.
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
Quindi eseguire MyCustomForm.__init__l' override come segue:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
È quindi possibile accedere all'oggetto richiesta da qualsiasi metodo ModelFormcon self.request.
__new__kwargs di s che in seguito verrà passata al __init__metodo della classe . Il nome della classe ModelFormWithRequestpenso sia molto più chiaro nel suo significato rispetto a ModelFormMetaClass.
Per quello che vale, se stai usando viste basate su classi , invece di viste basate su funzioni, sovrascrivi get_form_kwargsnella tua vista di modifica. Codice di esempio per un CreateView personalizzato :
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
Il codice di visualizzazione precedente renderà requestdisponibile come uno degli argomenti della parola chiave per la __init__funzione di costruzione del modulo . Quindi nel tuo ModelFormfare:
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)
requestoggetto all'interno get_form_kwargs.
self.get_object? Il CreateViewestende il SingleObjectMixin. Ma se questo funziona o solleva un'eccezione dipende dal fatto che tu stia creando un nuovo oggetto o aggiornando uno esistente; cioè prova entrambi i casi (e ovviamente la cancellazione).
Il solito approccio consiste nell'archiviare l'oggetto richiesta in un riferimento locale al thread utilizzando un middleware. Quindi puoi accedervi da qualsiasi punto della tua app, incluso il metodo Form.clean ().
Cambiare la firma del metodo Form.clean () significa che hai la tua versione modificata di Django, che potrebbe non essere quella che desideri.
Grazie al conteggio middleware assomiglia a questo:
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
Registra questo middleware come descritto nella documentazione di Django
**kwargs, il che significa che dovrai passare l'oggetto richiesta come MyForm(request.POST, request=request).
Per l'amministratore di Django, in 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
Mi sono imbattuto in questo particolare problema durante la personalizzazione dell'amministratore. Volevo convalidare un determinato campo in base alle credenziali dell'amministratore.
Poiché non volevo modificare la vista per passare la richiesta come argomento al form, ho fatto quanto segue:
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=objnon obj=Nonesulla riga 11.
'function' object has no attribute 'base_fields'. Tuttavia, la risposta più semplice (senza chiusura) di @ François funziona senza problemi.
Non è sempre possibile utilizzare questo metodo (e probabilmente è una cattiva pratica), ma se si utilizza il modulo solo in una vista, è possibile esaminarlo all'interno del metodo di visualizzazione stesso.
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_classmetodo CBV , se so di dover fare molte cose con la richiesta. Potrebbe esserci un sovraccarico nella creazione ripetuta della classe, ma ciò la sposta semplicemente dal momento dell'importazione al tempo di esecuzione.
La risposta di Daniel Roseman è ancora la migliore. Tuttavia, utilizzerei il primo argomento posizionale per la richiesta invece dell'argomento parola chiave per alcuni motivi:
Infine, utilizzerei un nome più univoco per evitare di sovrascrivere una variabile esistente. Pertanto, la mia risposta modificata assomiglia a:
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 ...
formaggio fresco di cheesebaker @ pypi: django-requestprovider
Ho un'altra risposta a questa domanda in base alle tue esigenze per accedere all'utente nel metodo pulito del modulo. Puoi provare questo. 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)
Ora puoi accedere a self.instance in qualsiasi metodo pulito in form.py
Quando vuoi accedervi attraverso le viste di classe Django "preparate" come se CreateViewci fosse un piccolo trucco da sapere (= la soluzione ufficiale non funziona immediatamente). Nel tuo CreateView dovrai aggiungere un codice come questo:
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
= in breve questa è la soluzione da passare requestal tuo form con le viste Crea / Aggiorna di Django.