0

複数のデータ型のリレーショナル データベースに任意のデータを格納する必要があったため、データ自体を格納するだけでなく、データのデータ型 (str、int など) を格納するソリューションを考え出しました。これにより、取得時に、データベースに格納されている文字列をデータの適切なデータ型にキャストできます。データ型を保存するために、カスタム モデル フィールドを作成しました。

class DataType(object):
    SUPPORTED_TYPES = {
        u'unicode': unicode,
        u'str': str,
        u'bool': bool,
        u'int': int,
        u'float': float
    }
    INVERSE_SUPPORTED_TYPES = dict(zip(SUPPORTED_TYPES.values(), SUPPORTED_TYPES.keys()))
    TYPE_CHOICES = dict(zip(SUPPORTED_TYPES.keys(), SUPPORTED_TYPES.keys()))

    def __init__(self, datatype=None):
        if not datatype:
            datatype = unicode

        t_datatype = type(datatype)

        if t_datatype in [str, unicode]:
            self.datatype = self.SUPPORTED_TYPES[datatype]

        elif t_datatype is type and datatype in self.INVERSE_SUPPORTED_TYPES.keys():
            self.datatype = datatype

        elif t_datatype is DataType:
            self.datatype = datatype.datatype

        else:
            raise TypeError('Unsupported %s' % str(t_datatype))

    def __unicode__(self):
        return self.INVERSE_SUPPORTED_TYPES[self.datatype]

    def __str__(self):
        return str(self.__unicode__())

    def __len__(self):
        return len(self.__unicode__())

    def __call__(self, *args, **kwargs):
        return self.datatype(*args, **kwargs)


class DataTypeField(models.CharField):
    __metaclass__ = models.SubfieldBase
    description = 'Field for storing python data-types in db with capability to get python the data-type back'

    def __init__(self, **kwargs):
        defaults = {}
        overwrites = {
            'max_length': 8
        }
        defaults.update(kwargs)
        defaults.update(overwrites)
        super(DataTypeField, self).__init__(**overwrites)

    def to_python(self, value):
        return DataType(value)

    def get_prep_value(self, value):
        return unicode(DataType(value))

    def value_to_string(self, obj):
        val = self._get_val_from_obj(obj)
        return self.get_prep_value(val)

これにより、次のようなことができます。

class FooModel(models.Model):
    data = models.TextField()
    data_type = DataTypeField()

>>> foo = FooModel.objects.create(data='17.94', data_type=float)
>>> foo.data_type(foo.data)
17.94
>>> type(foo.data_type(foo.data))
float

したがって、私の問題は、Django Admin (私は ModelAdmin を使用しています) で、テキスト ボックスの data_type の値が正しく表示されないことです。それがあるときはいつでもfloat(そしてdbではfloatとして保存されていることを確認しました)、表示される値は0.0です。intが表示され0ます。boolが表示されFalseます。data_type の文字列表現を表示する代わりに、Django が実際に呼び出す場所、つまり__call__がパラメーター付きで呼び出され、それらの値が得られることを意味します。例えば:

>>> DataType(float)()
0.0
>>> DataType(int)()
0
>>> DataType(bool)()
False

__call__メソッドを次のように置き換えて、モンキーパッチを適用する方法を見つけました。

def __call__(self, *args, **kwargs):
    if not args and not kwargs:
        return self.__unicode__()
    return self.datatype(*args, **kwargs)

これはフォームに正しい値を表示しますが、これはあまりエレガントではないと感じています。良くする方法はありますか?そもそも、Django がフィールド値を呼び出した場所がわかりませんでした。

ありがとう

4

1 に答える 1

0

DataType が呼び出される理由については、これをお読みください: https://docs.djangoproject.com/en/1.4/topics/templates/#accessing-method-calls

クリーンな解決策は、単純に呼び出しの名前をより明示的なものに変更することです。

于 2012-06-28T15:00:06.680 に答える