postgresql 9.3.5 数据库存储 字典型数据遇到的一个问题

2017-12-19 19:27:44 +08:00
 waterlaw

本人是 python 初级程序员, 今天在公司测试服务器遇到一个数据库存储的问题, 原本存储在数据库中的字段值 '{"first": ["", ""], "second": ["", ""]}' 变成了 '{{first, "", ""}, {second, "", ""}}',first 没有引号!!!, 而且突然有了 {{ 和 }} 是什么意思? 这里主要设计 django 的两个 model, 定义如下:

class A(models.Model):
	params = JSONField(verbose_name="A",default=dict)

class B(models.Model):
	template = models.ForeignKey(A, verbose_name='B')

存储 A 中一条记录的语句:

d = dict()
d["first"] = ["", ""]
d["second"] = ["", ""]
A.objects.create(params=d)

我在使用 A 的增删改查操作时 数据库记录都是正确的, 但是服务器第二天就报错了, 初步排查, 代码中只有一处对 A 表进行操作, 应该不是存储格式错误的原因,在服务器中使用 psql 查询 A 表时发现存储的数据 由原来的 {"first": ["", ""], "second": ["", ""]} 变成 {{first, "", ""}, {second, "", ""}},这是 postgresql 数据库的一个 bug 吗? 因为 9.3 版本不支持 jsonb, 所以自定义了一个 JSONField , 定义如下:

class JSONField(Field):
    empty_strings_allowed = True
    default_error_messages = {
        'invalid': "Value must be valid JSON.",
    }
    description = 'A JSON object'
    _encoder_class = {
        "indent": None,
        "sort_keys": True,
        "separators": (',', ':'),
        "skipkeys": True,
    }
    _decoder_kwargs = {
        "object_hook": hook_handler
    }

    def __init__(self, *args, **kwargs):
        if not kwargs.get('null', False):
            kwargs['default'] = kwargs.get('default', dict)
        self.encoder_kwargs = dict(
            kwargs.pop(
                'encoder_kwargs', self._encoder_class))

        self.decoder_kwargs = dict(
            kwargs.pop(
                'decoder_kwargs', self._decoder_kwargs))
        super(JSONField, self).__init__(*args, **kwargs)

    def formfield(self, **kwargs):
        defaults = {
            'form_class': JSONFormField,
            'widget': JSONWidget,
        }
        defaults.update(**kwargs)
        return super(JSONField, self).formfield(**defaults)

    def validate(self, value, model_instance):
        super(JSONField, self).validate(value, model_instance)
        try:
            json.dumps(value)
        except TypeError:
            raise ValidationError(
                self.error_messages['invalid'],
                code='invalid',
                params={'value': value},
            )

    def get_internal_type(self):
        return 'TextField'

    def db_type(self, connection):
        # if connection.vendor == 'postgresql' and connection.pg_version >= 90400:
        #     raise ValueError("使用 django.contrib.postgres.fields.JSONField")
        return 'text'

    def from_db_value(self, value, expression, connection, context):
        if value is None:
            return None
        return json.loads(value, **self.decoder_kwargs)

    def get_prep_value(self, value):
        if value is None:
            if self.null and self.blank:
                return None
            value =  ""
        return json.dumps(value, **self.encoder_kwargs)

    def value_to_string(self, obj):
        return self.value_from_object(obj)
1932 次点击
所在节点    Python
1 条回复
siteshen
2017-12-19 22:43:17 +08:00
看起来像是函数 `get_prep_value` 的问题,不知道你的 JSONField 怎么写出来的。
我的话,会在 Django 自带的 JSONField 上调整,楼主可以试试。

```
from django.contrib.postgres.fields.jsonb import JSONField as JSONBField

class JSONField(JSONBField):
def db_type(self, connection):
return 'json'
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/416076

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX