182đź‘Ť
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)
47đź‘Ť
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)
- [Django]-Good open source django project for learning
- [Django]-Django : How can I find a list of models that the ORM knows?
- [Django]-Django unit tests without a db
36đź‘Ť
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
.
- [Django]-What is reverse()?
- [Django]-What's the idiomatic Python equivalent to Django's 'regroup' template tag?
- [Django]-How do I run tests for all my Django apps only?
18đź‘Ť
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
- [Django]-How to set a value of a variable inside a template code?
- [Django]-What's the best solution for OpenID with Django?
- [Django]-Celery : Execute task after a specific time gap
14đź‘Ť
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
- [Django]-Paginating the results of a Django forms POST request
- [Django]-Why am I getting this error in Django?
- [Django]-Sending HTML email in django
10đź‘Ť
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
- [Django]-Change a form value before validation in Django form
- [Django]-Django logging of custom management commands
- [Django]-Django Form File Field disappears on form error
6đź‘Ť
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 ...
- [Django]-How to debug Django commands in PyCharm
- [Django]-How do I get user IP address in Django?
- [Django]-Best practices for adding .gitignore file for Python projects?
5đź‘Ť
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")
- [Django]-ImproperlyConfigured: You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings
- [Django]-Constructing Django filter queries dynamically with args and kwargs
- [Django]-How to get getting base_url in django template
- [Django]-How to pull a random record using Django's ORM?
- [Django]-How to set True as default value for BooleanField on Django?
- [Django]-Retrieving a Foreign Key value with django-rest-framework serializers
3đź‘Ť
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
- [Django]-Using django-rest-interface
- [Django]-Django Multiple Authentication Backend for one project
- [Django]-Storing an Integer Array in a Django Database
1đź‘Ť
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.
- [Django]-Django – No module named _sqlite3
- [Django]-Django model constraint for related objects
- [Django]-Multiple ModelAdmins/views for same model in Django admin