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

Python Django自定义表单字段在呈现和提交中更改值,python,django,forms,django-forms,Python,Django,Forms,Django Forms,我已经实现了一个自定义表单字段,用于将表示米单位的模型整数字段转换为表示公里单位的表单浮点字段。 i、 e.保存在“我的模型整数”字段中的3500米将在“形式浮点”字段中显示3,5,当发送形式时,需要将其转换回整数。为了实现这一点,我在显示之前将该值除以1000,在保存时将其乘以1000 渲染部分工作正常(在小部件渲染中除以1000,或者在表单字段中准备_值) 当表单抛出错误并且需要重新显示值时,就会出现问题。在这种情况下,表单值将被传递给它(即浮点值3,5),该值将被重新分配并显示为00035

我已经实现了一个自定义表单字段,用于将表示米单位的模型整数字段转换为表示公里单位的表单浮点字段。 i、 e.保存在“我的模型整数”字段中的3500米将在“形式浮点”字段中显示3,5,当发送形式时,需要将其转换回整数。为了实现这一点,我在显示之前将该值除以1000,在保存时将其乘以1000

渲染部分工作正常(在小部件渲染中除以1000,或者在表单字段中准备_值)

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

class KmInput(NumberInput):

    def render(self, name, value, attrs=None):
        try:
            value = str(float(value or 0) / 1000)
        except ValueError:
            pass
        return super(KmInput, self).render(name, value, attrs)

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)
        value *= 1000
        return result

class DistanceForm(forms.ModelForm):
    distance = MeterToKmField(help_text="km")

    class Meta:
        model = Distance
我错过什么了吗

更新: 正如所建议的,我已经在我的自定义小部件中实现了_format_value,但是当表单出现错误时,我仍然会调用这个方法,使已经被除以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

从日期字段的实现来看,最好的方法是使用自定义字段(这样您就可以对python进行
自定义)和自定义小部件(实现
\u format\u value

比如:

class KmInput(NumberInput):
    def _format_value(self, value):
        return str(value / 1000)
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

然后是上面的表单。

我在显示内部存储为整数的价格字段时遇到了类似的问题。这是我学到的:

您可以覆盖字段中的bounddata方法,以返回初始数据而不是输入的数据。绑定数据的结果稍后仍将通过prepare_值,因此您可以使用与以前相同的方法实现此功能:

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_值中的绑定值是unicode,而未绑定值是整数。所以你可以这样做:

class KmInput(NumberInput):
    def _format_value(self, value):
        return str(value / 1000)
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

我已经用这种新的方法更新了这个问题,请检查一下。然后,我将不得不花一些时间回顾源代码。日期内容应该是一个很好的例子-这是另一种情况,其中字符串表示形式需要不同于Python版本,但需要在字符串表示形式中向用户返回无效值。在向用户返回无效值时,有没有办法避免调用_format_value方法?或者,如果值是无效值,有没有办法知道inside\u format\u value方法?这就是我需要回顾的。看起来确实应该有一种方法来区分表单是从
POST
对象(如重新显示时)还是从实例中获取值。这是一个检测值是否已准备好的好技巧。