2009-12-31 8 views
0

je crée une vue qui retourne une forme comprenant un formulaire de contact et deux formes de phone_number, suivant cet exemple:django édition en ligne - formulaire en ligne uniquement nécessaire si au moins un champ est rempli

multiple forms

Le le numéro de téléphone formes ne doivent être validés si l'utilisateur insère au moins une valeur pour un champ dans une forme de numéro de téléphone. Par exemple: un numéro de téléphone a un type et un numéro. Si l'utilisateur sélectionne le type, le numéro est requis.

Maintenant, je me demande comment je peux vérifier dans la vue si l'utilisateur a inséré une valeur/sélectionné un type ou inséré un numéro. Cela devrait fonctionner comme dans l'admin pour l'édition en ligne d'un modèle.

mon avis ressemble à ceci:

def contact_add(request): 
    user = request.user 
    if request.method == 'POST': 
     cform = ContactForm(request.POST) 
     pforms = [PhoneNumberForm(request.POST, prefix=str(x)) for x in range(0,3)] 
     if cform.is_valid() and all([pf.is_valid() for pf in pforms]): 
      new_contact = cform.save(commit=False) 
      new_contact.created_by = user 
      new_contact.save() 
      for pf in pforms: 
       new_phone_number = pf.save(commit=False) 
       new_phone_number.contact = new_contact 
       new_phone_number.save() 
      request.user.message_set.create(message='Contact %s has been added.' % new_contact.__str__()) 
      return HttpResponseRedirect("/crm/contacts/?oby=1") 

    else: 
     cform = ContactForm() 
     pforms = [PhoneNumberForm(prefix=str(x)) for x in range(0,3)] 

    return render_to_response(
     'crm/contact_add.html', 
     {'cform': cform, 'pforms': pforms,}, 
     context_instance = RequestContext(request), 
    ) 

Modifier après la première réponse ci-dessous:

J'ai essayé d'accomplir cette tâche avec validation personnalisée, mais ne sont pas venus à une fin satisfaisante. Pour faciliter ma tâche, j'ai changé un peu le cas d'utilisation. Je crée un formulaire qui comprend un formulaire de contact et un formulaire d'adresse. Le formulaire d'adresse doit être validée si au moins un champ du formulaire d'adresse est rempli, car il devrait être possible de créer un contact sans créer une adresse correspondante.

Tout d'abord j'ai essayé d'utiliser la validation de custume, qui ressemblait à ceci:

class AddressForm(forms.ModelForm): 
    class Meta: 
     model = Address 
     exclude = ('contact',) 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     street = cleaned_data.get("street") 
     postal_code = cleaned_data.get("postal_code") 
     city = cleaned_data.get("city") 
     country = cleaned_data.get("country") 

     if not street and not postal_code and not city and not country: 
      #searching a better idea here 
      return 0 
     else: 
      return cleaned_data 

Mais cela ne fonctionne pas vraiment, puisque de cette façon que je ne vous débarrassez pas des erreurs de validation. Cela m'amène à l'idée que la méthode propre est le mauvais endroit pour faire cette validation, je pense que je dois vérifier dans la demande POST si toutes les valeurs pour le formulaire d'adresse sont manquantes. Et s'ils sont manquants, je n'appelle pas is_valid() pour le formulaire d'adresse et je l'ignore. Si au moins une valeur est disponible, je fais juste la validation normale du formulaire d'adresse, sans surcharger la méthode clean().

Bonne ou mauvaise idée? Si elle est une bonne idée, comment puis-je vérifier facilement la requête POST pour les valeurs de mon formulaire d'adresse.

façon de penser probablement à I`m compliqué :-)

Edit: La solution à l'aide Formsets:

@login_required 
def contact_add(request): 
    user = request.user 
    if request.method == 'POST': 
     cform = ContactForm(request.POST) 
     phonenumberformset = PhoneNumberFormSet(request.POST) 

     if cform.is_valid() and classificationformset.is_valid() and addressformset.is_valid() and phonenumberformset.is_valid(): 
      new_contact = cform.save(commit=False) 
      new_contact.created_by = user 
      new_contact.save() 

      new_phonenumber_instances = phonenumberformset.save(commit=False) 
      for new_phonenumber in new_phonenumber_instances: 
       new_phonenumber.contact = new_contact 
       new_phonenumber.save() 

      request.user.message_set.create(message='Contact %s has been added.' % new_contact.__str__()) 
      return HttpResponseRedirect("/crm/contacts/?oby=1") 
    else: 
     cform = ContactForm() 
     #By default, when you create a formset from a model, the formset will use 
     #a queryset that includes all objects in the model (e.g., Author.objects.all()). 
     #Here we want to present an empty formset in order to add a new object 

     phonenumberformset = PhoneNumberFormSet(queryset=PhoneNumber.objects.none()) 
    return render_to_response(
     'crm/contact_add.html', 
     {'cform': cform, 'phonenumberformset': phonenumberformset,}, 
     context_instance = RequestContext(request), 
    ) 

S'il vous plaît noter que cela peut aussi être réalisé en utilisant un inlineformset_factory, voir mon autre poste pour plus de détails: link

Notez que si vous utilisez formsets vous devez inclure un management_form pour chaque form_set dans votre modèle. docs

Sinon, vous obtenez cette erreur:

[u'ManagementForm data is missing or has been tampered with'] 

Using a formset inside a view is as easy as using a regular Form class. The only thing you will want to be aware of is making sure to use the management form inside the template.

{{ context.phonenumberformset.management_form }} 

Répondre

2

Vous devez utiliser formsets plutôt que de déconner avec des préfixes dynamiques pour votre PhoneNumber subform - Cela rendra tout plus facile, et c'est bien ainsi que l'admin gère les formulaires en ligne (voir aussi le model formsets documentation). Les ensembles de formulaires sont suffisamment intelligents pour que, si aucune information n'est saisie dans une forme du formset, ils n'appliquent pas les éléments requis - mais si un élément est rempli, tous les critères de validation seront appliqués. Cela ressemble à cela devrait résoudre votre problème.

+0

Formulaires? Je n'en ai jamais entendu parler. Je vais essayer. Ça sonne bien :-) –

+0

Mais pour mon cas d'utilisation ci-dessus, si je crée un Formset pour un formulaire d'adresse. Est-ce que le formset vérifie que l'utilisateur n'a pas rempli de données et ne le valide pas? –

+0

Ok ça marche. Va l'essayer aussi pour les autres inlines et poster le résultat dans ma question! –

2

Qu'est-ce que vous voulez faire est de définir custom validation sur le formulaire.

class PhoneNumberForm(forms.Form): 
    # Everything as before. 
    ... 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     phone1 = cleaned_data.get("phone1") 

     if phone1: 
      # validate manually, and if it doesn't pass: 
      self._errors["phone1"] = ErrorList(["Hey, this field is wrong."]) 
      del cleaned_data["phone1"]    

     # Always return the full collection of cleaned data. 
     return cleaned_data 

Puis dans la vue, vous voulez compter sur la gestion des erreurs de validation de formulaire erreur intégrée de Django:

{{ pforms.phone1 }} 
{{ pforms.phone1.errors }} 
Questions connexes