How do you create custom field lookups in Django?
When filtering querysets, django provides a set of lookups that you can use: __contains, __iexa
First, let me say that there is no Django machinery in place that's meant to publicly facilitate what you'd like.
(Edit - actually since Django 1.7 there is: https://docs.djangoproject.com/en/1.7/howto/custom-lookups/ )
That said, if you really want to accomplish this, subclass QuerySet and override the _filter_or_exclude() method. Then create a custom manager that only returns your custom QuerySet (or monkey-patch Django's QuerySet, yuck). We do this in neo4django to reuse as much of the Django ORM queryset code as possible while building Neo4j-specific Query objects.
Try something (roughly) like this, adapted from Zach's answer. I've left actual error handling for the field lookup parsing as an exercise for the reader :)
class PersonQuerySet(models.query.QuerySet):
def _filter_or_exclude(self, negate, *args, **kwargs):
cust_lookups = filter(lambda s: s[0].endswith('__within5'), kwargs.items())
for lookup in cust_lookups:
kwargs.pop(lookup[0])
lookup_prefix = lookup[0].rsplit('__',1)[0]
kwargs.update({lookup_prefix + '__gte':lookup[1]-5,
lookup_prefix + '__lt':lookup[1]+5})
return super(PersonQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)
class PersonManager(models.Manager):
def get_query_set(self):
return PersonQuerySet(self.model)
class Person(models.Model):
age = #...
objects = PersonManager()
Final remarks - clearly, if you want to chain custom field lookups, this is going to get pretty hairy. Also, I'd normally write this a bit more functionally and use itertools for performance, but thought it was more clear to leave it out. Have fun!