I want to write a filter once and reuse it everywhere, how can I do it?
For example: there is a model Student
with flag field
. I want to write a filter to get non-graduate students (flag=0
). But in many views and functions we need list non-graduate students, and I am lazy and don't want to write the filter again and again in these views and functions, as this will make it hard to maintain the source code.
Can I use meta in model Student? I did not find any filter related meta options. Or can I write a function to filter in model Student? In my mind, function in model only works in one Student object instead of list.
Using a custom QuerySet and QuerySet.as_manager() is the best solution now. Jamie Matthews of Dabapps has discussed reusable filters in detail in his blog post Building a higher-level query API: the right way to use Django's ORM.
“Using Django's low-level ORM query methods directly in a view is (usually) an anti-pattern”
— Jamie Matthews
The blog post is written before Django got the .as_manager() method for QuerySet though.
I'd use something like this now (based on the currently accepted answer):
class StudentQuerySet(models.query.QuerySet):
def graduate(self):
return self.filter(graduated=True)
def undergraduate(self):
return self.filter(graduated=False)
class Student(models.Model):
graduated = BooleanField()
objects = StudentQuerySet.as_manager()
In other, more complex cases, it's useful to be able to define complex filters in the custom query set since filters are chainable when implemented like this.
If you want this to be made available to related managers in other models (ie. if you had another model referencing the Student model and were using otherinstance.student_set.all()
), see Django: Using managers for related object access. In short, do this:
class Student(models.Model):
graduated = BooleanField()
objects = StudentQuerySet.as_manager()
objects.use_for_related_fields = True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With