【问题标题】:Django form - type of variable changes when reloaded after validation errorDjango表单-验证错误后重新加载时变量的类型发生变化
【发布时间】:2018-03-01 06:56:51
【问题描述】:

我在这方面花了一些时间,但无法弄清楚以下行为的确切原因。

我有一个 Django 表单,在模板中我试图查看一个整数是否存在于列表中,然后对其进行处理。

{% if pk in form.area.value %} {# form.area.value is a list like [7,21] #}
    do something
{% endif%}

除了在验证错误后重新加载表单的情况外,一切正常。在这种情况下,我要比较的列表会自行转换为字符串列表(来自整数列表),if 测试失败。所以上面的[7,21]变成了['7','21']

如果有帮助,这就是表单在视图中呈现的方式:

在 GET 请求中(if 条件正常):

form = SchoolForm(instance = school)
return render(request, 'edit-school.html', {'form': form, 'school_id': school_id})

POST 请求后(模板中的 if 条件失败):

form = SchoolForm(request.POST or None, instance=school, request=request)
return render(request, 'edit-school.html', {'form': form, 'school_id': school_id})

更新:通过在表单中​​声明另一种方法(如@bruno 在下面的答案中所建议)并使用它在模板中。这是代码 sn-p(关于它在模板中的使用方式):

<div class="checkbox">
    {% for pk, choice in form.area.field.widget.choices %}
        <label for="id_{{sub_type}}_{{form.area.name}}_{{ forloop.counter0 }}">
            <input class="form-control" id="id_{{sub_type}}_{{form.area.name}}_{{ forloop.counter0 }}" name="{{form.area.name}}" type="checkbox" value="{{ pk }}" {% if pk in form.area_values %} checked="checked" {% endif %}/>
            <span class="badge">{{ choice }}</span>
        </label>
    {% endfor %}
</div>

【问题讨论】:

  • 我看到了一个类似的问题here,没有一个赞成或接受的答案。不过,我已尝试更详细地解释上述内容。
  • 这是正常行为。问题是为什么您需要检查表单字段的值。您应该根据模板变量做出决定。它们保证类型稳定。
  • @Melvyn - 谢谢。 form.areaMultipleChoiceField。根据是否检查了一个值,我在模板中做了一些花哨的事情。我没有使用默认的CheckboxSelectMultiple 并自己渲染复选框。目前如何使用模板变量似乎并不简单,但会尝试弄清楚。
  • 那是由学校模型填充的,对吗?所以学校的模型实例决定了面积的值是多少。因此,不要提供school_id,而是提供模型:{ 'school': school, ... }。然后你只需使用school.area 来做一些花哨的事情。这似乎有点令人生畏,所以如果你提供 SchoolForm 和 School 模型的相关部分,我会发布一个答案来连接所有的点。
  • @Melvyn 不,它还没有保存在模型中。出现验证错误时会出现此页面。因此,这些值来自用户在提交之前填写的表单(并且页面现在使用表单数据和验证错误消息重新呈现)

标签: python django django-forms django-templates


【解决方案1】:

用户提交表单后,{{ form.area.value }}(在 Python 中解析为 form["area"].value)将填充来自 request.POST 的原始数据,这些数据确实是字符串。

您没有在模板中清楚地解释您要尝试做什么样的“花哨的事情”,因此很难为您的用例提供“最佳”解决方案,但作为一般规则,模板不是任何花哨的地方 - 这就是 Python 的用途(在您的视图中、在您的表单中、在自定义模板标签或过滤器等中)。

一个非常快速和简单的解决方案是向您的表单添加一个方法,该方法将area boundfield 值作为整数返回:

class SchoolForm(forms.ModelForm):
    # your code here

    def area_values(self):
        # XXX this might require some conditionals or
        # error handling to be failsafe 
        # works with both python 2.x and 3.x
        return [int(v) for v in self["area"].value()]

然后在您的模板中,将 {% if pk in form.area.value %} 替换为 {% if pk in form.area_values %}

【讨论】:

  • 很好的答案,但 area_values 最好返回 [choice for choice, label in self.choices]。如果他决定将它们更改为其他类型,这将保持类型稳定。
  • 据我了解,OP 想要的是选定的值(作为来自实例的初始值或来自提交后的 request.POST 的初始值),而不是您的代码将提供的整套可用选择返回。
  • 确认,你是对的。查看ChoiceField.valid_value,它会比较选择的文本表示。但它也解释了 optgroups。也许最好的方法是遵循该逻辑,而不是返回布尔值,而是从外部循环返回 k。然后像这样创建列表。 (作为更通用的解决方案)
  • 好吧,直到我们真正看到 OP 正在尝试做的事情,没有“最佳”解决方案......
  • 编辑:使用列表comp代替map直接兼容python 2.x和3.x
猜你喜欢
  • 2016-07-07
  • 2020-04-08
  • 2019-01-05
  • 2015-04-06
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
  • 2017-03-08
相关资源
最近更新 更多