¿Cómo accedo al objeto de solicitud o cualquier otra variable en el método clean () de un formulario?

Estoy tratando de solicitar.usuario para el método limpio de un formulario, pero ¿cómo puedo acceder al objeto de solicitud? ¿Puedo modificar el método de limpieza para permitir el ingreso de variables?

La respuesta de Ber, almacenarla en threadlocals, es una muy mala idea. No hay absolutamente ninguna razón para hacerlo de esta manera.

Una forma mucho mejor es anular el método __init__ del __init__ 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 de limpieza.

 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 su opinión:

 myform = MyForm(request.POST, request=request) 

ACTUALIZADO 25/10/2011 : Ahora estoy usando esto con una metaclase en lugar de un método, ya que Django 1.3 muestra algo extraño 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 ModelFormMetaClass(ModelForm): def __new__(cls, *args, **kwargs): kwargs['request'] = request return ModelForm(*args, **kwargs) return ModelFormMetaClass 

Luego anule 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 con self.request .

Para lo que vale la pena, si está utilizando vistas basadas en clase , 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 hará que la request esté disponible como uno de los argumentos de palabras clave para la función de constructor __init__ del __init__ . Por eso en tu ModelForm haz:

 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) 

El enfoque habitual es almacenar el objeto de solicitud en una referencia de subproceso local utilizando un middleware. Luego, puede acceder a esto desde cualquier parte de su aplicación, incluido el método Form.clean ().

Cambiar la firma del método Form.clean () significa que tienes tu propia versión modificada de Django, que puede no ser lo que quieres.

Gracias a la cuenta de middleware se ve algo como esto:

 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 la documentación de Django.

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 

No siempre puede usar este método (y es probable que sea una mala práctica), pero si solo está usando el formulario en una vista, podría incluirlo dentro del mismo método de vista.

 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") 

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 varias razones:

  1. No corres el riesgo de anular un kwarg con el mismo nombre
  2. La solicitud es opcional que no es correcta. El atributo de solicitud nunca debe ser Ninguno en este contexto.
  3. Puede pasar de forma limpia los argumentos y kwargs a la clase principal sin tener que modificarlos.

Por último, usaría un nombre más exclusivo para evitar anular una variable existente. Por lo tanto, Mi respuesta modificada se ve como:

 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 requerimiento: desea acceder al usuario al método de limpieza del formulario. Puedes probar esto. 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) 

Ahora puede acceder a la instancia de self en cualquier método limpio en form.py