1

保存する必要があるバイト文字列があります。

Django は BlobFields をサポートしていないので、db との対話時に base64 にエンコードおよびデコードする独自の Base64Field を作成すると思いました。そのため、まさにその目的のために to_python および get_db_prep_save メソッドをオーバーライド (?) しました。

問題は、 to_python が一度だけではなく、さまざまなシナリオで呼び出され、文字列が既にデコードされているかどうかを判断する方法がないことです。既にデコードされている場合は、明らかにエラーが発生します。

私のジレンマにはどのような解決策がありますか?

私には醜いように見える可能な解決策:デコードプロセスを除いて試し、デコードが失敗した場合は値を返し、インスタンス変数を使用すると1つのto_pythonしか許可されません(これはさらに悪いようです)

4

1 に答える 1

0

ある種のPickledObjectFieldを使用できます。

class PickledObjectField(models.Field):
    __metaclass__ = models.SubfieldBase

    marker_re = re.compile(r'^T\[(?P<type>\w+)\](?P<value>.*)$', re.DOTALL)
    markable_types = dict((t.__name__, t) for t in (str, int, unicode))

    def __init__(self, *args, **kwargs):
        self.compress = kwargs.pop('compress', True)
        self.protocol = kwargs.pop('protocol', 2)
        kwargs.setdefault('null', True)
        kwargs.setdefault('editable', False)
        super(PickledObjectField, self).__init__(*args, **kwargs)

    def generate_type_marked_value(self, value):
        return PickledObject(u"T[%s]%s" % (type(value).__name__, value))

    def read_marked_value(self, value):
        m = self.marker_re.match(value)

        if m:
            marker = m.group('type')
            value = m.group('value')
            if marker in self.markable_types:
                value = self.markable_types[marker](value)

        return value

    def get_default(self):
        if self.has_default():
            if callable(self.default):
                return self.default()
            return self.default

        return super(PickledObjectField, self).get_default()

    def to_python(self, value):
        if value is not None:
            try:
                if value.startswith("T["):
                    value = self.read_marked_value(value)
                else:
                    value = dbsafe_decode(value, self.compress)
            except:
                if isinstance(value, PickledObject):
                    raise
        return value

    def get_db_prep_value(self, value):
        if value is not None and not isinstance(value, PickledObject):
            if type(value).__name__ in self.markable_types and not (isinstance(value, basestring) and len(value
                                                                                                          ) > MAX_MARKABLE_STRING_LENGTH):
                value = unicode(self.generate_type_marked_value(value))
            else:
                value = unicode(dbsafe_encode(value, self.compress))
        return value

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)

    def get_internal_type(self):
        return 'TextField'

    def get_db_prep_lookup(self, lookup_type, value):
        if lookup_type not in ['exact', 'in', 'isnull']:
            raise TypeError('Lookup type %s is not supported.' % lookup_type)
        return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value)
于 2013-05-09T09:04:50.633 に答える