Django Admin:对象不是自定义字段子类JSONField上的JSON可序列化错误

时间:2017-11-04 22:16:11

标签: django django-models django-admin

我试图通过在JSONFields中存储某些对象来对我的Django Postgres数据库进行反规范化,该数据库支持JSON API:

https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#jsonfield

我扩展了django.contrib.postgres.fields.JSONField字段,以自动将数据序列化为Python对象。我这样做是为了将我的逻辑封装在对象周围并强制存储在JSONField中的对象的结构。我在这里关注自定义模型字段的Django文档:

https://docs.djangoproject.com/en/1.11/howto/custom-model-fields/

我能够将我的对象存储在自定义JSONField中,并且可以将它们检索为本机Python对象,但是,我已经破坏了管理控制台。当我尝试查看我的一个对象时,我收到此错误:

  MYSQL *conn= mysql_init(NULL);
  MYSQL_RES *res; /* holds the result set */
  MYSQL_ROW row;
  if(mysql_real_connect(conn, "xx.1x3.1xx.7x", "ixxx", "00000000", "xxx", 0, NULL, 0)){
    char q[1000];
    mysql_query(conn, "select id FROM user");
    res = mysql_store_result(conn);
    int num_fields = mysql_num_fields(res);
    while ((row = mysql_fetch_row(res)))
    {
       // Print all columns
       for(int i = 0; i < num_fields; i++)
       {
           // Make sure row[i] is valid!
                char *val = row[i];
                std::cout << row[i][1] << std::endl;

                //std::cout << "NULL" << std::endl;

           // Also, you can use ternary operator here instead of if-else
           // cout << row[i] ? row[i] : "NULL" << endl;
       }
    }

  }

我认为问题在于内置的json.dumps函数不能很好地处理随机对象,所以我希望有一些方法可以在我的PostalAddress类中重写以使其发挥得很好。

这是我的代码,虽然这是一个简单的地址案例,我想将这个模式应用于更复杂和有用的自定义JSONField用例,所以我希望在管理控制台中看到序列化的JSON并且能够编辑文本并保存。

fields.py

TypeError: <core.fields.PostalAddress object at 0x7fdcfaade4e0> is not JSON serializable

models.py

from django.contrib.postgres.fields import JSONField

class PostalAddress(object):
    def __init__(self, street='', city='', state='', postal_code=''):
        self.street = street
        self.city = city
        self.state = state
        self.postal_code = postal_code

def deserialize_address(address_dict):
    return PostalAddress(**address_dict)

def get_empty_address():
    return PostalAddress()

class PostalAddressField(JSONField):
    description = "A postal address"

    def __init__(self, *args, **kwargs):
        super(PostalAddressField, self).__init__(*args, **kwargs)

    def get_prep_value(self, value):
        if value is None:
            return value
        if isinstance(value, PostalAddress):
            return json.dumps(value.__dict__)
        return value

    def from_db_value(self, value, expression, connection, context):
        if value is None:
            return value
        return deserialize_address(value)

    def to_python(self, value):
        if isinstance(value, PostalAddress):
            return value
        if value is None:
            return value
        return deserialize_address(value)

完整追踪:

from django.db import models
from .fields import PostalAddressField, get_empty_address

class Person(models.Model):
    shipping_address = PostalAddressField(default = get_empty_address)

1 个答案:

答案 0 :(得分:1)

你遇到的问题是Django使用它的JSONField form field来尝试反序列化管理中的对象 - 这会失败,因为它只使用无法处理json.dumps()对象的PostalAddress

您已覆盖模型字段,但您还需要覆盖管理员中使用的表单字段。该文档描述了如何specify a custom form field for a model field

这样的事情:

from django.contrib.postgres.forms import JSONField 

# Define a new form field
class PostalAddressJSONField(JSONField):

    def prepare_value(self, value):
        # Here, deserialize the object in a way that works.
        # I've copied what you've done in your model field.
        return json.dumps(value.__dict__)

然后在PostalAddressField

中指定此新表单字段
class PostalAddressField(JSONField):

    def formfield(self, **kwargs):
        defaults = {'form_class': PostalAddressJSONField}
        defaults.update(kwargs)
        return super().formfield(**defaults)

ModelAdmin表单现在应该使用此自定义表单字段,并且能够正确反序列化。