Django自定义表单字段在呈现和提交中更改值

时间:2016-03-18 17:47:48

标签: python django forms django-forms

我已经实现了一个自定义表单字段,用于将表示米单位的模型整数字段转换为表示公里单位的表单浮点字段。 即在我的模型整数字段中保存的3500米将在表单浮点字段中显示3,5,并且当表单被发送时,它需要转换回整数。为了达到这个目的,我在显示之前将值除以1000,并在保存时将其乘以1000。

渲染部分工作正常(在窗口小部件渲染中除以1000,或者在窗体字段中除以prepare_value)。

当表单抛出错误并且需要重新显示值时,问题就出现了。在这种情况下,表单值将传递给它(浮点数为3,5)并且值被重新划分并显示为0,0035。所以我不需要再将值除以1000。

class KmInput(NumberInput):

    def _format_value(self, value):
        try:
            return str(float(value or 0) / 1000)
        except ValueError:
            return value

class MeterToKmField(forms.FloatField):
    widget = KmInput

    def __init__(self, max_value=None, *args, **kwargs):
        super(MeterToKmField, self).__init__(max_value, 0, *args, **kwargs)

    def to_python(self, value):
        result = super(MeterToKmField, self).to_python(value)
        result *= 1000
        return result

我错过了什么吗?

UPDATE:

正如Peter DeGlopper建议的那样,我已经在我的自定义小部件中实现了_format_value,但是当表单引发错误时,仍然会调用此方法,使得已经除以1000的值再次被分割。 这就是我所做的:

<div id="main">

  <div>
    <button rv-on-click="toggle">
      Toggle
    </button>
  </div>

  <div>
    Dynamic headers sould be visible: {showDynamicHeaders}
  </div>

  <table>
    <thead>
      <tr>
        <th>Fixed header</th>
        <th>Fixed header</th>
        <th rv-show="showDynamicHeaders" rv-each-item="items">
          {item.name}
        </th>
      </tr>
    </thead>
  </table>

</div>

2 个答案:

答案 0 :(得分:0)

通过查看日期字段的实现方式,看起来最好的方法是使用自定义字段(以便进行to_python自定义)和自定义窗口小部件 - 实现{{ 1}}。

类似于:

_format_value

然后是上面的表格。

答案 1 :(得分:0)

我有一个类似的问题,显示内部存储为整数的价格字段。这就是我所学到的:

您可以覆盖字段中的bounddata方法以返回初始数据而不是输入数据。绑定数据的结果稍后仍会通过prepare_value,因此您可以像以前一样实现此方法:

class MeterToKmField(forms.FloatField):
    def bound_data(self, data, initial):
        return initial

    def prepare_value(self,value):
        #...same as before, just divide by 1000

但是,这可能不是您想要的,因为用户所做的更改可能会丢失。因此,我首选的解决方案是基于以下事实:prepare_value中的绑定值是unicode,未绑定的值是整数。所以你可以这样做:

class MeterToKmField(forms.FloatField):
    def prepare_value(self, value):
        #python 2.x ,use str instead of basestring for python 3.x
        if isinstance(value, basestring):
            #in case of bound data, is already divided by 100
            return value
        else:
            #raw data
            return float(value)/ 1000

    #don't overwrite bound_data in this case