59 votes

django la classe de base des points de vue avec inline-modèle de formulaire ou un formset

J'ai 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 c'est possible:

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

et ensuite via l'affichage standard.

Maintenant, je me demandais, si il y a un moyen pour atteindre le même (ce qui signifie: à l'aide d'un en ligne pour l'ajout/modification d'éléments appartenant à un projet de loi) à l'aide de la classe de base de points de vue (pas pour l'interface d'administration).

66voto

Jordan Reiter Points 8679

On dirait que quelqu'un a réussi à trouver une mise en œuvre ici: http://haineault.com/blog/155/

Les points clés, dans le cas où ce n'est jamais une erreur 404:

  1. générée FormSets dans forms.py l'aide inlineformset_factory:

    BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2)
    BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
    
  2. renvoyé l' FormSets dans un CreateView classe 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. Utilisé form_valid pour enregistrer 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))
    

15voto

Yuji 'Tomita' Tomita Points 46106

J'ai juste ajouté ma propre version, après vérification de certains de ces pré-faites CBVs. J'ai particulièrement besoin de contrôler multiple formsets -> one parent dans une vue unique avec chaque individu enregistrer des fonctions.

En gros, j'ai bourré le FormSet la liaison de données en get_named_formsets fonction qui est appelée par get_context_data et form_valid.

Là, j'ai vérifier si tous les jeux de formulaires sont valides, et aussi regarder pour une méthode qui remplace un bon vieux formset.save() par formset base de la coutume de l'épargne.

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()

12voto

Udi Points 6298

Vous devriez essayer de django-extra-vues. Recherchez CreateWithInlinesView et UpdateWithInlinesView.

1voto

VGE Points 2969

J'rouge le générique de code source de l'1.3-beta-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 django.vue.génériques.edit (prise en charge détaillée de l'objet de l'édition) module comment utiliser le django.vue.génériques.détail du module.

Je pense que django.vue.génériques.list_edit module peut être mis en œuvre à l'aide de django.vue.génériques.liste et une partie de django.vue.génériques.edit.

1voto

knite Points 901

Le code de la Jordanie réponse n'a pas fonctionné pour moi. J'ai posté ma propre question à ce sujet, qui, je crois, j'ai maintenant résolu. Le premier argument de inlineformset_factory devrait être Livre, pas BookForm.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X