Lets say we have this model:
{{{
from django.contrib.postgres.fields import HStoreField
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=256)
attributes = HStoreField()
}}}
We then populate it.
{{{
Person.objects.create(name="James", attributes={"age": "30", "height":
"190"})
}}}
Here comes the thing that bothers me. If we try to access either of these
keys the entire attributes cell will be returned.
{{{
p = Person.objects.annotate(length=F("attributes__height"))
p[0].height
>>> {"age": "30", "height": "190"}
}}}
While the expected result would be an error or the value of the height
field, it's not.
I propose either making F objects support these fields or creating a new
type to handle this, a workaround that I'm playing around with myself.
{{{
from django.contrib.postgres.fields.jsonb import KeyTransformFactory
class HStoreF(F):
def resolve_expression(self, query=None, allow_joins=True, reuse=None,
summarize=False, for_save=False):
rhs = super().resolve_expression(query, allow_joins, reuse,
summarize, for_save)
field_list = self.name.split("__")
if field_list[-1] == rhs.target.name:
raise LookupError(
"HStoreF requires a key lookup in order to avoid unexpected
behavior. "
"Please append '__somekey' to '{}'."
.format("__".join(field_list)))
return KeyTransformFactory(field_list[-1])(rhs)
}}}
An issue with this is that updating models with it still wont work. As an
error is raised in {{{Query.resolve_ref()}}} due to the fact that it
interprets the {{{"__"}}} as an attempted join. This could be solved by
using a different lookup separator for keys (maybe relevant for JSONField
to?), but I was unable to successfully implement this.
Similar issue with JSONField: https://code.djangoproject.com/ticket/29769
--
Ticket URL: <https://code.djangoproject.com/ticket/30711>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* version: 2.2 => master
Comment:
Thanks for the report, I don't think that we should support this by adding
a custom expression because currently you can always use
`django.contrib.postgres.fields.hstore.KeyTransform`, e.g.
{{{
Person.objects.annotate(height=KeyTransform('height', 'attributes'))
}}}
I don't think that we need to add anything new. IMO, documentating
`django.contrib.postgres.fields.hstore.KeyTransform` should be enough.
It's more complicated for JSONField because nesting multiple
`KeyTransform()` is not so handy.
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:1>
Comment (by Gustav Eiman):
Replying to [comment:1 felixxm]:
> Thanks for the report, I don't think that we should support this by
adding a custom expression because currently you can always use
`django.contrib.postgres.fields.hstore.KeyTransform`, e.g.
> {{{
> Person.objects.annotate(height=KeyTransform('height', 'attributes'))
> }}}
> I don't think that we need to add anything new. IMO, documentating
`django.contrib.postgres.fields.hstore.KeyTransform` should be enough.
>
> It's more complicated for JSONField because nesting multiple
`KeyTransform()` is not so handy.
Thank you! I agree, I had no idea this was available.
Being a first time poster, what do I do now? Should I close this ticket?
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:2>
* component: contrib.postgres => Documentation
* owner: (none) => nobody
* type: New feature => Cleanup/optimization
* stage: Unreviewed => Accepted
Old description:
New description:
Document `django.contrib.postgres.fields.hstore.KeyTransform` in the
[https://docs.djangoproject.com/en/dev/ref/contrib/postgres/fields/#hstorefield
HStoreField documentation] that can be used on the right hand side of a
filter or an annotation.
--
Comment:
I changed ticket description, thanks!
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:3>
Comment (by tapaswenipathak):
Hello folks: Can I take the ticket?
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:4>
* owner: nobody => tapaswenipathak
* status: new => assigned
Comment:
Replying to [comment:4 tapaswenipathak]:
> Hello folks: Can I take the ticket?
That would be great! I'll assign it to you.
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:5>
* owner: Tapasweni Pathak => (none)
* status: assigned => new
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:6>
* owner: (none) => Alokik Roy
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:7>
Comment (by Alokik Roy):
PR [https://github.com/django/django/pull/15833]
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:8>
* has_patch: 0 => 1
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:9>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"0acaea1329e1b31d38dff2b58fc9088814981e0d" 0acaea13]:
{{{
#!CommitTicketReference repository=""
revision="0acaea1329e1b31d38dff2b58fc9088814981e0d"
[4.1.x] Fixed #30711 -- Doc'd
django.contrib.postgres.fields.hstore.KeyTransform().
Backport of 7faf25d682b8e8f4fd2006eb7dfc71ed2a2193b7 from main
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:10>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"7faf25d682b8e8f4fd2006eb7dfc71ed2a2193b7" 7faf25d]:
{{{
#!CommitTicketReference repository=""
revision="7faf25d682b8e8f4fd2006eb7dfc71ed2a2193b7"
Fixed #30711 -- Doc'd
django.contrib.postgres.fields.hstore.KeyTransform().
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:11>
Comment (by GitHub <noreply@…>):
In [changeset:"cb06f5ef8c80fc6a610db0fc36fb9dc7c625335a" cb06f5ef]:
{{{
#!CommitTicketReference repository=""
revision="cb06f5ef8c80fc6a610db0fc36fb9dc7c625335a"
Reverted "Fixed #30711 -- Doc'd
django.contrib.postgres.fields.hstore.KeyTransform()."
This reverts commit 7faf25d682b8e8f4fd2006eb7dfc71ed2a2193b7. The same
can be achieved with F() so there is no need to expose an extra API.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:12>
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):
In [changeset:"02876534aba63755e7418ee03a691ef6dcdb4416" 02876534]:
{{{
#!CommitTicketReference repository=""
revision="02876534aba63755e7418ee03a691ef6dcdb4416"
[4.1.x] Reverted "Fixed #30711 -- Doc'd
django.contrib.postgres.fields.hstore.KeyTransform()."
This reverts commit 7faf25d682b8e8f4fd2006eb7dfc71ed2a2193b7. The same
can be achieved with F() so there is no need to expose an extra API.
Backport of cb06f5ef8c80fc6a610db0fc36fb9dc7c625335a from main
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:13>
* resolution: fixed => wontfix
* stage: Ready for checkin => Unreviewed
Comment:
The same can be achieved with `F()` so there is no need to expose an extra
API.
--
Ticket URL: <https://code.djangoproject.com/ticket/30711#comment:14>