I tried the content written in the digression of Dynamic specification of queryset of ModelChoiceField in Django, so memo memo.
By playing with Form.fields, you can change various attributes of other fields after the form is generated. Is it possible to add / remove the field itself?
Launch Django's shell command and try it on an interactive shell
Form
object>>> from django import forms
>>> f = forms.Form()
>>> f.as_p()
''
>>> f.fields
OrderedDict()
No fields are defined at this point, so calling ʻas_p ()does not render anything
Form.fields only shows empty ʻOrderdDict
objects
… For the first time, we know that the type of Form.fields
is a class called OrderedDict.
Form.fields
>>> f.fields['name'] = forms.CharField(label='name')
>>> f.as_p()
'<p><label for="id_name">name:</label> <input id="id_name" name="name" type="text" /></p>'
>>> f.fields
OrderedDict([('name', <django.forms.fields.CharField object at 0x00000000045E5B388>)])
Add CharField
with the key'name'.
Rendered properly with ʻas_p (). The contents of
Form.fields also contain the object of
CharField` with the key'name'.
and checking ʻerrors
, cleaned_data
>>> f.is_valid()
Flase
>>> f.errors
{}
>>> f.cleaned_data
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Form' object has no attribute 'cleaned_data'
Since the added name field is required = True
(default value), it is expected that ʻis_valid ()will be False, but for some reason
Form.errors` is empty.
When I looked it up, if the Form
object didn't change the value of each field, or didn't receive a data
as an argument, it would just create an empty ʻerrors and handle
full_clean () Seems to finish (
cleaned_data` is not generated either).
There is no help for it, so pass the data
argument to the Form
object and regenerate it. I'll give it a try.
>>> f = forms.Form(data={})
>>> f.fields['name'] = forms.CharField(label='name')
>>> f.is_valid()
False
>>> f.errors
{'name': ['This field is required.']}
>>> f.cleaned_data
{}
As expected, the content of ʻerrorscontained a mandatory check error for'name'. An empty dict is also generated for
cleaned_data`.
and ʻerrors
At first, I tried to directly assign an empty dict to Form.data
to deal with the problem of ↑, but the result did not change.
When I followed the source of django, it was because of the following processing at the beginning of __init __ ()
of the BaseForm
class, which is the parent of the Form
class.
forms.py
self.is_bound = data is not None or files is not None
So, the implementation of ʻis_valid` is only one line below
forms.py
def is_valid(self):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""
return self.is_bound and not bool(self.errors)
In addition, errors are defined as methods with property decorators rather than fields.
forms.py
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
So, you couldn't just edit data
directly, you had to do the following two things.
full_clean ()
Well, if you think about using it as a normal web application, you shouldn't have to change the parameters and redo the validation while processing one request ...
It is natural that validation (call of full_clean ()
) is not executed every time ʻis_valid () or ʻerrors
is accessed, but only the first time.
data
so that validation is True>>> f.data = {'name':'hoge'}
>>> f.full_clean()
>>> f.is_valid()
True
>>> f.errors
{}
>>> f.cleaned_data
{'name':'hoge'}
>>> f.fields['date'] = forms.DateField(label='date',required=False)
>>> f.as_p()
'<ul class="errorlist"><li>This field is required.</li></ul>\n<p><label for="id_name">name:</label> <input id="id_name" name="name" type="text" /></p>\n<p><label for="id_date">date:</label> <input id="id_date" name="date" type="text" /></p>'
>>> f.fields
OrderedDict([('name', <django.forms.fields.CharField object at 0x00000000045E5B38>), ('date', <django.forms.fields.DateField object at 0x0000000002A3C828>)])
>>> f.full_clean()
>>> f.is_valid()
True
>>> f.errors
{}
>>> f.cleaned_data
{'date':None, 'name':'hoge'}
>>> f.data['date'] = '2014-12-04'
>>> f.full_clean()
>>> f.is_valid()
True
>>> f.errors
{}
>>> f.cleaned_data
{'date':datetime.date(2014, 12, 4), 'name':'hoge'}
Form.fields
>>> f.fields.popitem()
('date', <django.forms.fields.DateField object at 0x0000000002A3C828>)
>>> f.as_p()
'<p><label for="id_name">name:</label> <input id="id_name" name="name" type="text" value="hoge" /></p>'
>>> f.fields
OrderedDict([('name', <django.forms.fields.CharField object at 0x00000000045E5B38>)])
>>> f.full_clean()
>>> f.cleaned_data
{'name': 'hoge'}
>>> f.data
{'date': '2014-12-04', 'name': 'hoge'}
Form.fields
deletes the item with ʻOrderedDict.popitem. If the argument
last` is True (default), it will be LIFO, and if it is False, it will be LILO.
This time it's True, so the date field I added later was removed.
So, Django's Form
object can be added / removed later in the field itself.
I think it can respond to requests such as "Allow you to freely add screen input items in the master settings!"
Recommended Posts