user6089877
user6089877

Reputation:

Dynamic filter in Django

In my app, I have a form. Depending of the form, one or many filters could be configured by the user.

In my view, I have for exemple :

query = Test.objects.filter(filter1 = request.post['filter1'], filter2 = request.post['filter2'], filter3 = request.post['filter3'])

So, sometimes filter1, filter2 or filter3 could not exist.

If any filters doesn't exist, I just want to ignore the filter.

I could do a script with many "IF" conditions but may be there is a smart solution ?

Thanks for your help !

Upvotes: 6

Views: 11711

Answers (3)

You could use something like this:

import ast


def query_to_dict(query) -> dict:
    filters = {}
    for field, value in query.items(): #  <- param and value like ?param1=True
        filters[field] = ast.literal_eval(str(value)) #  <- parse list/str/bool

    return filters

def event_view(request):
    events = Event.objects.filter(
        Q(**query_to_dict(request.GET))
    )

    return Response(
        EventsSerializer(events, many=True).data
    )

In this example:

ast - module which will help to parse bool values and lists

request.GET - this is your query params ?param1=True&param2="[1, 2]". Make sure to pass params in way like ?title="hello" - using double quotes

query_to_dict - function which will convert query params to python dict. So you can pass this dict to your Event.objects.filter.

Benefit of using filtering this way, you can pass ?id__in="[1, 2]" something like this and it will work. I can't say for sure how it secure or not, but for some complex filtering or bool fields filtering it is perfect.

Upvotes: 0

ponnala aravind
ponnala aravind

Reputation: 19

This code solved my problem:

if request.method == 'GET':
        filters = {}
        for key, value in request.GET.items():
            if value != '':
                filters[key] = value
        filter_list=Pet.objects.filter(**filters)

Upvotes: 2

Dan Gamble
Dan Gamble

Reputation: 4155

You could do something along the lines of:

filters = {}

for key, value in request.post.items():
    if key in ['filter1', 'filter2', 'filter3']:
        filters[key] = value

Test.objects.filter(**filters)

Where the list is a list of keys that you are intending to filter by


Edit

As Thomas Junk suggested you can make it a lot cleaner with a comprehension:

filters = {
    key: value
    for key, value in request.post.items()
    if key in ['filter1', 'filter2', 'filter3']
}

Test.objects.filter(**filters)

Upvotes: 22

Related Questions