How do you create custom field lookups in Django?
When filtering querysets, django provides a set of lookups that you can use: __contains
, __iexact
, __in
, and so forth. I want to be able to provide a new lookup for my manager, so for instance, someone could say:
twentysomethings = Person.objects.filter(age__within5=25)
and get back all the Person
objects with an age between 20 and 30. Do I need to subclass the QuerySet
or Manager
class to do this? How would it be implemented?
As of Django 1.7, there is a simple way to implement it. Your example is actually very similar to the one from the documentation:
While registering, you can just use
Field.register_lookup(AbsoluteValueLessThan)
instead.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 customQuerySet
(or monkey-patch Django'sQuerySet
, yuck). We do this in neo4django to reuse as much of the Django ORM queryset code as possible while building Neo4j-specificQuery
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 :)
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!
Rather than creating a field lookup, best practice would be to create a manager method, that might look a little bit like this:
then usage would be like so:
A more flexible way to do this is to write a custom QuerySet as well as a custom manager. Working from ozan's code:
This allows you to chain your custom query. So both these queries would be valid: