Antworten:
Die Antwort von Ber - es in Threadlocals zu speichern - ist eine sehr schlechte Idee. Es gibt absolut keinen Grund, dies so zu tun.
Eine viel bessere Möglichkeit besteht darin, die __init__Methode des Formulars zu überschreiben , um ein zusätzliches Schlüsselwortargument zu verwenden request. Dadurch wird die Anforderung im Formular gespeichert , wo sie benötigt wird und von wo aus Sie mit Ihrer Bereinigungsmethode darauf zugreifen können.
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 ...
und aus Ihrer Sicht:
myform = MyForm(request.POST, request=request)
AKTUALISIERT am 25.10.2011 : Ich verwende dies jetzt mit einer dynamisch erstellten Klasse anstelle einer Methode, da Django 1.3 ansonsten etwas seltsam ist.
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
Dann überschreiben Sie MyCustomForm.__init__wie folgt:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Sie können dann von einer beliebigen Methode ModelFormmit auf das Anforderungsobjekt zugreifen self.request.
__new__kwargs eine Anfrage hinzu, die später an die __init__Methode der Klasse übergeben wird. ModelFormWithRequestIch nenne die Klasse viel klarer in ihrer Bedeutung als ModelFormMetaClass.
Wenn Sie klassenbasierte Ansichten anstelle von funktionsbasierten Ansichten verwenden, überschreiben Sie diese get_form_kwargsin Ihrer Bearbeitungsansicht. Beispielcode für eine benutzerdefinierte 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
Der obige Ansichtscode wird requestals eines der Schlüsselwortargumente für die __init__Konstruktorfunktion des Formulars verfügbar gemacht . Deshalb in Ihrem ModelFormdo:
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)
requestObjekt get_form_kwargsautomatisch enthalten ist.
self.get_object? Das CreateViewerweitert die SingleObjectMixin. Ob dies funktioniert oder eine Ausnahme auslöst, hängt davon ab, ob Sie ein neues Objekt erstellen oder ein vorhandenes aktualisieren. dh beide Fälle testen (und natürlich löschen).
Der übliche Ansatz besteht darin, das Anforderungsobjekt mithilfe einer Middleware in einer threadlokalen Referenz zu speichern. Dann können Sie von überall in Ihrer App darauf zugreifen, einschließlich der Form.clean () -Methode.
Wenn Sie die Signatur der Form.clean () -Methode ändern, haben Sie eine eigene, geänderte Version von Django, die möglicherweise nicht Ihren Wünschen entspricht.
Vielen Dank, dass die Anzahl der Middleware ungefähr so aussieht:
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
Registrieren Sie diese Middleware wie in den Django-Dokumenten beschrieben
**kwargsbedeutet, dass Sie das Anforderungsobjekt als übergeben müssen MyForm(request.POST, request=request).
Für Django-Administrator 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
Ich bin beim Anpassen des Administrators auf dieses spezielle Problem gestoßen. Ich wollte, dass ein bestimmtes Feld basierend auf den Anmeldeinformationen des jeweiligen Administrators überprüft wird.
Da ich die Ansicht nicht ändern wollte, um die Anforderung als Argument an das Formular zu übergeben, habe ich Folgendes getan:
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=objnicht obj=Nonein Zeile 11.
'function' object has no attribute 'base_fields'. Die einfachere (ohne Abschluss) @ François-Antwort funktioniert jedoch reibungslos.
Sie können diese Methode nicht immer verwenden (und es ist wahrscheinlich eine schlechte Vorgehensweise), aber wenn Sie das Formular nur in einer Ansicht verwenden, können Sie es innerhalb der Ansichtsmethode selbst erfassen.
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_classMethode, wenn ich weiß, dass ich mit der Anfrage viele Dinge tun muss. Das wiederholte Erstellen der Klasse kann mit einem gewissen Aufwand verbunden sein, der jedoch nur von der Importzeit zur Laufzeit verschoben wird.
Die Antwort von Daniel Roseman ist immer noch die beste. Ich würde jedoch aus einigen Gründen das erste Positionsargument für die Anforderung anstelle des Schlüsselwortarguments verwenden:
Zuletzt würde ich einen eindeutigeren Namen verwenden, um zu vermeiden, dass eine vorhandene Variable überschrieben wird. Meine modifizierte Antwort sieht also so aus:
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 ...
Frischkäse von Cheesebaker @ Pypi: Django-Requestprovider
Ich habe eine andere Antwort auf diese Frage gemäß Ihrer Anforderung, dass Sie auf den Benutzer über die saubere Methode des Formulars zugreifen möchten. Sie können dies versuchen. 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)
Jetzt können Sie in jeder sauberen Methode in form.py auf die self.instance zugreifen
Wenn Sie über "vorbereitete" Django-Klassenansichten darauf zugreifen möchten, CreateViewist ein kleiner Trick zu kennen (= die offizielle Lösung funktioniert nicht sofort). In Ihrem eigenen müssen CreateView Sie Code wie folgt hinzufügen:
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
= Kurz gesagt, dies ist die Lösung, die requestSie mit den Ansichten "Erstellen / Aktualisieren" von Django an Ihr Formular übergeben können.