Toshi023Yuki
Toshi023Yuki

Reputation: 345

How to search query sets that have a specific value in a list in Django Rest framework

What I want to do

Getting all query set which has a specific value in a list which is ManyToManyField.

In short, if I type http://localhost:8000/api/pickup/?choosingUser=5, I would like to get all PickUp_Places that matches like choosingUser = 5. choosingUser comes from ManyToManyField so a PickUp_Places model has like choosingUser = [2,3,5,7].

Problem

I cannot search query sets by a specific value in list. When I type http://localhost:8000/api/pickup/?choosingUser=5, I get all query sets that include ones don't have choosingUser = 5.

I am using django_filters in order to filter query sets. I read the documentation but I couldn't find how to get query sets by a value in a list.

If it is alright with you, would you please tell me how to do that?

Thank you very much.

===== ========= ========== =========

My code is like this.

models.py

class PickUp_Places(models.Model):
    name = models.CharField(max_length=200, unique=True)
    choosing_user = models.ManyToManyField(
        settings.AUTH_USER_MODEL, related_name="pick_up")

    def __str__(self):
        return self.name

    class Meta:
        db_table = "pickup_places"

serializers.py

class PickUp_PlacesSerializer(serializers.ModelSerializer):

    class Meta:
        model = PickUp_Places
        fields = "__all__"

views.py

class PickUp_PlacesViewSet(viewsets.ModelViewSet):
    queryset = PickUp_Places.objects.all()
    permission_classes = [
        permissions.IsAuthenticatedOrReadOnly
    ]
    serializer_class = PickUp_PlacesSerializer

    filter_backends = [filters.DjangoFilterBackend]
    filterset_fields = "__all__"

Upvotes: 0

Views: 766

Answers (2)

Biplove Lamichhane
Biplove Lamichhane

Reputation: 4095

To get choosingUser from url override get_queryset method:

def get_queryset(self):
    choosingUser = self.request.query_params.get('choosingUser')
    queryset = choosingUser is not None and PickUp_Places.objects.filter(choosing_user__id=choosingUser) or PickUp_Places.objects.all()
    return queryset

Elaborated version:

def get_queryset(self):
    choosingUser = self.request.query_params.get('choosingUser')
    if choosingUser is not None:      
        queryset = PickUp_Places.objects.filter(choosing_user__id=choosingUser)
    else:
        queryset = PickUp_Places.objects.all()
    return queryset

Upvotes: 1

Roham
Roham

Reputation: 2120

One way to add filter based on M2M fields is to add filter_fields to your viewset, something like:

class PickUp_PlacesViewSet(viewsets.ModelViewSet):
    queryset = PickUp_Places.objects.all()
    permission_classes = [
        permissions.IsAuthenticatedOrReadOnly
    ]
    serializer_class = PickUp_PlacesSerializer

    filter_backends = [filters.DjangoFilterBackend]
    filter_fields = ('choosing_user', )

and then for filtering based on this field use http://localhost:8000/api/pickup/?choosing_user=5 which will return all the places that have user with id = 5 as it's choosing user. If you want to filter based on multiple choosing_users you can do:

class PickUp_PlacesViewSet(viewsets.ModelViewSet):
        queryset = PickUp_Places.objects.all()
        permission_classes = [
            permissions.IsAuthenticatedOrReadOnly
        ]
        serializer_class = PickUp_PlacesSerializer
    
        filter_backends = [filters.DjangoFilterBackend]
        filter_fields = {
                'choosing_user__id': ['in',]
                }

and use http://localhost:8000/api/pickup/?choosing_user=5,1,2 to filter multiple ids.

Upvotes: 0

Related Questions