Changes between Initial Version and Version 3 of Ticket #30711


Ignore:
Timestamp:
Aug 15, 2019, 8:59:53 AM (5 years ago)
Author:
Mariusz Felisiak
Comment:

I changed ticket description, thanks!

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #30711

    • Property Version 2.2master
    • Property Component contrib.postgresDocumentation
    • Property Owner set to nobody
    • Property Triage Stage UnreviewedAccepted
    • Property Summary Add HStoreF for F object like querying on HStoreField.Document django.contrib.postgres.fields.hstore.KeyTransform.
    • Property Type New featureCleanup/optimization
  • Ticket #30711 – Description

    initial v3  
    1 When using F objects for key lookups on HStoreFields it never digs down to get the keys but unexpectedly returns the entire object.
    2 
    3 Lets say we have this model:
    4 {{{
    5 from django.contrib.postgres.fields import HStoreField
    6 from django.db import models
    7 
    8 class Person(models.Model):
    9     name = models.CharField(max_length=256)
    10     attributes = HStoreField()
    11 }}}
    12 
    13 We then populate it.
    14 {{{
    15 Person.objects.create(name="James", attributes={"age": "30", "height": "190"})
    16 }}}
    17 
    18 Here comes the thing that bothers me. If we try to access either of these keys the entire attributes cell will be returned.
    19 {{{
    20 p = Person.objects.annotate(length=F("attributes__height"))
    21 p[0].height
    22 >>> {"age": "30", "height": "190"}
    23 }}}
    24 
    25 While the expected result would be an error or the value of the height field, it's not.
    26 
    27 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.
    28 
    29 {{{
    30 from django.contrib.postgres.fields.jsonb import KeyTransformFactory
    31 
    32 class HStoreF(F):
    33     def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
    34         rhs = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
    35         field_list = self.name.split("__")
    36         if field_list[-1] == rhs.target.name:
    37             raise LookupError(
    38             "HStoreF requires a key lookup in order to avoid unexpected behavior. "
    39             "Please append '__somekey' to '{}'."
    40             .format("__".join(field_list)))
    41         return KeyTransformFactory(field_list[-1])(rhs)
    42 
    43 }}}
    44 
    45 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.
    46 
    47 Similar issue with JSONField: https://code.djangoproject.com/ticket/29769
     1Document `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.
Back to Top