web-dev-qa-db-ja.com

DjangoクラスベースのCreateViewおよびUpdateViewと複数のインラインフォームセット

DjangoクラスベースのCreateViewおよびUpdateViewを複数のインラインフォームセットで実行しようとしています

CreateViewは正常に機能しますが、UpdateViewが正しく機能しません。複数のインラインフォームセットでUpdateViewを試した場合、plsは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))

前もって感謝します。

18
ranjithtenz

私はあなたができないと思います

self.object = None

postの上書きされたUpdateViewメソッドについて。だから、試してみてください

self.object = self.get_object()

代わりに、この場合はすでにオブジェクトインスタンスが存在します。

6
DiogoLR

あなたが答えを見つけたかどうかはわかりませんが、私はここで私の答えに文書化されたUpdateViewの作業バージョンを文書化しています:

重複レコードを保存しようとするインラインフォームセットを含むUpdateView?

5
Garfonzo

とにかくそこにあるので、updateviewの通常のフォームをコンテキストに追加する必要があるとは思いません。 inlineformsetsを使用した作業中のUpdateviewは、それほど複雑ではありません。私はこれに基づいています 質問

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

したがって、私はこの post のモデルを認識します。 UpdateViewを適切に機能させるには、少なくとも2つ、場合によっては3つのことを行う必要があります。

  1. self.object = self.get_object()を更新します-その後、動的に追加する機能が動作します。

  2. 動的削除を適切に更新するには、form.DELETEを使用してテンプレートを変更する必要があります(2つの場所で、成分と指示)。

    {{ form.description }}
    {% if form.instance.pk %}{{ form.DELETE }}{% endif %}
    
  3. 必要かどうかはわかりませんが、can_deleteもファクトリに追加しました。

    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
eezis