透明地将Django模型字段存储为JSON数据
假设我有一个对象,叫做“订单”,它里面有一个字段“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)
并且让订单的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)
1 个回答
1
一种更好的方法是创建一个新的类,继承自文本字段(TextField),并重写一些相关的方法,这样就可以在需要的时候自动处理数据的保存和读取。实际上,已经有很多这样的实现了,比如这里就有一个。