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')
20
demandé sur alecxe 2009-10-27 16:19:19

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.

12
répondu Bartek 2009-10-27 13:23:34

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 
}
17
répondu southgate 2009-12-14 00:29:01

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 appeler self.client.get, ce même champ pourrait apparaître dans say data[form-8-somefield],
  • si vous modifiez data avant self.client.post, vous ne pouvez pas appeler self.client.post nouveau avec le même data: - vous appeler un self.client.get et reconstruire data nouveau.
4
répondu Raffi 2016-07-20 20:08:29

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.

0
répondu Daniel Roseman 2009-10-27 13:45:32

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é.

postscript-utf-8

0
répondu pragmar 2011-12-05 12:51:31