2015-01-10 7 views
14

Ich habe versucht Django klassenbasierte Create und UpdateView mit mehreren Inline-FormularsätzeDjango klassenbasierte Create und UpdateView mit mehreren Inline-Formularsätze

Create funktioniert gut, aber UpdateView funktioniert nicht richtig zu tun, wenn jemand UpdateView versucht, mit Mehrere Inline-Formsets, jeder versuchte pls teilen updateview Code-Snippet.

# models.py 
from django.db import models 

class Recipe(models.Model): 
    title = models.CharField(max_length=255) 
    description = models.TextField() 

class Ingredient(models.Model): 
    recipe = models.ForeignKey(Recipe) 
    description = models.CharField(max_length=255) 

class Instruction(models.Model): 
    recipe = models.ForeignKey(Recipe) 
    number = models.PositiveSmallIntegerField() 
    description = models.TextField() 


# forms.py 
from django.forms import ModelForm 
from django.forms.models import inlineformset_factory 
from .models import Recipe, Ingredient, Instruction 

class RecipeForm(ModelForm): 
    class Meta: 
     model = Recipe 

IngredientFormSet = inlineformset_factory(Recipe, Ingredient, extra=0) 
InstructionFormSet = inlineformset_factory(Recipe, Instruction, extra=0) 


# views.py 
from django.http import HttpResponseRedirect 
from django.views.generic.edit import CreateView, UpdateView 
from django.shortcuts import get_object_or_404 

from .forms import IngredientFormSet, InstructionFormSet, RecipeForm 
from .models import Recipe 

class RecipeCreateView(CreateView): 
    template_name = 'recipe_add.html' 
    model = Recipe 
    form_class = RecipeForm 
    success_url = '/account/dashboard/' 

    def get(self, request, *args, **kwargs): 
     self.object = None 
     form_class = self.get_form_class() 
     form = self.get_form(form_class) 
     ingredient_form = IngredientFormSet() 
     instruction_form = InstructionFormSet() 
     return self.render_to_response(
      self.get_context_data(form=form, 
            ingredient_form=ingredient_form, 
            instruction_form=instruction_form)) 

    def post(self, request, *args, **kwargs): 
     self.object = None 
     form_class = self.get_form_class() 
     form = self.get_form(form_class) 
     ingredient_form = IngredientFormSet(self.request.POST) 
     instruction_form = InstructionFormSet(self.request.POST) 
     if (form.is_valid() and ingredient_form.is_valid() and 
      instruction_form.is_valid()): 
      return self.form_valid(form, ingredient_form, instruction_form) 
     else: 
      return self.form_invalid(form, ingredient_form, instruction_form) 

    def form_valid(self, form, ingredient_form, instruction_form): 
     self.object = form.save() 
     ingredient_form.instance = self.object 
     ingredient_form.save() 
     instruction_form.instance = self.object 
     instruction_form.save() 
     return HttpResponseRedirect(self.get_success_url()) 

    def form_invalid(self, form, ingredient_form, instruction_form): 
     return self.render_to_response(
      self.get_context_data(form=form, 
            ingredient_form=ingredient_form, 
            instruction_form=instruction_form)) 

class RecipeUpdateView(UpdateView): 
    template_name = 'recipe_add.html' 
    model = Recipe 
    form_class = RecipeForm 

    def get_success_url(self): 
     self.success_url = '/account/dashboard/' 
     return self.success_url 

    def get_context_data(self, **kwargs): 
     context = super(RecipeUpdateView, self).get_context_data(**kwargs) 
     if self.request.POST: 
      context['form'] = RecipeForm(self.request.POST, instance=self.object) 
      context['ingredient_form'] = IngredientFormSet(self.request.POST, instance=self.object) 
      context['instruction_form'] = InstructionFormSet(self.request.POST, instance=self.object) 
     else: 
      context['form'] = RecipeForm(instance=self.object) 
      context['ingredient_form'] = IngredientFormSet(instance=self.object) 
      context['instruction_form'] = InstructionFormSet(instance=self.object) 
     return context 

    def post(self, request, *args, **kwargs): 
     self.object = None 
     form_class = self.get_form_class() 
     form = self.get_form(form_class) 
     ingredient_form = IngredientFormSet(self.request.POST) 
     instruction_form = InstructionFormSet(self.request.POST) 
     if (form.is_valid() and ingredient_form.is_valid() and 
      instruction_form.is_valid()): 
      return self.form_valid(form, ingredient_form, instruction_form) 
     else: 
      return self.form_invalid(form, ingredient_form, instruction_form) 

    def form_valid(self, form, ingredient_form, instruction_form): 
     self.object = form.save() 
     ingredient_form.instance = self.object 
     ingredient_form.save() 
     instruction_form.instance = self.object 
     instruction_form.save() 
     return HttpResponseRedirect(self.get_success_url()) 

    def form_invalid(self, form, ingredient_form, instruction_form): 
     return self.render_to_response(
      self.get_context_data(form=form, 
            ingredient_form=ingredient_form, 
            instruction_form=instruction_form)) 

