透明地将Django模型字段存储为JSON数据

时间:2022-09-14 16:57:01

Say I have an object, "Order," a field of which, "items," holds a list of order items. The list of items will never be searched or individually selected in the database so I just want to store it in a DB field as a JSON string.

假设我有一个对象,“Order”,其中的一个字段“items”包含一个订单项列表。项目列表永远不会被搜索,也不会在数据库中单独选择,所以我只想将它作为JSON字符串存储在DB字段中。

I'm trying to figure out the best way to embed this functionality so it's fairly transparent to anyone using the model. I think saving the model is pretty easy - just override the save method and serialize the "items" list into an internal "_items" field, and then write that to the db. I'm confused about how to deserialize, though. Having looked into possibly some kind of classmethod for creation, or creating a custom manger, or something to do with signals, I've thoroughly confused myself. I'm sure this has been solved a hundred times over and I'm curious what people consider to be best practice.

我想找出最好的方法来嵌入这个功能,这样对于任何使用这个模型的人来说都是透明的。我认为保存模型非常简单——只需覆盖save方法并将“items”列表序列化为内部的“_items”字段,然后将其写入db。但是我对如何反序列化感到困惑。我已经研究了一些创建的类方法,或者创建了一个自定义的管理器,或者与信号有关的一些东西,我已经彻底把自己弄糊涂了。我确信这已经解决了一百次了,我很好奇人们认为什么是最佳实践。

Example classes:

示例类:

class OrderItem():
    def __init__(self, desc="", qty=0):
        self.desc = desc
        self.qty = qty


class Order(Model):
    user = ForeignKey(User)
    _items = TextField() 

    def save(self, *args, **kwargs):
        self._items = jsonpickle.encode(self.items)
        super(Order, self).save(*args, **kwargs)

Example usage:

使用示例:

order = Order()
order.items = [OrderItem("widget", 5)]
order.save()

This would create a record in the DB in which

这将在DB中创建一个记录

_items = [{"desc":"widget", "qty":5}]

Now I want to be able to later select the object

现在我想以后能够选择对象

order = Order.objects.get(id=whatever)

and have order.items be the unpacked array of items, not the stored JSON string.

和有秩序。项目是项目的未打包数组,而不是存储的JSON字符串。

EDIT:

编辑:

The solution turned out to be quite simple, and I'm posting here in case it helps any other newbies. Based on Daniel's suggestion, I went with this custom model field:

这个解决方案其实很简单,我在这里发布,以防对其他新手有帮助。根据Daniel的建议,我选择了这个自定义模型领域:

class JSONField(with_metaclass(SubfieldBase, TextField)):
    def db_type(self, connection):
        return 'JSONField'

    def to_python(self, value):
        if isinstance(value, basestring):
            return jsonpickle.decode(value)
        else:
            return value

    def get_prep_value(self, value):
        return jsonpickle.encode(value)

1 个解决方案

#1


1  

A much better approach is to subclass TextField and override the relevant methods to do the serialization/deserialization transparently as required. In fact there are a number of implementations of this already: here's one, for example.

更好的方法是子类化TextField并重写相关的方法,以便根据需要透明地执行序列化/反序列化。事实上,已经有许多这样的实现了:例如,这里有一个。

#1


1  

A much better approach is to subclass TextField and override the relevant methods to do the serialization/deserialization transparently as required. In fact there are a number of implementations of this already: here's one, for example.

更好的方法是子类化TextField并重写相关的方法,以便根据需要透明地执行序列化/反序列化。事实上,已经有许多这样的实现了:例如,这里有一个。