简体   繁体   中英

Filter objects with Rest Framework Django API

I have a model Person in Django

class Language(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name


class Country(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name


class Person(models.Model):
    PersonId= models.UUIDField(
        primary_key=True, default=uuid.uuid4, editable=False)
    Countries = models.ManyToManyField(Country)
    Languages = models.ManyToManyField(Language)

each person can have (visit) many countries and have (speak) many languages.

I want to create an API that I will send to the endpoint list of few languages and countries , and will return for me the people, which has at their list at least one of the language and one country from the lists that I sent.

For example I have

Person(1,['Portugal', 'Spain'],['portugues','spanish']) ,

Person(2, ['Portugal', 'Germany'],['portugues','russian']) ,

Person(3,['France', 'Spain'],['spanish', 'french'])

I sent data

{
   Countries: ['Portugal', 'France'],
   Languages: ['russian', 'french']
}

so in this case it returns Person2 and Person3 . My PersonView with Authentication

class PeopleListView(ListAPIView):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    authentication_classes = [TokenAuthentication, ]
    permission_classes = [IsAuthenticated, ]

    def get_queryset(self):
        return Blog.objects.filter(UserId=self.request.user)

Is there any way to do this? I would not like to search by url but send data in body.

What it would look like if you were to test the answer below using requests. The simplicity and usage is why I think you can skip the requirement of not wanting the url to contain filter information.

import requests

requests.get(
    f'http://{site}', 
    params={'Countries': ['Portugal', 'France'], 'Languages': ['russian', 'french']}
).json()

The requests library allows for parameters to be sent as a list in a dictionary .

The PeopleListView needs to have the queryset updated based on the values sent.

class PeopleListView(ListAPIView):
    serializer_class = PersonSerializer
    authentication_classes = [TokenAuthentication, ]
    permission_classes = [IsAuthenticated, ]

    def get_queryset(self):
    """Returns a list of of People that match the critera"""
        # get query parameters
        countries = self.request.GET.getlist('Countries', None)
        languages = self.request.GET.getlist('languages', None)

        # return the filter set based on parameters sent
        if countries is not None and languages is not None:
            return Person.objects.filter(countries__name__in=countries).filter(languages__name__in=languages)
        elif countries is not None and languages is None:
            return Person.objects.filter(countries__name__in=countries)
        elif countries is None and languages is not None:
            return Person.objects.filter(languages__name__in=languages)
        else:
            return Person.objects.all()  # returns everyone if no filters set

This uses the The documentation on filtering with Django Rest Framework to change the query set based on the parameters sent.

The if.. elif... elif... else block uses The documentation on filtering in Django's orm

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM