Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass multiple values for a single parameter into the API url in Django Rest Framework?

I have made a filter API like this:

localhost/api/allpackages?price_min=700&price_max=900&destination=Spain&new_activity=Swimming&tour_type=Group%20Tour&featured=true&fix_departure=true

But according to new changes, I should be able to filter like this:

localhost/api/allpackages?destination=Spain&destination=Japan&destination=Thailand....featured=true...

There can be multiple values for a single parameter, because user can now click the checkboxes on the frontend. How can I achieve this?

My models:

class Package(models.Model):
    operator = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
    destination = models.ForeignKey(Destination, on_delete=models.CASCADE)
    package_name = models.CharField(max_length=255)
    featured = models.BooleanField(default=False)
    price = models.IntegerField()
    duration = models.IntegerField(default=5)
    discount = models.CharField(max_length=255, default="15% OFF")
    discounted_price = models.IntegerField(default=230)
    savings = models.IntegerField(default=230)
    tour_type = models.CharField(max_length=100, choices=TOUR_TYPE, default='Group Tour')
    new_activity = models.ManyToManyField(NewActivity)
    accommodation = models.CharField(max_length=255,default='Guest House & Hotel')
    transport = models.CharField(max_length=150, default='Flight')
    age_range = models.CharField(max_length=100, default='6 to 79 years old')
    fix_departure = models.BooleanField(default=False)
....
...

My views:

class AllPackageAPIView(ListAPIView):
    queryset = Package.objects.all()
    serializer_class = PackageSerializer
    filterset_class = PackageFilter
    
 
    def get_queryset(self):
        new_activity = self.request.query_params.get('new_activity', None)
        destination = self.request.query_params.get('destination', None)
        if new_activity is not None:
            if destination is not None:
                return Package.objects.filter(destination__name=destination, new_activity__title=new_activity)
            else:
                return Package.objects.filter(new_activity__title=new_activity)
        elif destination is not None:
            if new_activity is not None:
                return Package.objects.filter(destination__name=destination, new_activity__title=new_activity)
            else:
                return Package.objects.filter(destination__name=destination)
        else:
            return Package.objects.all()

My filter:

class PackageFilter(filters.FilterSet):
   price = filters.RangeFilter()

   class Meta:
      model = Package
      fields = ['price','featured', 'fix_departure',
                'tour_type',]

My serializers:

class PackageSerializer(serializers.ModelSerializer):
  
    class Meta:
        model = Package
        fields = ['id', 'operator','destination', 'package_name', 'duration', 'featured', 'price', 'discount', 'discounted_price',
                       'tour_type','new_activity', 'accommodation', 'transport', 'age_range',
                  'savings', 'fix_departure', 'rating', 'image', 'date_created', ]
        # fields = '__all__'
        depth = 1

I have done this but now no data are shown. The get list is empty. I used get_queryset(self) as a function and now self.request.GET.get for querying.

My updated view:

class AllPackageAPIView(ListAPIView):
    queryset = Package.objects.all()
    serializer_class = PackageSerializer
    filterset_class = PackageFilter

def get_queryset(self): 
    new_activity = self.request.GET.get('new_activity', None)
    destination = self.request.GET.get("destination", "")
    destination_values = destination.split(",")
    if new_activity is not None:
        if destination is not None:
            return Package.objects.filter(destination__name=destination_values, new_activity__title=new_activity)
        else:
            return Package.objects.filter(new_activity__title=new_activity)
    elif destination is not None:
        if new_activity is not None:
            return Package.objects.filter(destination__name=destination_values, new_activity__title=new_activity)
        else:
            return Package.objects.filter(destination__name=destination_values)
    else:
        return Package.objects.all()

My solution:

def get_queryset(self):
# def get(self, request, format=None, *args, **kwargs):

    new_activity = self.request.GET.get('new_activity',None)
    destination = self.request.GET.get("destination",None)
    tour_type = self.request.GET.get("tour_type",None)
    if new_activity is not None:
        new_activity = self.request.GET.get('new_activity', "")
        new_activity_values = new_activity.split(",")
        if destination is not None:
            destination = self.request.GET.get("destination", "")
            destination_values = destination.split(",")
            if tour_type is not None:
                tour_type = self.request.GET.get("tour_type", "")
                tour_type_values = tour_type.split(",")
                return Package.objects.filter(destination__name__in=destination_values,new_activity__title__in=new_activity_values,
                                          tour_type__in=tour_type_values)
            else:
                return Package.objects.filter(destination__name__in=destination_values,
                                              new_activity__title__in=new_activity_values)
        else:
            return Package.objects.filter(new_activity__title__in=new_activity_values)
    elif destination is not None:
        destination = self.request.GET.get("destination", "")
        destination_values = destination.split(",")
        if new_activity is not None:
            new_activity = self.request.GET.get('new_activity', "")
            new_activity_values = new_activity.split(",")
            if tour_type is not None:
                tour_type = self.request.GET.get("tour_type", "")
                tour_type_values = tour_type.split(",")
                return Package.objects.filter(destination__name__in=destination_values,
                                              new_activity__title__in=new_activity_values,
                                              tour_type__in=tour_type_values)
            else:
                return Package.objects.filter(destination__name__in=destination_values,
                                              new_activity__title__in=new_activity_values
                                              )
        else:
            return Package.objects.filter(destination__name__in=destination_values)
    elif tour_type is not None:
        tour_type = self.request.GET.get("tour_type", "")
        tour_type_values = tour_type.split(",")
        if destination is not None:
            destination = self.request.GET.get("destination", "")
            destination_values = destination.split(",")
            if new_activity is not None:
                new_activity = self.request.GET.get('new_activity', "")
                new_activity_values = new_activity.split(",")
                return Package.objects.filter(destination__name__in=destination_values,
                                              new_activity__title__in=new_activity_values,
                                              tour_type__in=tour_type_values)
            else:
                return Package.objects.filter(destination__name__in=destination_values,
                                                       tour_type__in=tour_type_values)
        else:
            return Package.objects.filter(tour_type__in=tour_type_values)
    else:
        return Package.objects.all()

This works as a filter for checkbox searches in ecommerce website, but it has a problem. When calling API, it repeats some of the objects i.e. same package object in my case. If anyone can solve it, let me know.

like image 472
Reactoo Avatar asked Nov 24 '25 21:11

Reactoo


1 Answers

I have solved this question before, I've decided to get multiple values in URL by using split , character.

Example: URL: localhost/api/allpackages?destination=Spain,Japan,Thailand....featured=true...

destination = self.request.GET.get("destination", "")

destination_values = destination.split(",")

Sample code about filtering first_name, last_name, and multiple values of username in User model.

model.py

class User(AbstractUser):
    @property
    def full_name(self):
        """Custom full name method as a property"""
        return str(self.first_name) + ' ' + str(self.last_name)

    def __str__(self):
        return self.email

view.py

class UserFilter(filters.FilterSet):
    class Meta:
        model = User
        fields = ['first_name', 'last_name']


class ListCreateUser(ListCreateAPIView):
    """
    List and Create User Generic contains create and list user APIs.
    """
    serializer_class = UserSerializer
    queryset = User.objects.all()
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = UserFilter

    def get_queryset(self):
        username = self.request.GET.get('username', '')

        if username:
            username_values = username.split(',')
            return User.objects.filter(username__in=username_values)

        return User.objects.all()

Results:

  • List all users
  • Filter by first_name, last_name, and username
  • Filter by usernameenter image description here
like image 199
Vu Phan Avatar answered Nov 26 '25 17:11

Vu Phan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!