#16187: Refactor lookup system -------------------------------------+------------------------------------- Reporter: UloPe | Owner: akaariai Type: | Status: assigned Cleanup/optimization | Version: master Component: Database layer | Resolution: (models, ORM) | Triage Stage: Accepted Severity: Normal | Needs documentation: 0 Keywords: | Patch needs improvement: 1 Has patch: 1 | UI/UX: 0 Needs tests: 0 | Easy pickings: 0 | -------------------------------------+-------------------------------------
Comment (by akaariai): I did a little more work on the API. I am confident it is general enough yet simple enough now. I created a quick-and-dirty HStoreField implementation, I'll attach a ready to run project. Quick instructions: edit database settings to point to a db with hstore extension installed, syncdb and run python tester.py. The interesting bits are in testproject/hstore.py. I'll paste that portion in here: {{{ from django.db.models import TextField, Lookup, Extract # This one implements "get value of key X from the hstore". The # value is extracted from the hstore, and so further lookups on # the value are possible. The extracted values are of type text # in the DB, so output_type = TextField(). class HStoreExtract(Extract): output_type = TextField() def as_sql(self, qn, connection): lhs, params = qn.compile(self.lhs) # extracts know the lookups used for creating them, # so init_lookups[0] gives us the 'somekey' in # hstorefield__somekey='foo' params.append(self.init_lookups[0]) return '%s -> %%s' % (lhs), params # This one implements "does hstore contain key X". This is a # a lookup on the hstore field itself. class HStoreContains(Lookup): lookup_name = 'hcontains' def as_sql(self, qn, connection): lhs, params = self.process_lhs(qn, connection) rhs, rhs_params = self.process_rhs(qn, connection) params.extend(rhs_params) return '%s ? %s' % (lhs, rhs), params # Main HStoreField class HStoreField(TextField): # Following two methods needed for createdb & save support. def db_type(self, connection): return 'hstore' def get_db_prep_save(self, value, connection): data = [] for k, v in value.items(): data.append('%s=>%s' % (k, v)) return ','.join(data) def get_lookup(self, lookup): found_lookup = None # It is possible to rename Django's own lookups so that conflicts # between common names (contains, exact for example) can be avoided. if lookup.startswith('dj_'): # If it started with 'dj_' use Django's own lookups found_lookup = super(HStoreField, self).get_lookup(lookup[3:]) # If it wasn't something existing, then interpret as extract key from # hstore if found_lookup is None: return HStoreExtract else: return found_lookup HStoreField.register_lookup(HStoreContains) }}} Using HStoreField it is possible to do queries like `qs.filter(hstoredata__somekey__icontains='foobar')`. The test project contains some examples which go a bit further. Now, docs need rewriting and this one is RFC. -- Ticket URL: <https://code.djangoproject.com/ticket/16187#comment:35> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/063.788a7db7b5fe7e1610ab076e7227392b%40djangoproject.com. For more options, visit https://groups.google.com/groups/opt_out.