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?
11 Answers
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)

- 588,541
- 66
- 880
- 895
-
4You 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 Jun 29 '09 at 14:18
-
this is perfect, thanks. threadlocals is useful tho, in the instance of overriding model's save methods whereby request is useful. – nubela Jun 30 '09 at 09:17
-
4It isn't useful when you are extending an admin form, because you can init your form passing the request var. Any idea¿? – Mordi May 26 '11 at 08:48
-
15Why do you say using thread-local storage is a very bad idea? It avoids having to drop the code for passing the request around everywhere. – Michael Mior Dec 22 '11 at 18:43
-
9I wouldn't pass the request object itself to the form, but rather the fields of request that you need (ie user), otherwise you tie your form logic to the request/response cycle which makes testing harder. – Andrew Ingram Jan 29 '13 at 10:34
-
2Chris Pratt has a good solution too, for when dealing with forms in admin.ModelAdmin – radtek Jan 08 '15 at 18:25
-
1`kwargs.pop('request', None)` returns None for me on Django 1.10. I printed kwargs and it doesnt have the request object at all. Did something for Django 1.10? – Anupam Jul 21 '17 at 10:31
-
2@Anupam you need to pass that kwarg in the view, as I show in the second snippet. – Daniel Roseman Jul 21 '17 at 10:33
-
1The solution given by Ber is good if your logic lies in a reusable component (a custom field type), which should be seeminglessly replaceable by the user. – Luis Masuelli Oct 30 '17 at 19:18
-
When you want to access it throught "prepared" Django class views like `CreateView` there's a small trick to know (= your solution doesn't work out of the box) – Olivier Pons Apr 17 '20 at 14:15
For what it's worth, if you're using Class Based Views, instead of function based views, override get_form_kwargs
in your editing view. Example code for a custom 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
The above view code will make request
available as one of the keyword arguments to the form's __init__
constructor function. Therefore in your ModelForm
do:
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)

- 14,760
- 10
- 76
- 102
-
1This worked for me. I make the note because I was using get_form_kwargs anyway due to complex WizardForm logic. No other answer I've seen accounted for WizardForm. – datakid Oct 03 '14 at 05:36
-
2Does anyone besides me think this is just a big mess to do something that's pretty rudimentary for a web framework? Django is great but this makes me not want to use CBV at all, ever. – trpt4him Jul 20 '17 at 15:06
-
1IMHO the benefits of CBVs outweigh the drawbacks of FBVs by far, especially if you work on a large project with 25+ devs writing code that aims for 100% unit test coverage. Not sure if newer versions of Django cater for having the `request` object within `get_form_kwargs` automatically. – Joseph Victor Zammit Jul 20 '17 at 16:59
-
In similar vein, is there any way to access the object instance's ID in get_form_kwargs? – Hassan Baig Mar 01 '18 at 00:22
-
1@HassanBaig Possibly using `self.get_object`? The `CreateView` extends the [`SingleObjectMixin`](https://docs.djangoproject.com/en/1.7/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin). But whether this works or raises an exception depends on whether you're creating a new object or updating an existing one; i.e. test both cases (and deletion of course). – Joseph Victor Zammit Mar 22 '18 at 15:24
-
It's more readable to include the additional argument explicitly in the signature: `def __init__(self, *args, request=None, **kwargs)` puts the argument value straight into the parameter, with no need for a `pop`. Then you. just need `self.request = request`. – holdenweb May 25 '23 at 07:57
-
@holdenweb I agree it makes the `pop` redundant. But then we're changing the signature of the `__init__` constructor, making it different from what's found "up" the hierarchy. So it's up to you and what you prefer. My answer prioritises function signature being identical across the hierarchy for example. – Joseph Victor Zammit May 25 '23 at 12:27
UPDATED 10/25/2011: I'm now using this with a dynamically created class instead of method, as Django 1.3 displays some weirdness otherwise.
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
Then override MyCustomForm.__init__
as follows:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
You can then access the request object from any method of ModelForm
with self.request
.

- 167
- 3
- 12

- 232,153
- 36
- 385
- 444
-
1Chris, that "def __init__(self, request=None, *args, **kwargs)" is bad, because it will end up with request in both the first positional arg and in kwargs. I changed it to "def __init__(self, *args, **kwargs)" and that works. – slinkp Dec 19 '11 at 22:08
-
1Whoops. That was just a mistake on my part. I neglected to update that part of the code when I made the other update. Thanks for the catch. Updated. – Chris Pratt Dec 20 '11 at 15:10
-
4Is this really a metaclass ? I think it just normal overriding, you add request to `__new__`'s kwargs which later on will be passed to the class's `__init__` method. Naming the class `ModelFormWithRequest` I think much clearer in it's meaning than `ModelFormMetaClass`. – k4ml Mar 08 '12 at 16:55
-
2This in NOT a metaclass! See http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – frnhr Sep 04 '14 at 12:42
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

- 40,356
- 16
- 72
- 88
-
2Despite 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 Oct 21 '09 at 01:15
-
4@rplevy have you actually passed the request object when you create an instance of the form? In case you haven't noticed it uses keyword arguments `**kwargs`, which means you will have to pass the request object as `MyForm(request.POST, request=request)`. – unode Mar 04 '11 at 22:57
For Django admin, 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

- 5,531
- 1
- 33
- 39
-
1The top-rated method further above indeed seems to have stopped working somewhere between Django 1.6 and 1.9. This one does work and is much shorter. Thanks! – Raik Apr 27 '16 at 22:16
I ran into this particular problem when customizing the admin. I wanted a certain field to be validated based on the particular admin's credentials.
Since I did not want to modify the view to pass the request as an argument to the form, the following is what I did:
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

- 3,134
- 20
- 20
-
Thanks for that. Quick typo: `obj=obj` not `obj=None` on line 11. – François Constant Nov 16 '15 at 23:12
-
-
Django 1.9 delivers: ```'function' object has no attribute 'base_fields'```. However, the simpler (without closure) @François answer works smoothly. – raratiru May 11 '16 at 21:11
The answer by Daniel Roseman is still the best. However, I would use the first positional argument for the request instead of the keyword argument for a few reasons:
- You don't run the risk of overriding a kwarg with the same name
- The request is optional which is not right. The request attribute should never be None in this context.
- You can cleanly pass the args and kwargs to the parent class without having to modify them.
Lastly, I would use a more unique name to avoid overriding an existing variable. Thus, My modified answer looks like:
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 ...

- 1
- 1

- 389
- 5
- 6
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")

- 732
- 7
- 6
-
This is sometimes a really nice solution: I often do this in a CBV `get_form_class` method, if I know I need to do lots of stuff with the request. There may be some overhead in repeatedly creating the class, but that just moves it from import time to run-time. – Matthew Schinckel Feb 23 '17 at 03:44
I have another answer to this question as per your requirement you want to access the user into the clean method of the form. You can Try this. 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)
Now you can access the self.instance in any clean method in form.py

- 819
- 2
- 15
- 25
When you want to access it through "prepared" Django class views like CreateView
there's a small trick to know (= the official solution doesn't work out of the box). In your own CreateView
you'll have to add code like this:
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 short this is the solution to pass request
to your form with Django's Create/Update views.

- 15,363
- 26
- 117
- 213