Django ModelForms - “实例”没有按预期工作

Posted

技术标签:

【中文标题】Django ModelForms - “实例”没有按预期工作【英文标题】:Django ModelForms - 'instance' not working as expected 【发布时间】:2011-04-21 22:32:59 【问题描述】:

我有一个模型表单,可以创建新模型或编辑现有模型 - 这很简单,应该可以工作,但由于某种原因,我每次都会得到一个新实例。

场景是这是电子商务订单的第一步。用户必须填写一些描述订单的信息(存储在模型中)。我创建模型,保存它,然后重定向到下一个视图,让用户输入他们的抄送信息。我将模型粘贴在会话中,因此我不必在下一个视图中进行数据库查找。第二个(抄送信息)视图的模板中有一个链接,可让用户返回第一个视图以编辑他们的订单。

# 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”字段(不是同时),但是我的表单根本没有呈现。

我怀疑我让这变得比它需要的更复杂,但我现在卡住了,可以使用一些反馈。提前致谢。

【问题讨论】:

“我相信这是因为我已经限制了表单中的字段”......那么如果您不限制表单中的字段会发生什么? 【参考方案1】:

这很有趣。这是我的尝试。考虑这一行:

form = MyForm(request.POST)

你能检查request.POST的内容吗?具体来说,检查是否有关于正在编辑模型的哪个 instance 的任何信息。你会发现没有。换句话说,每次您在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():
              ....

【讨论】:

进行了一些小改动(从 request.session 而不是 URL 中获取现有模型),就成功了。不知道 MyForm(request.POST, instance=instance),谢谢!

以上是关于Django ModelForms - “实例”没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

django 中的 ModelForms 是不是仅用于发布?

django ModelForms - 我做对了吗?

在 ModelForms 中继承 formfield_callback 的 Django 问题

在 ModelForms 中继承 formfield_callback 的 Django 问题

基于 Django 类的通用视图和 ModelForms

显示 ModelForms 的 django 表单验证错误