Home > Mobile >  How to write a Django filter query for multiple values selected from a form without many if statemen
How to write a Django filter query for multiple values selected from a form without many if statemen

Time:12-13

I have several Django forms of which when submitted I store the values like so if the forms are valid with only the min and max price being required, but the other values may be blank or not:

    max_budget = price_form.cleaned_data['max_price'] #required
    
    max_budget = price_form.cleaned_data['max_price'] #required 
    
    another_value1 = other_form1.cleaned_data['another_value1'] #string
    
    another_value2 = other_form1.cleaned_data['another_value2'] #string
    
    another_value3 = other_form2.cleaned_data['another_value3'] #string
    
    another_value4 = other_form2.cleaned_data['another_value4'] #string
    
    another_value5 = other_form3.cleaned_data['another_value5'] #boolean value
    
    another_value6 = other_form3.cleaned_data['another_value6'] #boolean value

I want to query a model (single database table) by using these variable values which correspond to specific fields in that DB as filters. The problem is that currently, I would have to use numerous carefully planned nested if/else statements each containing a variation of the line below to properly filter the DB based on the different possible values or lack thereof.

query_results = Model.objects.filter(price__range=(min_budget, max_budget), field_in_the_DB="another_value1", field_in_the_DB="another_value2", field_in_the_DB__icontains="another_value3", field_in_the_DB__icontains="another_value4", field_in_the_DB="another_value5", field_in_the_DB="another_value6").order_by("Another_field_in_the_DB_not_related_these_values")

This is because only the min and max prices are required to be entered so something like this would be required.

price__range=(min_budget, max_budget)
    

As for the other variables, some may have values or some may be left blank when submitted. Therefore, how can I filter the DB table efficiently without having to use numerous if/else statements to account for the different possible values or lack thereof? Is there a simpler way?

CodePudding user response:

I use a Q filter. You are not saved from the "IF" but you can have them ordered.

from django.db.models import Q

# this condition must always exist otherwise the filter fails
my_filter = Q( price__range=(min_budget, max_budget) ) 

#I use Get, modify for POST if necessary
if self.request.GET.get("other_value1", ""): 
    my_filter &= Q( field_in_the_DB="other_value1" )
if self.request.GET.get("other_value2", ""):
    my_filter &= Q( field_in_the_DB="other_value2" )
if self.request.GET.get("other_value3", ""):
    my_filter &= Q(field_in_the_DB__icontains="another_value3" )
if self.request.GET.get("other_value4", ""):
    my_filter &= Q(field_in_the_DB__icontains="another_value4" )
if self.request.GET.get("other_value5", ""):
    my_filter &= Q( field_in_the_DB="other_value5" )
if self.request.GET.get(other_value6):
    my_filter &= Q( field_in_the_DB="other_value6" )


query_results = Model.objects.filter(my_filter).order_by("...")

see the &= in assignments I hope it helps you.

CodePudding user response:

You can use a dict, and pass it as **kwargs in the filter.

Example

query_params = {
    'field_in_db': value,
    'another_field__icontains': another_value
}

query_results = Model.objects.filter(**query_params)  # the rest of the queryset

CodePudding user response:

I would first like to say thank you very much to Daniel Acuña as your answer is for the most part correct and you deserve 99.9% of the credit for providing it.

However, I did make changes to the if statement as I realized that they were being skipped over and not being accessed.

Here are the minor changes I made to the if statements:

if other_value1: 
    my_filter &= Q( field_in_the_DB="other_value1" )
if other_value2:
    my_filter &= Q( field_in_the_DB="other_value2" )
if other_value3:
    my_filter &= Q(field_in_the_DB__icontains="another_value3" )
if other_value4:
    my_filter &= Q(field_in_the_DB__icontains="another_value4" )
if other_value5:
    my_filter &= Q( field_in_the_DB="other_value5" )
if other_value6:
    my_filter &= Q( field_in_the_DB="other_value6" )
  • Related