Reputation: 5142
I have created a filter for my model. How do I make it so that it filters as answered or archived
? At the moment if I pass both parameters, it combines them using and
- this makes sense but it is not what I am trying to achieve.
I would be happy to have just one field (ie. answered_or_archived
)
from django_filters import rest_framework as filters
from conversations.models import Conversation
class ConversationFilter(filters.FilterSet):
answered = filters.BooleanFilter(field_name="answered_at", lookup_expr="isnull", exclude=True)
archived = filters.BooleanFilter(field_name="is_archived")
class Meta:
model = Conversation
fields = ["answered", "archived"]
Upvotes: 0
Views: 171
Reputation: 8673
Create a custom filter field, and do the querying in there. You can do anything you would normally do, its just a queryset.
class SomeFilterField(Filter):
field_class = forms.CharField
def filter(self, qs, value):
if value is None or value == other_bad_value:
return qs
start = some_date_value()
end = some_date_value()
# use Q() to manually construct more complicated filters
# (a > start and a < end) or (archived=False)
f = Q(answered_at__gte=start) & Q(answered_at__lte=end)
# or last condition
f = f | Q(archived=False)
qs = qs.filter(f)
... other stuff
return qs
def to_python(self, value):
# custom conversion to python object, or None
# if field_class is enough, you don't need this
return value
Upvotes: 1
Reputation: 5142
Andrew Backer's answer was of great help and got us in the right direction.
Here is how we implemented the filter:
from django_filters import rest_framework as filters
from django.db.models import Q
from distutils import util
import datetime
from conversations.models import Conversation
class ArchivedField(filters.Filter):
def filter(self, qs, value):
if value is None:
return qs
if bool(util.strtobool(value)):
f = Q(is_archived=True) | Q(answered_at__isnull=False)
else:
f = Q(is_archived=False) & Q(answered_at__isnull=True)
qs = qs.filter(f)
return qs
def to_python(self, value):
return value
class ConversationFilter(filters.FilterSet):
archived = ArchivedField(field_name="archived")
class Meta:
model = Conversation
fields = ["archived"]
Upvotes: 1