Django formset unit test
It is in fact easy to reproduce whatever is in the formset by inspecting the context of the response.
Consider the code below (with self.client
being a regular test client):
url = "some_url"
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
# data will receive all the forms field names
# key will be the field name (as "formx-fieldname"), value will be the string representation.
data = {}
# global information, some additional fields may go there
data['csrf_token'] = response.context['csrf_token']
# management form information, needed because of the formset
management_form = response.context['form'].management_form
for i in 'TOTAL_FORMS', 'INITIAL_FORMS', 'MIN_NUM_FORMS', 'MAX_NUM_FORMS':
data['%s-%s' % (management_form.prefix, i)] = management_form[i].value()
for i in range(response.context['form'].total_form_count()):
# get form index 'i'
current_form = response.context['form'].forms[i]
# retrieve all the fields
for field_name in current_form.fields:
value = current_form[field_name].value()
data['%s-%s' % (current_form.prefix, field_name)] = value if value is not None else ''
# flush out to stdout
print '#' * 30
for i in sorted(data.keys()):
print i, '\t:', data[i]
# post the request without any change
response = self.client.post(url, data)
Important note
If you modify data
prior to calling the self.client.post
, you are likely mutating the DB. As a consequence, subsequent call to self.client.get
might not yield to the same data, in particular for the management form and the order of the forms in the formset (because they can be ordered differently, depending on the underlying queryset). This means that
- if you modify
data[form-3-somefield]
and callself.client.get
, this same field might appear in saydata[form-8-somefield]
, - if you modify
data
prior to aself.client.post
, you cannot callself.client.post
again with the samedata
: you have to call aself.client.get
and reconstructdata
again.
Every Django formset comes with a management form that needs to be included in the post. The official docs explain it pretty well. To use it within your unit test, you either need to write it out yourself. (The link I provided shows an example), or call formset.management_form
which outputs the data.
In particular, I've found that the ManagmentForm validator is looking for the following items to be POSTed:
form_data = {
'form-TOTAL_FORMS': 1,
'form-INITIAL_FORMS': 0
}