Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST Framework filter multiple fields

Models

class Task(Model):
    employee_owner = ForeignKey(Employee, on_delete=CASCADE)
    employee_doer = ForeignKey(Employee, on_delete=CASCADE)

Views

class TaskViewSet(ModelViewSet):
    serializer_class = TaskSerializer
    queryset = Task.objects.all()
    filter_class = TaskFilter

Filter

class TaskFilter(FilterSet):
    owner_id = NumberFilter(name='employee_owner__id')
    doer_id = NumberFilter(name='employee_doer__id')

    class Meta:
        model = Task
        fields = {
            'owner_id',
            'doer_id'
        }

Endpoints

http://localhost:8000/api/tasks?owner_id=1&doer_id=1

(Gives only those tasks where owner and doer are the same employee)

http://localhost:8000/api/tasks?owner_id=1

(Gives only those tasks where owner is specific employee and doer is anyone)

http://localhost:8000/api/tasks?doer_id=1

(Gives only those tasks where doer is specific employee and owner is anyone)

What I want

I want an endpoint like:

http://localhost:8000/api/tasks?both_id=1

(Which would give me all results from above 3 endpoints)

I want django-filter to do filtering exactly like:

Task.objects.filter(
    Q(employee_owner__id=1) | Q(employee_doer__id=1)
)

How can I achieve that ? Thank you.

like image 239
Madi7 Avatar asked Apr 23 '18 04:04

Madi7


Video Answer


2 Answers

You can customize filter using method argument like this:

class TaskFilter(FilterSet):
    owner_id = NumberFilter(name='employee_owner__id')
    doer_id = NumberFilter(name='employee_doer__id')
    both_id = NumberFilter(method='filter_both')

    class Meta:
        model = Task
        fields = {
            'owner_id',
            'doer_id',
            'both_id' 
        }

    def filter_both(self, queryset, name, value):
        return queryset.filter(
            Q(employee_owner__id=value) | Q(employee_doer__id=value)
        )
like image 155
neverwalkaloner Avatar answered Oct 30 '22 10:10

neverwalkaloner


Personally I would like to suggest use DjangoFilterBackend for filtration

from django_filters.rest_framework import DjangoFilterBackend

After that

class TaskViewSet(ModelViewSet):
    serializer_class = TaskSerializer
    queryset = Task.objects.all()
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ['owner_id', 'doer_id']# pass query through params
like image 26
Khubaib Raza Avatar answered Oct 30 '22 12:10

Khubaib Raza