【问题标题】:Django custom form field change value in render and submitDjango自定义表单字段在渲染和提交中更改值
【发布时间】:2016-07-05 14:26:44
【问题描述】:

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

渲染部分工作正常(在小部件渲染中除以 1000,或者更确切地说是表单字段中的 prepare_value)。

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

我错过了什么吗?

更新:

正如Peter DeGlopper 所建议的那样,我已经在我的自定义小部件中实现了 _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 django forms django-forms


    【解决方案1】:

    从查看日期字段的实现方式来看,最好的方法似乎是使用自定义字段(因此您可以进行 to_python 自定义)和自定义小部件 - 一个实现 _format_value 的小部件。

    比如:

    class KmInput(NumberInput):
        def _format_value(self, value):
            return str(value / 1000)
    

    然后是上面的表格。

    【讨论】:

    • 我已经用这种新方法更新了问题,请查看
    • 那么我将不得不花一些时间查看源代码。日期内容应该是一个很好的例子——这是另一种情况,字符串表示需要不同于 Python 版本,但无效值需要以字符串表示形式返回给用户。
    • 在向用户返回无效值时,有什么方法可以避免调用 _format_value 方法?或者有什么方法可以在 _format_value 方法中知道该值是否为无效值?
    • 这就是我需要审查的内容。似乎应该有一种方法来区分表单是从 POST 对象(当您重新显示时)还是从实例获取值。
    【解决方案2】:

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

    您可以覆盖字段中的 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
    

    【讨论】:

    • 一个很好的提示,用于检测值是否已经准备好。
    猜你喜欢
    • 2021-06-07
    • 2012-02-25
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    • 2018-07-07
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多