Vielen Dank im Voraus.

+1

Original-Beitrag [Django klassenbasierte Ansichten mit mehreren Inline-Formularsätze] (http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/) –

+0

@vishes_shell dieser Link ist jetzt tot. – datakid

Antwort

5

Meine Vermutung ist, dass Sie nicht

self.object = None 

auf überschrieben post Verfahren in einem UpdateView tun können. Versuchen Sie also

self.object = self.get_object() 

statt, sobald Sie bereits eine Objektinstanz in diesem Fall haben.

4

Ich bin mir nicht sicher, ob Sie eine Antwort gefunden habe, aber ich habe eine funktionierende Version von UpdateView dokumentiert in meiner Antwort hier:

UpdateView with inline formsets trying to save duplicate records?

+1

Dieser Link bietet den Weg. Achten Sie auf die Verwendung von 'instance' im Gegensatz zu' initial' in der formset-Definition der get-Funktion und 'self.object = self.get_object' anstelle von' None' –

-1

So erkenne ich die Modelle dieses post bilden. Zum Laufen bringen UpdateView richtig gehen zu müssen, mindestens zwei, vielleicht drei Dinge tun:

  1. Aktualisieren der self.object = self.get_object() - danach, Ihre Fähigkeit, sollte dynamisch hinzufügen arbeiten.

  2. Um die dynamische Löschungen richtig zu aktualisieren, müssen Sie die Vorlage mit form.DELETE ändern (an zwei Stellen, die Zutaten und die Anweisungen).

    {{ form.description }} 
    {% if form.instance.pk %}{{ form.DELETE }}{% endif %} 
    
  3. nicht sicher, dass es notwendig war, aber ich hinzugefügt can_delete auch in die Fabrik.

    IngredientFormSet = inlineformset_factory(Recipe, Ingredient, fields=('description',), extra=3, can_delete=True) 
    InstructionFormSet = inlineformset_factory(Recipe, Instruction, fields=('number', 'description',), extra=1, can_delete=True) 
    
+0

Der Link in diesem Kommentar ist tot. – datakid

1

Ich glaube nicht, dass die regelmäßige Form der updateview den Kontext hinzugefügt werden muss, weil es dort sowieso ist. Eine funktionierende Updateview mit Inlineformsets könnte weniger kompliziert durchgeführt werden. Ich basiert diese auf dieser Question

class RecipeUpdateView(UpdateView): 
    model = Recipe 
    form_class = RecipeUpdateForm 
    success_url = "/foo/" 

    def get_success_url(self): 
     self.success_url = '/account/dashboard/' 
     return self.success_url 

    def get_object(self): 
     return #your object 

    def get_context_data(self, **kwargs): 
     context = super(ShoppingCartView, self).get_context_data(**kwargs) 
     if self.request.POST: 
      context['ingredient_form'] = IngredientFormSet(self.request.POST, instance=self.object) 
      context['instruction_form'] = InstructionFormSet(self.request.POST, instance=self.object) 
     else: 
      context['ingredient_form'] = IngredientFormSet(instance=self.object) 
      context['instruction_form'] = InstructionFormSet(instance=self.object) 
     return context 

    def form_valid(self, form): 
     context = self.get_context_data() 
     ingredient_form = context['ingredient_form'] 
     instruction_form = context['instruction_form'] 
     if ingredient_form.is_valid() and instruction_form.is_valid(): 
      self.object = form.save() 
      ingredient_form.instance = self.object 
      ingredient_form.save() 
      instruction_form.instance = self.object 
      instruction_form.save() 
     return self.render_to_response(self.get_context_data(form=form)) 
Verwandte Themen