How to Access the Request Object or Any Other Variable in a Form's Clean() Method

How do I access the request object or any other variable in a form's clean() method?

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)

Django: Accessing request in forms.py clean function

You can overwrite the FormMixin's get_form_kwargs method to add the request for to the form's init parameters:

class ItemCreate(FormView):
def get_form_kwargs(self):
kwargs = super(ItemCreate, self).get_form_kwargs()
kwargs.update({
'request' : self.request
})
return kwargs

Django: Access request object from admin's form.clean()

Indeed, there is a way to solve your issue!

You will need to subclass form provided by ModelAdmin.get_form() and override it:

class BusinessDocumentCommentForm(forms.ModelForm):

def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
# Voila, now you can access request anywhere in your form methods by using self.request!
super(BusinessDocumentCommentForm, self).__init__(*args, **kwargs)
if self.request.GET.get('document_pk', False):
#Do something
def clean(self):
# Do something with self.request
# etc.
class Meta:
model = BusinessDocumentComment

class BusinessDocumentCommentAdmin(admin.ModelAdmin):

form = BusinessDocumentCommentForm

def get_form(self, request, obj=None, **kwargs):

AdminForm = super(BusinessDocumentCommentAdmin, self).get_form(request, obj, **kwargs)

class AdminFormWithRequest(AdminForm):
def __new__(cls, *args, **kwargs):
kwargs['request'] = request
return AdminForm(*args, **kwargs)

return AdminFormWithRequest

How to get requested user in clean function in django forms?

You never construct a form with a request in the first place. You should pass this with:

class KycFormCreateView(CreateView):
form_class = KycModelForm
model = KycModel
template_name = 'accounts/kyc/new_kyc.html'

def get_form_kwargs(self, *args, **kwargs):
form_kwargs = super().get_form_kwargs(*args, **kwargs)
form_kwargs['request'] = self.request
return form_kwargs

def form_valid(self, form):
user_kyc = form.save(commit=False)
user_kyc.owner = self.request.user
user_kyc.save()
return super().form_valid(form)

In the clean function, you do not need to query for a user self.request.user is a user object, so you can work with self.request.user directly:

class KycModelForm(forms.ModelForm):

class Meta:
model = KycModel
fields = '__all__'
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(KycModelForm, self).__init__(*args, **kwargs)

def clean(self):
cleaned_data = super().clean()
user = self.request.user
print(user)
return cleaned_data

How to access cleaned data in a Django form's clean() method?

forminstance.is_valid or forminstance.full_clean will call your form's clean method implicitly by which time forminstance.cleaned_data will have the dict populated with the data in the right type according to the form fields. The call to super in the example you posted is in case you have inheritance in your form class hierarchy.
For clarification. It won't hurt if you have super but it won't change anything if you're not inheriting from a form class that doesn't have any fields defined.

Grabbing POST variable in form clean() method

The POST data is contained in self.data.

How to safely access request object in Django models

I trying to access request object in my Django models so that I can get the currently logged in user with request.user.

Well a problem is that models are not per se used in the context of a request. One for example frequently defines custom commands to do bookkeeping, or one can define an API where for example the user is not present. The idea of the Django approach is that models should not be request-aware. Models define the "business logic" layer: the models define entities and how they interact. By not respecting these layers, one makes the application vulnerable for a lot of problems.

The blog you refer to aims to create what they call a global state (which is a severe anti-patten): you save the request in the middleware when the view makes a call, such that you can then fetch that object in the model layer. There are some problems with this approach: first of all, like already said, not all use cases are views, and thus not all use cases pass through the middleware. It is thus possible that the attribute does not exist when fetching it.

Furthermore it is not guaranteed that the request object is indeed the request object of the view. It is for example possible that we use the model layer with a command that thus does not pass through the middleware, in which case we should use the previous view request (so potentially with a different user). If the server processes multiple requests concurrently, it is also possible that a view will see a request that arrived a few nanoseconds later, and thus again take the wrong user. It is also possible that the authentication middleware is conditional, and thus that not all requests have a user attribute. In short there are more than enough scenario's where this can fail, and the results can be severe: people seeing, editing, or deleting data that they do not "own" (have no permission to view, edit, or delete).

You thus will need to pass the request, or user object to the user_test method. For example with:

from django.http import HttpRequest

class TestManager(models.Manager):
def user_test(self, request_or_user):
if isinstance(request_or_user, HttpRequest):
return self.filter(user=request_or_user.user, viewed=False)
else:
return self.filter(user=request_or_user, viewed=False)

one thus has to pass the request object from the view to the function. Even this is not really pure. A real pure approach would only accept a user object:

class TestManager(models.Manager):
def user_test(self, user):
return self.filter(user=user, viewed=False)

So in a view one can use this as:

def some_view(request):
some_tests = Test.objects.user_test(request.user)
# ...
# return Http response

For example if we want to render a template with this queryset, we can pass it like:

def some_view(request):
some_tests = Test.objects.user_test(request.user)
# ...
return render(request, 'my_template.html', {'some_tests': some_tests})

Python - Django - Pass Argument To Form Clean Method

Your __init__ method should accept *args and **kwargs, you should pass these when you call the superclass' __init__ method, rather than self and property_id.

def __init__(self, property_id, *args, **kwargs):
self.property_id = property_id
super(property_booking_form, self).__init__(*args, **kwargs)

You also need to change the way you instantiate the form in the view, since property_id is the first argument. For example:

if request.method == 'POST':
booking_form = property_booking_form(property_id=property_id, data=request.POST)

Alternatively, you can remove property_id from the signature, and pop it from kwargs. In this case, no changes to the views are required.

def __init__(self, *args, **kwargs):
self.property_id = kwargs.pop('property_id')
super(property_booking_form, self).__init__(*args, **kwargs)


Related Topics



Leave a reply



Submit