基于Django类的CreateView和UpdateView,具有多个内联表单集

ran*_*enz 18 django django-class-based-views

我一直在尝试使用多个内联表单集来执行基于Django类的CreateView和UpdateView

CreateView工作正常,但UpdateView无法正常工作,如果有人尝试使用多个内联formset的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))
Run Code Online (Sandbox Code Playgroud)

提前致谢.

小智 6

我的猜测是你不能这样做

self.object = None
Run Code Online (Sandbox Code Playgroud)

post在一个覆盖的方法UpdateView.所以,试试吧

self.object = self.get_object()
Run Code Online (Sandbox Code Playgroud)

相反,一旦你在这种情况下已经有一个对象实例.


use*_*456 6

我不认为必须将 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))
Run Code Online (Sandbox Code Playgroud)


Gar*_*nzo 5

我不确定您是否找到答案,但是在这里找到的答案中记录了UpdateView的工作版本:

内联表单集的UpdateView试图保存重复记录吗?

  • 这个链接提供了方法。注意在 get 函数的表单集定义中使用 `instance`,而不是 `initial`,并使用 `self.object = self.get_object` 而不是 `None` (2认同)