formmodel - forms meta django
Django formset unit test (5)
No puedo ejecutar Unit Test con formset.
Intento hacer una prueba:
class NewClientTestCase(TestCase):
def setUp(self):
self.c = Client()
def test_0_create_individual_with_same_adress(self):
post_data = {
''ctype'': User.CONTACT_INDIVIDUAL,
''username'': ''dupond.f'',
''email'': ''[email protected]'',
''password'': ''pwd'',
''password2'': ''pwd'',
''civility'': User.CIVILITY_MISTER,
''first_name'': ''François'',
''last_name'': ''DUPOND'',
''phone'': ''+33 1 34 12 52 30'',
''gsm'': ''+33 6 34 12 52 30'',
''fax'': ''+33 1 34 12 52 30'',
''form-0-address1'': ''33 avenue Gambetta'',
''form-0-address2'': ''apt 50'',
''form-0-zip_code'': ''75020'',
''form-0-city'': ''Paris'',
''form-0-country'': ''FRA'',
''same_for_billing'': True,
}
response = self.c.post(reverse(''client:full_account''), post_data, follow=True)
self.assertRedirects(response, ''%s?created=1'' % reverse(''client:dashboard''))
y tengo este error:
Error de validación: [u''faltan los datos de Management Management o se han manipulado '']
Mi vista :
def full_account(request, url_redirect=''''):
from forms import NewUserFullForm, AddressForm, BaseArticleFormSet
fields_required = []
fields_notrequired = []
AddressFormSet = formset_factory(AddressForm, extra=2, formset=BaseArticleFormSet)
if request.method == ''POST'':
form = NewUserFullForm(request.POST)
objforms = AddressFormSet(request.POST)
if objforms.is_valid() and form.is_valid():
user = form.save()
address = objforms.forms[0].save()
if url_redirect=='''':
url_redirect = ''%s?created=1'' % reverse(''client:dashboard'')
logon(request, form.instance)
return HttpResponseRedirect(url_redirect)
else:
form = NewUserFullForm()
objforms = AddressFormSet()
return direct_to_template(request, ''clients/full_account.html'', {
''form'':form,
''formset'': objforms,
''tld_fr'':False,
})
y mi archivo de formulario:
class BaseArticleFormSet(BaseFormSet):
def clean(self):
msg_err = _(''Ce champ est obligatoire.'')
non_errors = True
if ''same_for_billing'' in self.data and self.data[''same_for_billing''] == ''on'':
same_for_billing = True
else:
same_for_billing = False
for i in [0, 1]:
form = self.forms[i]
for field in form.fields:
name_field = ''form-%d-%s'' % (i, field )
value_field = self.data[name_field].strip()
if i == 0 and self.forms[0].fields[field].required and value_field =='''':
form.errors[field] = msg_err
non_errors = False
elif i == 1 and not same_for_billing and self.forms[1].fields[field].required and value_field =='''':
form.errors[field] = msg_err
non_errors = False
return non_errors
class AddressForm(forms.ModelForm):
class Meta:
model = Address
address1 = forms.CharField()
address2 = forms.CharField(required=False)
zip_code = forms.CharField()
city = forms.CharField()
country = forms.ChoiceField(choices=CountryField.COUNTRIES, initial=''FRA'')
Cada formato de Django viene con un formulario de administración que debe incluirse en la publicación. Los documentos oficiales lo explican bastante bien. Para usarlo dentro de su prueba de unidad, debe escribirlo usted mismo. (El enlace que proporcioné muestra un ejemplo), o llame a formset.management_form
que genera los datos.
De hecho, es fácil reproducir lo que esté en el formset inspeccionando el contexto de la respuesta.
Considere el siguiente código (con self.client
siendo un cliente de prueba regular):
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)
Nota IMPORTANTE
Si modifica los data
antes de llamar a self.client.post
, es probable que esté mutando la base de datos. Como consecuencia, la llamada posterior a self.client.get
podría no ceder a los mismos datos, en particular para el formulario de gestión y el orden de los formularios en el conjunto de formularios (porque pueden ordenarse de forma diferente, según el conjunto de consultas subyacente). Esto significa que
- si modifica los
data[form-3-somefield]
y llama aself.client.get
, este mismo campo podría aparecer en, digamos,data[form-8-somefield]
, - si modifica los
data
antes deself.client.post
, no puedeself.client.post
llamar aself.client.post
con los mismosdata
: debe llamar aself.client.get
y reconstruir losdata
nuevamente.
En particular, he encontrado que el validador ManagmentForm está buscando los siguientes elementos para POSTAR:
form_data = {
''form-TOTAL_FORMS'': 1,
''form-INITIAL_FORMS'': 0
}
Esto no parece ser un conjunto de formas en absoluto. Formsets siempre tendrá algún tipo de prefijo en cada valor POST, así como el ManagementForm que menciona Bartek. Podría haber ayudado si publicó el código de la vista que está intentando probar, y el formulario / formset que utiliza.
Mi caso puede ser un caso atípico, pero en algunos casos faltaba un campo establecido en el formulario / plantilla de administrador de "contrib" que provocaba el error
"Faltan datos de ManagementForm o han sido manipulados"
cuando se guarda.
El problema fue con el método Unicode (SomeModel: [Bad Unicode data]) que encontré investigando las líneas que faltaban.
La lección aprendida es no usar el mapa de caracteres de MS, supongo. Mi problema era con las fracciones vulgares (¼, ½, ¾), pero supongo que podría ocurrir de muchas maneras diferentes. Para caracteres especiales, se ha corregido el copiado / pegado de la página w3 utf-8.