【问题标题】:In Django 1.4, do Form.has_changed() and Form.changed_data, which are undocumented, work as expected?在 Django 1.4 中,未记录的 Form.has_changed() 和 Form.changed_data 是否按预期工作?
【发布时间】:2012-07-27 11:48:37
【问题描述】:

从源代码中,您可以看到 Django 1.4 的 Form 类有一个 has_changed() 方法和 changed_data 属性,它们看起来相当有用,但没有记录。我的问题是:按预期进行这些工作,即:

  • Form.clean()中,Form.has_changed()如果任何表单数据发生变化,则返回True,否则返回False
  • Form.clean() 中,Form.changed_data 是值已更改的字段名称列表。

如果是这样,除了关于使用未记录功能的常见警告/危险(即可能会更改、不受支持等)之外,是否有任何不使用它们的具体原因?

注意 1:要使这些与自定义小部件一起使用,这些小部件需要有一个 _has_changed() 方法,该方法是为内置小部件定义的。

注意 2:有趣的是,文档确实包含了对 Formset.has_changed() 方法的临时提及,但没有提及 Form.has_changed()

【问题讨论】:

  • 很棒的功能。感谢您的解释。 ;-)

标签: django django-forms


【解决方案1】:

您可以在两个条件下依赖这些方法:

  1. 您也可以在发布请求期间将初始数据字典传递给表单构造函数。
  2. 您不要使用带有show_hidden_initial=True 的字段。 (这些字段的问题是用户也可以提交用于比较的初始值,因此它不可信。)

【讨论】:

  • 谢谢!这个答案为我引出了另一个问题——show_hidden_initial 是什么?我在 Django 文档中找不到它...
  • show_hidden_initial 只是意味着在包含该字段初始值的原始 html 输出旁边生成了第二个隐藏字段。
【解决方案2】:

在进一步研究了 Django 源代码之后,在 Florian 的回答中提供了有用的提示,我可以报告 has_changedchanged_data 确实按照我的问题中的描述工作只要表单有方法获取初始数据以比较新数据。

所以问题是,从 POST 数据创建的表单如何知道 GET 表单的初始值是什么?简短的回答是它没有——除非你以某种方式告诉它。有两种说法:

  1. 通过表单的 initial 关键字参数和/或字段的 initial 关键字参数,与您告诉 GET 表单初始值的方式完全相同。注意:如果你这样做,你需要确保你的 GET 和 POST 表单使用相同的值。这是唯一真正可靠的方法,因为您可以直接控制初始值。

  2. 通过将每个适用字段的 show_hidden_initial 关键字参数设置为 True,让 Django 完成从 GET 中记住初始值的工作。对于这些字段,Django 将具有初始值的隐藏输入元素呈现到 GET 表单的 HTML 中。稍后,当您在 POST 表单上调用 has_changedchanged_data 时,对于任何以 show_hidden_initialTrue 的字段,Django 将自动从 POST 数据中的隐藏输入元素中获取初始值(取代来自initial 表单或字段参数)。注意:与任何依赖 POST 数据的方法一样,这种方法最终是不可靠的,因为隐藏输入的值尽管被隐藏了仍然可以更改。

【讨论】:

  • 您有机会了解如何使用initial 关键字。您是在发送表单时使用它还是在表单返回时使用它?它如何与instance 一起使用?
【解决方案3】:

这是一段代码,可以按照@Ghopper21 的建议进行操作。为了获取初始数据,我使用 QueryDict 上的 values() 函数。它返回一个包含属于该对象的数据的字典。一个重要的警告是我没有检查它如何处理外键引用。

saveStudentView(request,studentID):
    existingData = Student.objects.filter(id=paperID).values()[0]
    form = StudentForm(request.POST)
    if form.is_valid():
        form = StudentForm(request.POST, initial=existingData)
        if not form.has_changed():
            //Tell the user nothing has changed
        else:
            //Do other stuff

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 2015-07-19
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多