'How to omit fields in Django form that are not provided by the request after cleaning?
I have several Django forms which are used in HTTP APIs, and these forms are full of optional fields. For example:
class MySearchForm(forms.Form):
param1 = forms.CharField(required=False)
param2 = forms.BooleanField(required=False)
param3 = forms.IntegerField(required=False, min_value=0)
Now I'm using these to validate parameters or forms in requests, by calling form.is_valid(), just like this:
def on_my_search_request(request):
form = MySearchForm(request.GET) # in case of a POST request, request.POST is used
if form.is_valid():
do_search(form.cleaned_data) # do something with form.cleaned_data
else:
# response with error
The code above is expected to work properly even if no parameter is given in the request (in this case, apply no condition to the search).
So, I'm expecting form.cleaned_data to contain only the valid fields that appears in the request, which is not the case. After the cleaning, all the fields not provided are given an empty value.
Consider the following request:
https://hostname-of-my-server:port/search?param1=test
And what I need in the do_search function:
{'param1': 'test'}
But the actual value is:
{'param1': 'test', 'param2': False, 'param3': None}
# improperly set or unexpected param2 and param3 will cause problems
Is there an elegant way to omit the fields that are not provided?
Solution 1:[1]
I personally figured out an approach, that is, to override the cleaning function in the Form class:
from django import forms
from django.core.exceptions import ValidationError
class CustomForm(forms.Form):
""" Only keeps fields explicitly provided in cleaned_data. """
def _clean_fields(self):
for name, field in self.fields.items():
if name not in self.data: # <<< added
continue # <<< added
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, forms.FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
Not very elegent, and not sure if it works in all cases (enough for myself only).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | PleasantFuban |
