Opened 9 years ago
Closed 8 years ago
#25995 closed New feature (fixed)
Add more sophisticated serialization support to JSONField
Reported by: | Jim Graham | Owned by: | nobody |
---|---|---|---|
Component: | contrib.postgres | Version: | dev |
Severity: | Normal | Keywords: | JSONB |
Cc: | Marc Tamlyn, zachborboa@…, debanshuk2007@… | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
It would be great if the jsonb
field could support serialization of objects to the JSON field. The DjangoJSONEncoder
would be helpful here for datetime
s, Decimal
s etc that are in JSON blobs.
I've worked on a similar serializer if it would help to come up with a pull request.
Change History (17)
comment:1 by , 9 years ago
Cc: | added |
---|---|
Component: | Database layer (models, ORM) → contrib.postgres |
comment:2 by , 9 years ago
I think serializing would be be optional at the model level, and the user could decide how they wanted objects serialized/deserialize. The default would continue to be no serialization.
Is it worthwhile coming up with a PR for comments, or is this a non-starter?
Thanks.
comment:3 by , 9 years ago
Could you be a bit more explicit about what the behavior would look like, e.g. with some code examples?
comment:4 by , 9 years ago
Such a field would actually be quite different in implementation to the current field. We currently lever psycopg2's serialization and while this can be customised[1], it is most easily customisable at the field level. There is a possibility of providing an alternative to Json()
for adaption (into the db), but coming back out can only be done at the connection level.
A JSON field which does all of its de-/serialization in the field would be possible of course, one such implementation is https://github.com/bradjasper/django-jsonfield/
[1] http://initd.org/psycopg/docs/extras.html#json-adaptation
comment:5 by , 9 years ago
Do you think there are any action items for this ticket then? If not, perhaps we could document the restriction and note that alternative fields exist.
comment:6 by , 9 years ago
Based on what you've pointed out, I think pointing to the external projects is the best thing to do.
Thanks for your time in reviewing this.
Regards.
comment:7 by , 9 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Summary: | Support serialization to `django.contrib.postgres.fields.jsonb.py` → Add more sophisticated serialization support to JSONField |
Doc patch. I avoided recommending a particular third-party field since we avoid that as it's difficult to curate a list of packages that doesn't go stale.
comment:8 by , 9 years ago
Resolution: | wontfix |
---|---|
Status: | closed → new |
I hit the same problem: https://groups.google.com/d/msg/django-developers/upg9pgGvaUs/LMN8Xfq8EQAJ
If Django doesn't provide an escape hatch, I suspect I won't be the only one to resort to monkey-patching.
Right now I don't have time to dig into this issue but I don't think we can leave it there altogether.
comment:9 by , 9 years ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Version: | 1.9 → master |
comment:10 by , 9 years ago
Cc: | added |
---|
comment:13 by , 8 years ago
We could use a custom data type representation scheme to represent dates, decimals etc in JSON.
The scheme could be similar to what MongoDB uses for it's extended JSON (https://docs.mongodb.com/manual/reference/mongodb-extended-json/#bson-data-types-and-associated-representations).
Eg: a date object would be stored as {"$date": <ISO-8601 date string>}
Or,
It could be something more sophisticated and generic like
{ "$djExtJson": { "$type": <type string>, "$args": <args array>, "$kwargs": <kwargs object> } }
Where '$type' would be the full path of a class (eg, datetime.date
or decimal.Decimal
) and '$args' and '$kwargs' would be the arguments for constructor of the class.
So a date object would be stored as:
{"$djExtJson": {"$type": "datetime.date", "$args": ["2016", "7", "6"]}}
and a decimal object as:
{"$djExtJson": {"$type": "decimal.Decimal", "$args": ["21.5"]}}
Using this format, one would be able to store any class's object in JSON. Eg:
# my_utils.py class ABC(): def __init__(self, dt: date): self.date = dt
An object of above class could be stored as:
{"$djExtJson": { "$type": "my_utils.ABC", "$args": [{"$djExtJson": {"$type": "datetime.date", "$args": ["2016", "7", "6"]}}] }}
Deserialisation of objects using above format would be very simple, as we would have type information stored withing the object with all the arguments required to call constructor of that type, so we would be able to call the constructor and get the object.
For serialisation, it won't be possible to get arguments which need to be passed to a class's constructor just by looking at a object of that class. So for that, we can have custom code in Django for supporting serialisation of common standard library objects and builtins. And for user defined classes, we can created a mixin (we may call it DjExtJsonSerialisable
) which would simply stores arguments (and keyword arguments) passed to the constructor of a user defined class in some attribute, when a object of a class inheriting from at mixin is created (attribute can __dj_ext_json_data__
).
comment:14 by , 8 years ago
Cc: | added |
---|
comment:15 by , 8 years ago
Has patch: | set |
---|
This PR adds custom encoding support.
The decoding part is another story. The patch currently recommends using from_db
/from_db_value
hooks. If anyone can come with a concrete proposal with another method, please propose it.
comment:16 by , 8 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
PR #7071 looks good to me. I left a comment about the type of the encoding
parameter in the pull request.
I think the problem here is that we couldn't also deserialize that data since we have no way to know if the user originally passed a string or some other Python type. For example, if we see '1' in the JSONField, do we deserialize it to 1 (integer) or leave it as a string? Using
DjangoJSONEncoder
for model serialization is different because we have the model field type hint to use for deserialization.