我有一个可以创建新模型或编辑现有模型的模型 - 这很简单并且应该可以工作,但出于某种原因我每次都会得到一个新实例。
情景是这是电子商务订单的第一步。用户必须填写描述订单的一些信息(存储在模型中)。我创建模型,保存它,然后重定向到下一个视图,以便用户输入他们的cc信息。我将模型粘贴在会话中,因此我不必在下一个视图中进行数据库查找。第二个(cc信息)视图的模板中有一个链接,允许用户返回第一个视图来编辑他们的订单。
# forms.py
class MyForm(forms.ModelForm):
class Meta:
fields = ('field1', 'field2')
model = MyModel
# views.py
def create_or_update(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
m = form.save(commit=False)
# update some other fields that aren't in the form
m.field3 = 'blah'
m.field4 = 'blah'
m.save()
request.session['m'] = m
return HttpResponseRedirect(reverse('enter_cc_info'))
# invalid form, render template
...
else:
# check to see if we're coming back to edit an existing model
# this part works, I get an instance as expected
m = request.session.get('m', None)
if m:
instance = get_object_or_None(MyModel, id=m.id)
if instance:
form = MyForm(instance=instance)
else:
# can't find it in the DB, but it's in the session
form = MyForm({'field1': m.field1, 'field2': m.field2})
else:
form = MyForm()
# render the form
...
如果我在调试器中单步执行,当我返回视图以编辑创建表单的顺序时,实例设置为先前创建的模型,如预期的那样。但是,在后续POST中处理表单时,它会在调用form.save()时创建模型的新实例。
我相信这是因为我限制了表单中的字段,因此呈现的HTML中没有任何地方可以将id(或其他引用)存储到现有模型中。但是,我尝试添加'pk'和'id'字段(不是同时),但是我的表单根本没有呈现。
我怀疑我让它变得比它需要的更复杂,但我现在卡住了并且可以使用一些反馈。提前谢谢。
答案 0 :(得分:9)
这很有趣。这是我的抨击。考虑这一行:
form = MyForm(request.POST)
您可以查看request.POST
的内容吗?具体来说,检查是否有关于正在编辑模型的实例的信息。你会发现没有。换句话说,每次在POST
上保存表单时,都会创建一个新实例。
为什么会这样?当您创建传递instance=instance
关键字参数的表单时,您告诉Form类返回模型实例的实例。但是,当您将表单呈现模板时,此信息仅使用 来填写字段。也就是说,有关特定实例的信息将丢失。当你发布包时,有办法连接到旧实例。
你怎么能阻止这个?一个常见的习惯用法是将主键用作URL的一部分,并在POST
上查找实例。然后创建表单。在你的情况下,这意味着:
def create_or_update(request, instance_id):
# ^^^^^
# URL param
if request.method == 'POST':
instance = get_object_or_None(Model, pk = instance_id)
# ^^^^^
# Look up the instance
form = MyForm(request.POST, instance = instance)
# ^^^^^^^
# pass the instance now.
if form.is_valid():
....