Consider adding get_transform() to supplement get_lookup()
|Reported by:||akaariai||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 and 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 exact for .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.
Change History (4)
comment:1 Changed 3 years ago by mjtamlyn
- Needs documentation unset
- Needs tests unset
- Patch needs improvement unset
- Triage Stage changed from Unreviewed to Accepted