Reputation: 107092
Consider the following case:
class MyModelManager(models.Manager):
def my_filter(self):
return [some code here].filter(field_A__gt=3)
class MyModel(models.Model):
# some fields
objects = MyModelManager()
# The way I'd like to use it:
qs = MyModel.objects.filter(field_B__lt=1)
# some code
qs = qs.my_filter()
Notice that I'd like to use the custom my_filter()
function on the already filtered queryset. What code should I place in the [some code here]
above? Is the structure as a whole correct?
Upvotes: 3
Views: 2463
Reputation: 1553
I guess there is no way to do it exactly this way. MyModel.objects.filter(field_B__lt=1) will return QuerySet object, not MyModelManager. You may either pass it to my_filter method as Ignacio Vazquez-Abrams mentioned or first apply my_filter to your manager, that will return QuerySet object, that you can filter further
Upvotes: 2
Reputation: 18727
Your approach is wrong because you can only use Model.Manager while you retreive data from database, so using two managers or trying to use a manager ona a queryset causes error.
data = SomeModel.objects.my_manager.all()
or
data = SomeModel.objects.all()
data = data.my_manager.filter(...)
is wrong since you can not use two managers...
One possible waw is defining a function that gets a queryset as a parameter and returns a filtered queryset...
def extra_filter(queryset):
queryset = queryset.filter(...)
but i am not sure if this helps.
Best approach is defining another model Manager and use it instread of objects if required...
class SomeManager(models.Manager):
def get_query_set(self):
return super(SomeManager, self).get_query_set().filter(<filteer criteria>)
class MyModel(models.Model):
# some fields
objects = models.Manager()
mymanager = SomeManager()
data = MyModel.mymanager.all()
And use just one...
UPDATE: In django, querysets are lazy. That means, you can apply as many filters as you wish and data will not be retreived from the database unliess you try to get a specific record from the filtered or you try to slice it...Documentation is here
So, there is no diffrence between
qs = MyModel.objects.filter(field_B__lt=1)
qs = qs.filter(field_A__gt=3)
and
qs = MyModel.objects.filter(field_A__gt=3)
qs = qs.filter(field_B__lt=1)
So defining a manager to apply a specific filtering is the main reason for using managers...
You define your manager :
class SomeManager(models.Manager):
def get_query_set(self):
return super(SomeManager, self).get_query_set().filter(field_A__gt=3)
then you call it with other filtering criteria:
Somemodel.mymodelmanager.filter(field_B__lt=1, ....)
And django will add all filters and evluate the query when you want it to do.
So if it is a filter that you use oftenly, manager i the best choice...
As for an example, i have valid_ field in my most database models and a val manager that filters invalid entries. So When i wish to filter all valid data (90% of the time) i use
Somemodel.val.filter(...)
And in the situation that i need all the data i just use basic django manager:
Somemodel.objects.filter(...)
Upvotes: 1
Reputation: 798626
class MyModelManager(models.Manager):
def my_filter(self, qs=None):
if qs is None:
qs = [however you got it before]
return qs.filter(field_A__gt=3)
Then just pass your queryset to it.
Upvotes: 0