Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-filter multiple URL parameters

I am using Django-filter app to construct search on my website. This is the code:

class PropertyFilter(django_filters.FilterSet):
city = django_filters.ModelMultipleChoiceFilter(queryset=City.objects.all(), widget = CheckboxSelectMultiple)
trade_type = django_filters.ModelMultipleChoiceFilter(queryset=Trade.objects.all(), widget = CheckboxSelectMultiple)

class Meta:
    model = Property
    fields = ['city', 'trade_type']

The problem is that when user marks two cities, Django-filter only filters objects via last URL parameter (city no. 2 in this casse):

http://example.org/lt/list/city=1&city=2

Models.py:

class City(models.Model):
    name = models.CharField(max_length=250, verbose_name=_('Name'))

Maybe I am doing something wrong ?

like image 890
Eimantas Avatar asked Aug 08 '14 12:08

Eimantas


3 Answers

You could create a plural version of your query string and accept a list as the filter argument:

http://example.org/lt/list/?cities=1,2


class CustomFilterList(django_filters.Filter):
    def filter(self, qs, value):
        if value not in (None, ''):
            values = [v for v in value.split(',')]
            return qs.filter(**{'%s__%s' % (self.name, self.lookup_type): values})
        return qs

class PropertyFilter(django_filters.FilterSet):
    city = django_filters.ModelMultipleChoiceFilter(queryset=City.objects.all(), widget = CheckboxSelectMultiple)
    trade_type = django_filters.ModelMultipleChoiceFilter(queryset=Trade.objects.all(), widget = CheckboxSelectMultiple)
    cities = CustomFilterList(name="city", lookup_type="in")

    class Meta:
        model = Property
        fields = ['cities', 'city', 'trade_type']

Check out this answer for filtering a list of values properly:

Possible to do an `in` `lookup_type` through the django-filter URL parser?

like image 61
punkrockpolly Avatar answered Sep 19 '22 01:09

punkrockpolly


You can get it to work with the same URL you were trying. Follow my example. You have to pass the choices that you want to filter with.

The URL that I'm calling:

http://example.org/product-list/gender=1&gender=2

filters.py

GENDER_CHOICES = tuple(
    ProductAttributeOptions.objects.filter(group__name='gender').values_list('id', 'option'))

class ProductFilter(django_filters.FilterSet):        
    gender = django_filters.MultipleChoiceFilter(choices=GENDER_CHOICES,
                                                 method='filter_gender')

    def filter_gender(self, qs, name, value):
        result = qs.filter(Q(attribute_values__attribute__name='gender',
                         attribute_values__value_option__in=value))

        return result

class Meta:
    model = Product
    fields = ('gender')

Hope this could help. I took inspiration from the official docs.

like image 21
Jay Modi Avatar answered Sep 20 '22 01:09

Jay Modi


The best way is to use custom filter from Django filter DOC in my case i used (',') to split the url should look like this:

localhost:8000/?city=1,2,3 (you can use Strings values)

    
   class F(django_filters.FilterSet):
         city = CharFilter(method='my_custom_filter')

         class Meta:
            model = Property
            fields = ['city','trade_type']

         def my_custom_filter(self, queryset, name, value):
            value_list = value.split(u',') #split the values by ,
            return queryset.filter(**{
            name+"__in": value_list, #add __in to get each value of the list
            })
like image 32
Mokrani Yacine Avatar answered Sep 21 '22 01:09

Mokrani Yacine