Skip to main content
 首页 » 编程设计

python之渲染和提交中的 Django 自定义表单字段更改值

2025年04月02日54lori

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

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

当表单抛出错误并且需要重新显示值时,问题就来了。在这种情况下,表单值将传递给它( float 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 

请您参考如下方法:

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

您可以覆盖字段中的 bounddata 方法以返回初始数据而不是输入的数据。绑定(bind)数据的结果稍后仍会通过 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 中的绑定(bind)值是 unicode 而未绑定(bind)值是整数这一事实。所以你可以这样做:

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