【问题标题】:Concept of different systems of measurement in Django projectDjango项目中不同测量系统的概念
【发布时间】:2014-06-16 12:18:19
【问题描述】:

我想在我的 Django 项目中实现不同的测量系统,以便用户可以选择他们想要使用公制还是英制单位。但是,我不知道这样做的正确方法是什么。

目前我的模型没有测量单位感知字段(它们是整数/十进制字段),我希望不必直接更改我的字段。

由于我当前的数据库值已经代表度量值,我计划保持这种方式,这意味着我将不得不处理用户输入/值输出转换。 Pint 似乎是一个很好的库。

这是否可以不编辑应用程序中的字段,而是使用registration patterns 或其他东西来代替?我想要实现的是这样的:

  1. 我定义了一个数据结构,其中包含不同的测量类型和可能的值,例如长度:米、英尺;重量:公斤、磅等。
  2. 我在每个应用程序目录中添加了一个新文件“measurements.py”或类似文件,其中包含保存测量值的字段。在这个字段中,我可以定义哪些是精确的测量字段以及它们的类型,例如 fields = {mymodelfield: length, myothermodelfield: weight} 等。
  3. 一些默认设置可以在设置文件中设置并在应用文件中覆盖,例如每次测量的默认单位(存储在数据库中的单位)。
  4. 用户为每种测量类型设置他的偏好。如前一点所述,每种测量类型都有默认单位。需要在偏好/默认(存储)单位不匹配的情况下转换用户输入的逻辑。绑定表单还应该能够将字段值从默认值转换回用户首选单位。

这种解决方案可以更轻松地将其插入现有应用程序,因为不会直接在应用程序中更改任何字段和表单。使用注册模式的基本示例会很有帮助。

欢迎提供任何相关信息,包括在非 Django 项目中如何做到这一点的一般想法和模式。

【问题讨论】:

  • 我设法根据 Dan 的回答和 recource 使用自定义字段实现单位转换。
  • 我刚刚发布了一个集成了 pint 和 django 的 pypi 小库,与上面的非常相似。看看 -> github.com/bharling/django-pint
  • 此时我可以建议django-measurement吗?我想这将是注册模式的有效选项。或者,正如您所说,“由于不应直接在应用程序中更改任何字段和表单”,您可以创建其他模型并将其关联起来。该库充满了处理测量单位的类,还可以帮助将其与模型字段一起存储。

标签: python django units-of-measurement unit-conversion


【解决方案1】:

由于您想继续以公制存储,那么您唯一可能转换的时间是:

  1. 用户输入
  2. 向用户显示数据

对于用户输入,您可以使用自定义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])

当您使用initial={'num':[None,'imp']} 实例化表单时,可以覆盖TestFormnum 的默认度量设置,以便您可以从他们的个人资料中插入用户首选项。

使用上面的表格当你看到is_valid()这个表格返回给你的数据是公制的。

当用户看到表单时,它将显示为 Django NumberInput,后跟一个已选择默认设置的选择。

为了显示数据,您可以使用template filter。给大家一个简单的思路

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}}

当然,所有这些只是转换英里/公里。您必须复制和更改小部件/字段或对其进行子类化,并且可能有更多模板过滤器来涵盖其他内容,例如磅/千克。

【讨论】:

  • 感谢您的详细解答!我今天将对此进行研究,看看它是如何进行的。附言在这种情况下是否可以使用前面提到的注册模式?例如。类似于 Haystack 搜索对 ​​SearchIndexes 所做的事情?
  • 要将这些表格与您的模型相关联?可以,但你应该看看 ModelForm docs.djangoproject.com/en/dev/topics/forms/modelforms/…
猜你喜欢
  • 2018-05-06
  • 1970-01-01
  • 2016-12-14
  • 2011-06-07
  • 2012-03-02
  • 2011-07-03
  • 2011-02-14
  • 2010-10-04
  • 1970-01-01
相关资源
最近更新 更多