Skip to main content
 首页 » 编程设计

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

2025年05月04日32JeffreyZhao

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

我正在尝试找出嵌入此功能的最佳方式,以便它对使用该模型的任何人都相当透明。我认为保存模型非常简单 - 只需重写保存方法并将“items”列表序列化为内部“_items”字段,然后将其写入数据库。不过,我对如何反序列化感到困惑。在研究了可能用于创建的某种类方法,或者创建自定义管理器,或者与信号有关的东西之后,我彻底混淆了自己。我敢肯定这已经被解决了一百多次而且我很好奇人们认为什么是最佳实践。

示例类:

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) 

示例用法:

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

这将在数据库中创建一条记录

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

现在我希望以后能够选择对象

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

并让 order.items 成为解压缩的项目数组,而不是存储的 JSON 字符串。

编辑:

事实证明,解决方案非常简单,我将其发布在这里,以防对其他新手有所帮助。根据 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) 

请您参考如下方法:

更好的方法是子类化 TextField 并覆盖相关方法以根据需要透明地执行序列化/反序列化。事实上,已经有很多这样的实现:here's one ,例如。