As someone who has been using the Postgres-specific JSONField extensively for dynamic, custom fields for the past couple of years, can I humbly suggest that the some more thought goes into the field lookup before the current approach is enshrined?
The simple .filter(field__foo="hello world") is actually fine, but it gets really weird if you let users define foo. What if they call foo something like "contains"? What if "foo" is actually "Foo the bar?". The JSON makes sense:
{
"Foo the bar?": true
}
but the Django filter does not.
The current documentation says you can use __contains, but as far as I can tell, __contains, besides being difficult to understand, cannot be used for queries like __icontains. And it overwrites a built-in, otherwise useful operator.
My current wish list is:
- kill special contains and contained_by (use Q(field__foo="xxx") | Q(field__bar="yyy") instead)
- kill has_keys and has_any_keys (use Q(field__has_key="xxx") | Q(field__has_key="yyy") instead)
- add possibility of using something more robust than __ for path traversal, perhaps just a JSON extract string like JSONExtract("owner.other_pets[0].name")
This could perhaps also allow us to use the JSONField content in places where you currently can't (e.g. annotate). I'm not sure how exactly to combine it with field lookup and operators, but I'm personally okay with something like
.filter(**{ "myfield__" + JSONExtract("owner.other_pets[0].name") + "__icontains": "baz" })
That's way better than what we have now.
The neat thing about JSONField is that it can store some of the things that are otherwise difficult to handle with traditional schemas. I think with some love and a set of more orthogonal primitives, we could query it easily from Django, too.
Ole