Question

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.

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.

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

_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.

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:

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)
Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top