Question

Je les modèles suivants:

class Bill(models.Model):
    date = models.DateTimeField(_("Date of bill"),null=True,blank=True)

class Item(models.Model):
    name = models.CharField(_("Name"),max_length=100)
    price = models.FloatField(_("Price"))
    quantity = models.IntegerField(_("Quantity"))
    bill = models.ForeignKey("Bill",verbose_name=_("Bill"),
                             related_name="billitem")

Je sais que cela est possible:

from django.forms.models import inlineformset_factory
inlineformset_factory(Bill, Item)

et traiter ensuite ce via la vue standard.

Maintenant, je me demandais s'il y a un moyen d'atteindre les mêmes (ce qui signifie: en utilisant une ligne pour ajouter / modification d'éléments appartenant à un projet de loi) en utilisant des vues sur la base class (pas pour le Admin- interface).

Était-ce utile?

La solution

Points clés est:

  1. FormSets générée à l'intérieur en utilisant forms.py inlineformset_factory:

    BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2)
    BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
    
  2. retourné les FormSets au sein d'une classe CreateView dans views.py:

    def get_context_data(self, **kwargs):
        context = super(BookCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            context['bookimage_form'] = BookImageFormSet(self.request.POST)
            context['bookpage_form'] = BookPageFormSet(self.request.POST)
        else:
            context['bookimage_form'] = BookImageFormSet()
            context['bookpage_form'] = BookPageFormSet()
        return context
    
  3. form_valid Permet de sauvegarder le formulaire et formset:

     def form_valid(self, form):
         context = self.get_context_data()
         bookimage_form = context['bookimage_formset']
         bookpage_form = context['bookpage_formset']
         if bookimage_form.is_valid() and bookpage_form.is_valid():
             self.object = form.save()
             bookimage_form.instance = self.object
             bookimage_form.save()
             bookpage_form.instance = self.object
             bookpage_form.save()
             return HttpResponseRedirect('thanks/')
         else:
             return self.render_to_response(self.get_context_data(form=form))
    

Autres conseils

Je viens d'ajouter ma propre version après avoir vérifié quelques-unes de ces CBV pré-fait. Je contrôle spécifiquement besoin sur multiple formsets -> one parent en une seule vue chacun épargnent de fonctions.

Je essentiellement bourré les données Formset liant dans une fonction get_named_formsets qui est appelée par get_context_data et form_valid.

, je vérifie si tous les formsets sont valides, et cherchons également une méthode qui l'emporte sur une ancienne plaine formset.save() sur une base formset pour économiser sur mesure.

Le modèle rend formsets via

{% with named_formsets.my_specific_formset as formset %}
 {{ formset }}
 {{ formset.management_form }}
{% endwith %}

Je pense que je vais utiliser ce système régulièrement.

class MyView(UpdateView): # FormView, CreateView, etc
  def get_context_data(self, **kwargs):
        ctx = super(MyView, self).get_context_data(**kwargs)
        ctx['named_formsets'] = self.get_named_formsets()
        return ctx

    def get_named_formsets(self):
        return {
            'followup': FollowUpFormSet(self.request.POST or None, prefix='followup'),
            'action': ActionFormSet(self.request.POST or None, prefix='action'),
        }

    def form_valid(self, form):
        named_formsets = self.get_named_formsets()
        if not all((x.is_valid() for x in named_formsets.values())):
            return self.render_to_response(self.get_context_data(form=form))

        self.object = form.save()

        # for every formset, attempt to find a specific formset save function
        # otherwise, just save.
        for name, formset in named_formsets.items():
            formset_save_func = getattr(self, 'formset_{0}_valid'.format(name), None)
            if formset_save_func is not None:
                formset_save_func(formset)
            else:
                formset.save()
        return http.HttpResponseRedirect('')

    def formset_followup_valid(self, formset):
        """
        Hook for custom formset saving.. useful if you have multiple formsets
        """
        followups = formset.save(commit=False) # self.save_formset(formset, contact)
        for followup in followups:
            followup.who = self.request.user
            followup.contact = self.object
            followup.save()

Vous devriez essayer django-extra-vues . Rechercher des CreateWithInlinesView et UpdateWithInlinesView.

I rouge le code source générique du 1,3-bêta-1:

Le code est absolument pas prêt pour la liste d'édition ou il y a un peu de magie noire ici. Mais je pense qu'il peut être mis en œuvre rapidement.

Si vous regardez le module django.view.generic.edit (que le support d'édition d'objets détaillés) comment utiliser le module django.view.generic.detail.

Je pense qu'un module django.view.generic.list_edit peut être mis en œuvre en utilisant django.view.generic.list et une partie de django.view.generic.edit.

J'ai fait quelques modifications à la solution originale de laisser formset.is_valid () au travail:

    if self.request.POST:
        context['fs'] = MyInlineFS(self.request.POST, instance=self.object)
    else:
        context['fs'] = MyInlineFS(instance=self.object)

Le code dans la réponse de Jordan ne fonctionne pas pour moi. Je posté ma propre question sur ce que je crois que je suis maintenant résolu. Le premier argument de inlineformset_factory devrait être livre, pas BookForm.

Je avais besoin de faire une autre modification de la Jordanie et la get_context_data() de la vue de Speq afin d'avoir exist de formset.non_form_errors dans le contexte du template.

...
if self.request.POST:
    context['fs'] = MyInlineFS(self.request.POST, instance=self.object)
    context['fs'].full_clean()  # <-- new
else:
    context['fs'] = MyInlineFS(instance=self.object)
return context
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top