Kas*_* B. 6 python django units-of-measurement unit-conversion
我想在我的Django项目中实现不同的测量系统,以便用户可以选择他们想要使用公制或英制单位.但是,我不知道这样做的正确方法是什么.
目前我的模型没有测量单位感知字段(它们是整数/十进制字段),我希望我不必直接更改字段.
由于我当前的数据库值已经表示度量值,我计划保持这种方式,这意味着我将不得不处理用户输入/值输出转换.Pint似乎是一个很好的图书馆.
如果没有在应用程序中编辑字段,但是使用注册模式或其他内容,这是否可行?我想要实现的是这样的:
这种解决方案可以更容易地将其插入现有应用程序,因为在应用程序中不会直接更改任何字段和表单.使用注册模式的基本示例会很有帮助.
欢迎提供任何相关信息,包括在非Django项目中如何完成此操作的一般概念和模式.
由于您想继续以公制存储,因此您唯一可能进行转换的时间是:
对于用户输入,您可以使用自定义MultiValueField和自定义MultiWidget,它将输出指标值。
from django import forms
from django.forms import widgets,Form, CharField, MultiValueField, ChoiceField, DecimalField
imperial = "imp"
imperial_display = "Miles"
metric = "met"
metric_display = "Kilometers"
unit_types = ((imperial, imperial_display), (metric, metric_display))
#You would use that library instead of this, and maybe not floats
def to_imperial(val):
return float(val) * 1.60934
def to_metric(val):
return float(val) / 0.62137
class NumberUnitWidget(widgets.MultiWidget):
def __init__(self, default_unit=None, attrs=None):
#I feel like this default_unit thing I'm doing is ugly
#but I couldn't think of another way to get the decompress
#to know which unit to convert to
self.default_unit = default_unit
_widgets = [
widgets.NumberInput(attrs=attrs),
widgets.Select(attrs=attrs, choices=unit_types),
]
super(NumberUnitWidget, self).__init__(_widgets, attrs)
#convert a single value to list for the form
def decompress(self, value):
if value:
if self.default_unit == imperial:
return [to_imperial(value), self.default_unit]
#value is the correct format
return [value, self.default_unit]
return [0, self.default_unit]
class NumberUnitField(MultiValueField):
def __init__(self, *args, **kwargs):
_widget = NumberUnitWidget(default_unit=kwargs['initial'][0])
fields = [
DecimalField(label="Number!"),
ChoiceField(choices=unit_types)
]
super(NumberUnitField, self).__init__(fields=fields, widget = _widget, *args, **kwargs)
def compress(self, values):
if values[1] == imperial:
#They inputed using imperial, convert to kilo
return to_metric(values[0])
return values[0] #You dont need to convert because its in the format you want
class TestForm(Form):
name = CharField()
num = NumberUnitField(initial=[None, metric])
Run Code Online (Sandbox Code Playgroud)
当您使用实例化表单时,可以覆盖numin指标的默认设置,以便您可以从用户的个人资料中插入用户首选项。TestForminitial={'num':[None,'imp']}
使用上面的表单,当您看到表单is_valid()返回给您的数据将采用公制时。
当用户看到表单时,它将显示为 Django NumberInput,后跟一个已选择默认设置的选择。
为了显示数据,您可以使用模板过滤器。这是一个简单的给你一个想法
from django import template
register = template.Library()
@register.filter
def convert_units(value, user_pref):
#You probably want to use that library you found here to do conversions
#instead of what i've used.
if user_pref == "met":
return str(value) + " Kilometers"
else:
return str(float(value)/ 1.60934) + " Miles"
Run Code Online (Sandbox Code Playgroud)
然后在模板中它看起来像这样:
{{a_value|convert_units:user_pref}}
Run Code Online (Sandbox Code Playgroud)
当然,所有这些只是转换英里/公里。您必须复制、更改或子类化小部件/字段,并且可能有更多模板过滤器来覆盖其他内容,例如磅/千克。
| 归档时间: |
|
| 查看次数: |
1074 次 |
| 最近记录: |