Django——一个视图上有多个表单——将未创建的对象传递给第二个表单



我想知道是否有可能在一个视图上创建两个基于Django模型的表单,其中一个视图需要第二个创建的对象(外键(。我将举一个例子让它更容易理解。

我有这些型号:

class Recipe(models.Model):
name = models.CharField(max_length=200)

def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(max_length=200)
quantity = models.CharField(max_length=200)
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
def __str__(self):
return self.name

如您所见,配料模型以配方为参数。我想制作一个表格,允许用户制作新的配方和配料(或配料(,配方字段将由在同一视图中创建的配方填充

我试着用这种方式

from .models import Ingredient, Recipe
from django.forms import ModelForm
class IngredientForm(ModelForm):
class Meta:
model = Ingredient
fields = ['name', 'quantity']
class RecipeForm(ModelForm):
class Meta:
model = Recipe
fields = ['name']
def recipeAndIngredientsCreationView(request):
form1 = RecipeForm()
form2 = IngredientForm()
if request.method == "POST":

data1 = {
'csrfmiddlewaretoken': request.POST['csrfmiddlewaretoken'],
'name': request.POST['name'],
}
form1 = RecipeForm(data1)

if form1.is_valid():
form1.save()
print("recipe created")

data2 = {
'csrfmiddlewaretoken': request.POST['csrfmiddlewaretoken'],
'name': request.POST['name'],
'quantity' : request.POST['quantity'],
'recipe_id': Recipe.objects.get(name=request.POST['name']).id,
}
form1 = IngredientForm(data2)

if form2.is_valid():
form2.save()
return redirect('home')

context = {'form1':form1, 'form2':form2}
return render(request, 'recipes/create_recipe.html', context)

不要注意配方和配料会有相同的名字,我稍后会做一些修改来修复它。

配方制作没有任何问题,但配料有一些问题,我应该改变什么才能让它发挥作用,或者改变我的方法,以完全不同的方式制作形式?

编辑:我不确定"recipe_id"是否是传递id的正确方式,但我遇到了一个错误,需要填写带有该名称的字段,所以我用的方式

第2版:

我做了一点研究,得出了这一点:

def recipe_create_view(request):
context = {}
form = RecipeForm(request.POST or None)
IngredientFormset = formset_factory(IngredientForm)
formset = IngredientFormset(request.POST or None)
context['form'] = form
context['formset']  = formset
if request.method == "POST":
if form.is_valid() and formset.is_valid():

parent = form.save(commit=False)

parent.save()
for form in formset:
child = form.save(commit=False)
child.recipe = parent
child.save()
return render(request, 'recipes/create_recipe.html', context)

但它仍然不起作用,我应该改变什么?我甚至接近我想要的吗?

首先,您需要准备表单:

from django import forms
from django.forms.models import inlineformset_factory
from .models import Ingredient, Recipe

class RecipeForm(ModelForm):
class Meta:
model = Recipe
fields = ['name']

IngredientInlineFormset = inlineformset_factory(Recipe, Ingredient, fields='__all__', extra=1)

inlineformset_factory是Django文档的模型形式函数

extra表示应在模板中显示多少表单集

那么在你看来:

def new_recipe(request):
if request.method == 'POST':
form_inline = IngredientInlineFormset(request.POST)
form = RecipeForm(request.POST)
if form.is_valid() and form_inline.is_valid():
instance = form.save()
form_inline.instance = instance
form_inline.save()
return redirect('index')
else:
print(form.errors, form_inline.errors)
else:
form_inline = IngredientInlineFormset()
form = RecipeForm()
context = {
'form': form,
'form_inline': form_inline,
}
return render(request, 'new_recipe.html', context)

在这里,您检查两个表单是否都有效,然后首先保存父模型表单并将其分配给inlineformset(我们需要有新Recipe对象的id(。

最后是模板中的表单:

<form method="post">
{% csrf_token %}
{{ form }}
{{ form_inline.management_form }}
{{ form_inline.non_form_errors }}
{% for form in form_inline %}
<p>{{ form }}</p>
{% endfor %}
<button type="submit">Add Recipe with Ingredients</button>
</form>

这是一个基本的例子。请记住包含inlineformset的management_form。慢慢来,我花了很长时间才弄明白。

将名称表单输入添加到所有表单中,并使用在def-post中控制视图

if request.POST['name_form] == 'form1':
#
elif request.POST['name_form'] == 'form2':
#

最新更新