9

I have a simple question: Currently I can do this to get an object from my backend:

http://127.0.0.1:8000/api/v1/boats/boats?id=10
http://127.0.0.1:8000/api/v1/boats/boats?home_port=98&id=5

But I'd like to get an array of boats based on a list of ids or a list of home_ports, and I have tried:

http://127.0.0.1:8000/api/v1/boats/boats?id=10,11
http://127.0.0.1:8000/api/v1/boats/boats?id_in=10,11
http://127.0.0.1:8000/api/v1/boats/boats?id=10,id=11
http://127.0.0.1:8000/api/v1/boats/boats?id=10&id=11

But these do not work. What is the best way to do this with django-filter, how are the URL rules defined?

Here is my view:

class BoatList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOrReadOnly,)
    serializer_class = BoatSerializer
    queryset = Boat.objects.all()
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('id', 'home_port',)

The solution I marked accepted 100% answers my question, but I ended up implementing something different based on another post I found which uses filters:

class ListFilter(Filter):

    def filter(self, qs, value):
        if not value:
            return qs

        self.lookup_type = 'in'
        values = value.split(',')
        return super(ListFilter, self).filter(qs, values)

class BoatFilter(FilterSet):
    ids = ListFilter(name='id')

    class Meta:
        model = Boat
        fields = ['home_port', 'ids']


class BoatList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOrReadOnly,)
    serializer_class = BoatSerializer
    queryset = Boat.objects.all()
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = BoatFilter

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)
0

4 Answers 4

8

The answer given by doniyor is quite apt. But I guess request won't be available where it is used.

There is another way of doing this.You can override the get_queryset method. This can be done as follows:

class BoatList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOrReadOnly,)
    serializer_class = BoatSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('id', 'home_port',)

    def get_queryset(self):
        id_list = self.request.GET.getlist("id")
        if not id_list:
            return []
        return Boat.objects.filter(id__in=id_list)
Sign up to request clarification or add additional context in comments.

3 Comments

One small issue with the above is that an empty list will be returned by getlist("id") if id is not present and then it will be filtering for membership in an empty list.
@MarkGalloway Thanks for pointing that out. Corrected the code.
Thank you for this, and doniyor's comment. So there is no way to do this with a filter? It has to be done with the actual query set itself? Anyways, tested this, and it works! To make it work, one small change id_list = self.request.GET.getlist("id")[0].split(',') since it returned an array of one element with the value '10,11'. Thanks again!
4

you just creat a filter class

    class NumberInFilter(BaseInFilter, NumberFilter):
          pass


    class myFilter(FilterSet):
          id__in = NumberInFilter(field_name='id', lookup_expr='in')

          class Meta:
                model = Boat

in the viewset use the

           filter_class = myFilter

you can see this document of the django-filter: https://django-filter.readthedocs.io/en/master/ref/filters.html?highlight=BaseInFilter

2 Comments

I recommend this as well also recommended by Django
This is the right way to query with an array. Thank you.
2

try this:

url: http://127.0.0.1:8000/api/v1/boats/boats?id=10,11

class BoatList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOrReadOnly,)
    serializer_class = BoatSerializer
    queryset = Boat.objects.filter(id__in=request.GET.getlist('id')) #<------
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('id', 'home_port',)

Comments

0

Simple Solution Make a object of your filterset fields if you want to use an array.

filterset_fields = {'id':['exact'],'dist':['exact'],'data_type':['exact','in'], 'data_sub_type':['exact','in']}

Lets see data_sub_type now if from postman we can send a list. data_type__in = "1,2,3" like this

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.