#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.

Reply via email to