Opened 5 years ago

Last modified 20 months ago

#30711 closed Cleanup/optimization

Add HStoreF for F object like querying on HStoreField. — at Initial Version

Reported by: Gustav Eiman Owned by:
Component: Documentation Version: dev
Severity: Normal Keywords: HStoreField F
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When using F objects for key lookups on HStoreFields it never digs down to get the keys but unexpectedly returns the entire object.

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

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top