2015-01-10 4 views
14

ho cercato di fare Django CreateView basato su classi e UpdateView con più formsets lineaDjango CreateView basato su classi e UpdateView con più formsets linea

CreateView funziona bene, ma UpdateView non funziona correttamente, se qualcuno ha provato UpdateView con più moduli in linea, chiunque ha provato pls condivide lo snippet di codice updateview.

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

Grazie in anticipo.

+1

originale [vista di classe a base di Django con più formsets linea] (http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/) –

+0

@vishes_shell quel collegamento è morto ora. – datakid

risposta

5

La mia ipotesi è che non si può fare

self.object = None 

su sovrascritto post metodo in una UpdateView. Quindi, provare

self.object = self.get_object() 

invece, una volta che si dispone già di un'istanza di un oggetto, in questo caso.

4

non sono sicuro se hai trovato una risposta, ma ho una versione funzionante di UpdateView documentato nella mia risposta trovato qui:

UpdateView with inline formsets trying to save duplicate records?

+1

Questo collegamento fornisce la via. Presta attenzione all'uso di 'instance', al contrario di' initial', nella definizione formset della funzione get, e 'self.object = self.get_object' invece di' None' –

-1

Così ho riconoscere i modelli formano questo post. Per ottenere UpdateView funziona correttamente che si sta per avere a che fare almeno due, forse tre cose:

  1. Aggiornare il self.object = self.get_object() - dopo che, la vostra capacità di aggiungere in modo dinamico dovrebbe funzionare.

  2. Per ottenere la cancellazione dinamica dell'aggiornamento correttamente, è necessario modificare il modello con form.DELETE (in due punti, gli ingredienti e le istruzioni).

    {{ form.description }} 
    {% if form.instance.pk %}{{ form.DELETE }}{% endif %} 
    
  3. Non sono sicuro che era necessario, ma ho aggiunto can_delete alla fabbrica anche.

    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

Il link in questo commento è morto. – datakid

1

non credo che la forma regolare del updateview deve essere aggiunto al contesto perché è lì comunque. Una vista Aggiornamenti funzionante con inlineformsets potrebbe essere ottenuta in modo meno complicato. Ho basato questo su questo post 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))