tags:

views:

1017

answers:

3

I am trying to request.user for a form's clean method, but how can I access the request object? Can I modify the clean method to allow variables input?

Thanks.

+4  A: 

The usual aproach is to store the request object in a thread-local reference using a middleware. Then you can access this from anywhere in you app, including the Form.clean() method.

Changing the signature of the Form.clean() method means you have you own, modified version of Django, which may not be what you want.

Thank middleware count look something like this:

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

Register this middleware as described in the Django docs

Ber
Despite the above comments, this method works whereas the other method does not. Setting an attribute of the form object in __init__ does not reliably carry over to clean methods, whereas setting the thread locals does allow this data to be carried over.
rplevy
+9  A: 

The answer by Ber - storing it in threadlocals - is a very bad idea. There's absolutely no reason to do it this way.

A much better way is to override the form's __init__ method to take an extra keyword argument, request. This stores the request in the form, where it's required, and from where you can access it in your clean method.

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 ...

and in your view:

myform = MyForm(request.POST, request=request)
Daniel Roseman
You are right in this case. However, it may not be desired to modified Forms/Views in this was. Also, there are use cases for thread local store where adding method parameters or instance variables is impossible. Think about callable argument to a query filter that needs access to request data. You can neither add a parameter to the call, nor is there any instance to reference.
Ber
this is perfect, thanks. threadlocals is useful tho, in the instance of overriding model's save methods whereby request is useful.
nubela
A: 

You can't always use this method (and its probably bad practice), but if you are only using the form in one view you could scope it inside the view method itself.

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