Django formset de test unitaire
Je ne peux pas lancer de test D'unité avec formset.
j'ai essayer de faire un test:
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': 'new@gmail.com',
'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'))
et j'ai cette erreur:
ValidationError: [données manquantes ou manquantes de la forme de gestion altéré']
Mon avis :
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,
})
et mon fichier de formulaire :
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')
5 réponses
chaque formset Django est livré avec un formulaire de gestion qui doit être inclus dans le post. officiel docs expliquer assez bien. Pour l'utiliser dans votre test unitaire, vous avez soit besoin de l'écrire vous-même. (Le lien que j'ai fourni montre un exemple), ou appeler formset.management_form
qui produit les données.
En particulier, j'ai trouvé que la ManagmentForm validateur est à la recherche pour les éléments suivants pour être Affiché:
form_data = {
'form-TOTAL_FORMS': 1,
'form-INITIAL_FORMS': 0
}
Il est en fait facile à reproduire ce qui est dans le formset en inspectant le contexte de la réponse.
considerez le code ci-dessous (avec self.client
régulier client de test):
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)
Note importante
Si vous modifiez data
avant d'appeler le self.client.post
, vous êtes probablement en train de muter le DB. En conséquence, l'appel suivant self.client.get
pourraient ne pas donner les mêmes données, en particulier pour le formulaire de gestion et la commande des formulaires dans le jeu de formulaires (parce qu'ils peuvent être commandés différemment, en fonction du queryset sous-jacent). Cela signifie que
- si vous modifiez
data[form-3-somefield]
et appelerself.client.get
, ce même champ pourrait apparaître dans saydata[form-8-somefield]
, - si vous modifiez
data
avantself.client.post
, vous ne pouvez pas appelerself.client.post
nouveau avec le mêmedata
: - vous appeler unself.client.get
et reconstruiredata
nouveau.
Cela ne semble pas être un formset. Formsets aura toujours une sorte de préfixe sur chaque valeur affichée, ainsi que la forme de gestion que Bartek mentionne. Cela aurait pu aider si vous aviez Posté le code de la vue que vous essayez de tester, et le form/formset qu'il utilise.
Mon cas, peut-être une exception, mais certains cas ont été effectivement manquant un ensemble de champs dans le stock "contrib" admin forme/modèle conduisant à l'erreur
"ManagementForm de données est manquant ou a été falsifié"
lorsqu'il est sauvegardé.
Le problème était avec le unicode méthode (SomeModel: [Bad Unicode data]) que j'ai trouvé en étudiant les lignes intérieures qui manquaient.
la leçon apprise est de ne pas utiliser le MS La table de caractères, je suppose. Mon problème était avec les fractions vulgaires ( ¼ ,½,¾), mais je suppose qu'il pourrait se produire de nombreuses façons différentes. Pour les caractères spéciaux, la copie / collage à partir de la page W3 utf-8 l'a corrigé.