Search code examples
djangodjango-formsdjango-q

Django / GET form / Q filtering


I'm trying to create filter for my results that would take multiple values from html form. This current setup gives me urls such as this /?language=French&language=German however the results would not show French and German records but only French. Additionally, adding new filtering criteria such as "level" /?language=French&level=Beginner doesn't work either.

Could anybody please help and point me in the right direction?

thanks sikor

My form looks as follows:

RESOURCES_LANGUAGE =        (('English', 'English'),
                            ('Spanish', 'Spanish'),
                            ('French', 'French'),
                            ('German', 'German'))

RESOURCES_LEVEL =           (('Beginner', 'Beginner'),
                            ('Intermediate', 'Intermediate'),
                            ('Advanced', 'Advanced'))

SORTBY =                    (('likes', 'Likes'),
                            ('name', 'Name'),
                            ('latest', 'Latest'))

class FiltersAndSortingForm(forms.Form): 
    language = forms.MultipleChoiceField(required=False, label='Language', widget=forms.CheckboxSelectMultiple, choices=RESOURCES_LANGUAGE)
    level = forms.MultipleChoiceField(required=False, label='Level', widget=forms.CheckboxSelectMultiple, choices=RESOURCES_LEVEL)
    provider = forms.ModelMultipleChoiceField(queryset=Provider.objects.all().order_by('name'), label='Provider', required=False,)
    sortby = forms.MultipleChoiceField(required=False, label='Sort by', widget=forms.CheckboxSelectMultiple, choices=SORTBY)

My view:

def resources(request):
    if request.GET:
        language = request.GET.get('language', '')
        level = request.GET.get('level', '')
        provider = request.GET.get('provider', '')  

        sortby = request.GET.get('sortby', '')
        if sortby == 'name':
            orderby = 'name'
        elif sortby == 'latest':
            orderby = '-dt_added'
        elif sortby == 'likes':
            orderby = '-facebook_likes'
        else:
            orderby = '-facebook_likes'    

        qset = (
            Q(language=language) 
#            & 
#            Q(level=level) 
            )

        resources = Resource.objects.filter(inactive=0).filter(qset).order_by(orderby)
        form = FiltersAndSortingForm()
    else:
        form = FiltersAndSortingForm()
        resources = Resource.objects.filter(inactive=0).order_by('-facebook_likes')

Solution

  • OK, eventually after looking at this thread django dynamically filtering with q objects I got it working like this. Maybe it is not the cleanest way but seems like it is doing the job. Unless anybody could suggest better solution?

    thanks -s

    def resources(request):
        if request.GET:
            type = request.GET.getlist('type', '')
            language = request.GET.getlist('language', '')
            level = request.GET.getlist('level', '')
            provider = request.GET.getlist('provider', '')  
    
            sortby = request.GET.get('sortby', '')
            if sortby == 'name':
                orderby = 'name'
            elif sortby == 'latest':
                orderby = '-dt_added'
            elif sortby == 'likes':
                orderby = '-facebook_likes'
            else:
                orderby = '-facebook_likes'  
    
            qset_type = Q() # Create an empty Q object to start with
            for x in type:
                qset_type |= Q(provider__tags__name=x) # 'or' the Q objects together
    
            qset_language = Q() 
            for x in language:
                qset_language |= Q(language=x) 
    
            qset_level = Q() 
            for x in level:
                qset_level |= Q(level=x) 
    
            qset_provider = Q() 
            for x in provider:
                qset_provider |= Q(provider=x)    
    
            qset = qset_language & qset_level & qset_type & qset_provider
    
            resources = Resource.objects.filter(inactive=0).filter(qset).order_by(orderby)
            form = FiltersAndSortingForm()
        else:
            form = FiltersAndSortingForm()
            resources = Resource.objects.filter(inactive=0).order_by('-facebook_likes')