Ответ 1
Я предполагаю, что вы не можете сделать
self.object = None
для перезаписанного метода post
в UpdateView
. Итак, попробуйте
self.object = self.get_object()
вместо этого, как только вы уже имеете экземпляр объекта в этом случае.
Я пытаюсь создать DjView на основе классов CreateView и UpdateView с несколькими встроенными формами
CreateView отлично работает, но UpdateView работает некорректно. Если кто-то попробовал UpdateView с несколькими встроенными наборами форм, любой пробовал использовать фрагмент кода 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))
Спасибо заранее.
Я предполагаю, что вы не можете сделать
self.object = None
для перезаписанного метода post
в UpdateView
. Итак, попробуйте
self.object = self.get_object()
вместо этого, как только вы уже имеете экземпляр объекта в этом случае.
Я не уверен, что вы нашли ответ, но у меня есть рабочая версия UpdateView, описанная в моем ответе, найденном здесь:
UpdateView с встроенными наборами форм, которые пытаются сохранить повторяющиеся записи?
Я не думаю, что обычная форма updateview должна быть добавлена в контекст, потому что она есть в любом случае. Работающий Updateview с inlineformsets может быть достигнут менее сложным. Я основал это на этом вопросе
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))
Итак, я узнаю модели из этого post. Чтобы обновить UpdateView, вам нужно будет сделать как минимум две, а может быть, три вещи:
Обновите self.object = self.get_object()
- после этого ваша способность динамически добавлять должна работать.
Для правильного обновления динамических удалений вам нужно будет изменить шаблон с помощью формы .DELETE(в двух местах, ингредиентах и инструкциях).
{{ form.description }}
{% if form.instance.pk %}{{ form.DELETE }}{% endif %}
Не уверен, что это было необходимо, но я добавил can_delete в factory тоже.
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)