tutorial formmodel form dynamically django unit-testing formset

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 a self.client.get , este mismo campo podría aparecer en, digamos, data[form-8-somefield] ,
  • si modifica los data antes de self.client.post , no puede self.client.post llamar a self.client.post con los mismos data : debe llamar a self.client.get y reconstruir los data 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.

postscript-utf-8