Respuestas:
La respuesta de Ber, almacenarlo en threadlocals, es una muy mala idea. No hay absolutamente ninguna razón para hacerlo de esta manera.
Una mejor manera es mucho para anular de forma __init__
método para tomar un argumento de palabra clave adicional, request
. Esto almacena la solicitud en el formulario , donde se requiere y desde donde puede acceder a ella en su método limpio.
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 ...
y en tu opinión:
myform = MyForm(request.POST, request=request)
ACTUALIZADO 25/10/2011 : ahora estoy usando esto con una clase creada dinámicamente en lugar de un método, ya que Django 1.3 muestra algunas rarezas de lo contrario.
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
Luego anule de la MyCustomForm.__init__
siguiente manera:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Luego puede acceder al objeto de solicitud desde cualquier método de ModelForm
with self.request
.
__new__
los kwargs que más adelante se pasarán al __init__
método de la clase . Nombrar la clase ModelFormWithRequest
creo que es mucho más claro en su significado que ModelFormMetaClass
.
Por lo que vale, si está utilizando vistas basadas en clases , en lugar de vistas basadas en funciones, anule get_form_kwargs
en su vista de edición. Código de ejemplo para un CreateView personalizado :
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
El código de vista anterior estará request
disponible como uno de los argumentos de palabra clave para la __init__
función constructora del formulario . Por lo tanto, en tu ModelForm
hacer:
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
objeto dentro get_form_kwargs
automáticamente.
self.get_object
? El CreateView
extiende el SingleObjectMixin
. Pero si esto funciona o genera una excepción depende de si está creando un nuevo objeto o actualizando uno existente; es decir, probar ambos casos (y supresión, por supuesto).
El enfoque habitual es almacenar el objeto de solicitud en una referencia local de subproceso utilizando un middleware. Luego, puede acceder a esto desde cualquier lugar de su aplicación, incluido el método Form.clean ().
Cambiar la firma del método Form.clean () significa que tiene su propia versión modificada de Django, que puede no ser la que desea.
Gracias, el recuento de middleware se ve así:
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
Registre este middleware como se describe en los documentos de Django
**kwargs
, lo que significa que tendrá que pasar el objeto de solicitud como MyForm(request.POST, request=request)
.
Para el administrador de Django, en 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
Me encontré con este problema en particular al personalizar el administrador. Quería que un determinado campo fuera validado en función de las credenciales del administrador en particular.
Como no quería modificar la vista para pasar la solicitud como un argumento al formulario, lo siguiente es lo que hice:
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
no obj=None
en la línea 11.
'function' object has no attribute 'base_fields'
. Sin embargo, la respuesta de @ François más simple (sin cierre) funciona sin problemas.
No siempre puede usar este método (y probablemente sea una mala práctica), pero si solo está usando el formulario en una vista, puede ubicarlo dentro del método de vista en sí.
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
método CBV , si sé que necesito hacer muchas cosas con la solicitud. Puede haber algunos gastos generales al crear repetidamente la clase, pero eso simplemente la mueve del tiempo de importación al tiempo de ejecución.
La respuesta de Daniel Roseman sigue siendo la mejor. Sin embargo, usaría el primer argumento posicional para la solicitud en lugar del argumento de palabra clave por algunas razones:
Por último, usaría un nombre más exclusivo para evitar anular una variable existente. Por lo tanto, mi respuesta modificada se ve así:
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 ...
queso fresco de cheesebaker @ pypi: django-requestprovider
Tengo otra respuesta a esta pregunta según su requisito de que desee acceder al usuario al método limpio del formulario. Puedes probar esto. View.py
person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)
formularios.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)
Ahora puede acceder a self.instance en cualquier método limpio en form.py
Cuando desee acceder a él a través de vistas de clase de Django "preparadas" como si CreateView
hubiera un pequeño truco para saber (= la solución oficial no funciona de inmediato). En el suyo CreateView
, tendrá que agregar un código como este:
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
= en resumen, esta es la solución para pasar request
a su formulario con las vistas Crear / Actualizar de Django.