I have added a 'cancelled' field to my model, is there a way to modify the model default query to something like cancelled=False ? without having to modify all my filter/exclude queries ?
2 Answers
You can do this with a custom model manager and override the get_queryset
function to always filter canceled=False.
class CustomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(canceled=False)
class MyModel(models.Model):
# Blah blah
objects = CustomManager()
Then when calling MyModel.objects.all()
it will always exclude canceled objects. Here is a blog post I found helpful on the subject. http://www.b-list.org/weblog/2006/aug/18/django-tips-using-properties-models-and-managers/
EDIT: Perhaps a better approach with a custom manager would be to attach it to another property, other than objects, such as:
class MyModel(models.Model):
# Blah blah
active = CustomManager()
And in your views your queries would look like MyModel.active.all()
.
EDIT2:
Updated method spelling from get_query_set
to get_queryset
for modern versions of django.

- 18,659
- 11
- 66
- 69

- 24,664
- 5
- 76
- 70
-
7you have to be VERY VERY careful with overriding default manager just like that. In this particular case, once item is cancelled, you won't ever find it with filter()/get(). – Dmitry Shevchenko Mar 22 '10 at 18:08
-
1Agreed. Would I typically supplement this approach with overriding get() to not use this filter if the pk is given. You probably would also want to change the admin queryset to return all including canceled. But if you rarely want canceled items in your queries this can be a reasonable approach. – Mark Lavin Mar 22 '10 at 18:25
-
1Hi, is there a way to modify the behaviour of get_query_set to use additional parameters i.e. passed from somewhere, or use global variables like current login user info? thanks! – ultrajohn Jun 10 '12 at 21:39
-
Depending on when you knew the parameters then you could pass them in the `CustomManager.__init__`. However the currently logged in user is is most certainly not available globally in a Django project. – Mark Lavin Jun 10 '12 at 23:50
-
1Wonder where the `get_query_set` spelling comes from. I believe the correct method name is [get_queryset](https://docs.djangoproject.com/en/1.10/topics/db/managers/#modifying-a-manager-s-initial-queryset). – knaperek Sep 02 '16 at 21:15
-
1Yes the old name `get_query_set` was deprecated in 1.6 and removed in 1.8: https://docs.djangoproject.com/en/1.10/internals/deprecation/#deprecation-removed-in-1-8 – Mark Lavin Sep 06 '16 at 14:37
-
This answer helped me fix a similar issue with Wagtail because you can't use `ordering = ('
', )` in a Wagtail model that inherits from `Page`. – Max Goodridge Jan 03 '17 at 15:36 -
If I were truly overriding the "default" so that I didn't have to refactor 90% of my views with the same filter, I'd perhaps make `objects = CustomManager()`, and have something like `objects_including_canceled = models.Manager()`. This is what I would try if I had a model with records that shouldn't quite be deleted, but aren't relevant to regular use. Depends on the data, though. – Supra621 Feb 03 '21 at 16:44
You could write custom query manager, but I don't believe this is the right way to go. This would make an implicit, hidden condition for a filter, which would make code unreadable. Remember Zen of Python: Explicit is better than implicit
. Detect places, where you need to add cancelled=False and just add this, that's the way you should do this.

- 40,948
- 31
- 128
- 181
-
17I strongly disagree. What, then, would be the point of having custom managers? What is so implicit about `not_cancelled = CustomManager()` and then using MyModel.not_cancelled.all()? – Mar 23 '10 at 04:28