example - modelform django
Django basado en clases CreateView y UpdateView con mĂșltiples conjuntos de formularios en lĂnea (4)
He estado tratando de hacer Django basado en clases CreateView y UpdateView con múltiples conjuntos de formularios en línea
CreateView funciona bien, pero UpdateView no funciona correctamente. Si alguien probó UpdateView con varios conjuntos de formularios en línea, cualquiera intentó por favor compartir el fragmento de código de 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))
Gracias por adelantado.
Así que reconozco los modelos de este post . Para que UpdateView funcione correctamente, tendrá que hacer al menos dos, tal vez tres cosas:
Actualice
self.object = self.get_object()
: después de eso, su capacidad para agregar dinámicamente debería funcionar.Para obtener la actualización dinámica de las eliminaciones correctamente, deberá modificar la plantilla con form.DELETE (en dos lugares, los ingredientes y las instrucciones).
{{ form.description }} {% if form.instance.pk %}{{ form.DELETE }}{% endif %}
No estoy seguro de que fuera necesario, pero también agregué can_delete a la fábrica.
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)
Mi conjetura es que no puedes hacer
self.object = None
en el método post
sobrescrito en un UpdateView
. Entonces prueba
self.object = self.get_object()
en cambio, una vez que ya tienes una instancia de objeto en este caso.
No creo que la forma regular de la vista de actualización deba agregarse al contexto porque está ahí de todos modos. Una actualización de trabajo con inlineformsets podría lograrse de manera menos complicada. Basé esto en esta 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))
No estoy seguro de haber encontrado una respuesta, pero tengo una versión funcional de UpdateView documentada en mi respuesta encontrada aquí:
¿UpdateView con conjuntos de formularios en línea tratando de guardar registros duplicados?