引き続きメトリックに保存したいので、変換する可能性があるのは次の場合だけです。
- ユーザー入力
- ユーザーへのデータの表示
ユーザー入力には、メトリック値を出力するカスタム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])
num
を使用してフォームをインスタンス化すると、 inのメトリックのデフォルト設定TestForm
が上書きされる可能性があるinitial={'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"
次に、テンプレートでは次のようになります。
{{a_value|convert_units:user_pref}}
もちろん、これはすべてマイル/キロメートルを変換するだけです。ウィジェット/フィールドを複製して変更またはサブクラス化する必要があり、おそらくポンド/キログラムなどの他のものをカバーするためにいくつかのテンプレート フィルターが必要です。