formularios form example ejemplo avanzados django django-class-based-views

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:

  1. Actualice self.object = self.get_object() : después de eso, su capacidad para agregar dinámicamente debería funcionar.

  2. 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 %}

  3. 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))