Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django class-based CreateView and UpdateView with multiple inline formsets

Tags:

I have been trying to do Django class-based CreateView and UpdateView with multiple inline formsets

CreateView works fine but UpdateView is not working properly, If anyone tried UpdateView with multiple inline formsets, anyone tried pls share 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)) 

Thanks in advance.

like image 494
ranjithtenz Avatar asked Jan 10 '15 13:01

ranjithtenz


2 Answers

I don't think that the regular form of the updateview has to be added to the context because it is there anyways. A working Updateview with inlineformsets could be achieved less complicated. I based this on this 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(RecipeUpdateView, 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)) 
like image 76
LonnyT Avatar answered Oct 05 '22 10:10

LonnyT


My guess is that you can't do

self.object = None 

on overwritten post method in a UpdateView. So, try

self.object = self.get_object() 

instead, once you already have an object instance in this case.

like image 21
Diogo Avatar answered Oct 05 '22 11:10

Diogo