Consider adding get_transform() to supplement get_lookup()
|Reported by:||Anssi Kääriäinen||Owned by:||nobody|
|Component:||Database layer (models, ORM)||Version:||1.7-alpha-1|
|Has patch:||yes||Needs documentation:||yes|
|Needs tests:||no||Patch needs improvement:||no|
Currently the API for get_lookup() is get_lookup(lookup_name). However, there are situations where a field will need more information to decide if it needs to return a lookup or a transform. Consider HStoreField. A candidate API for HStoreField is that:
hstore_field__exact=val=> exact lookup against the hstore_field
hstore_field=val=> also exact lookup against the hstore_field
hstore_field__exact__exact=val=> get key exact from hstore, do an exact lookup against that
hstore_field__nonlookup=val=> get key nonlookup from hstore, do an exact lookup against that
This is similar to how
fk__exact__exact work currently if the model pointed by fk has field named exact.
In addition, we want to support transforms in .values() etc calls in the future. So
hstore_field__exact should always resolve to transform if used in values().
Currently this is impossible to do. The get_lookup() method doesn't know if there are still further lookups in the path. It knows just the current lookup. If we are resolving path
exact__exact get_lookup() should return transform for the first
exact, lookup for the second
exact. If we are resolving just
exact, then lookup should be returned for the first 'exact'. When resolving
.values('hstorefield__exact') call in later releases, the
exact should resolve to transform.
If we add get_transform() method we could change the lookup resolution code in the ORM to do:
- for non-final lookups: always use get_transform()
- for final lookup in filter() calls: try get_lookup(lookup_name). If that doesn't return anything, use get_transform(lookup_name) + get_lookup('exact').
- for any lookup in .values() etc calls: always use get_transform()
The above examples would be resolved as follows:
hstorefield__exact=val: get_lookup('exact') -> match, so use exact lookup against hstorefield
hstorefield=val: get_lookup('exact') -> same as above
hstorefield__exact__exact=val: get_transform('exact'), get_lookup('exact') -> match, so use exact lookup against key exact of hstorefield
hstorefield__nonlookup=val: get_lookup('nonlookup') -> no match, so try get_transform('nonlookup') + get_lookup('exact') -> exact lookup against key nonlookup
The values() call will use always get_transform() so
.values('hstorefield__exact)` will work correctly.
There might also be need to add register_transform() method. If we have only register_lookup() but methods get_lookup() and get_transform() it might lead to some confusion.
Adding register_transform() will break the API, but that is hopefully OK during alpha.