1
\$\begingroup\$

I needed a way to get URL parameters and put them and their values into a query set's .filter() if they exist. After a day of piecing together information from the Interwebs, I have a working solution to my problem. However, is it the best way to do this? I feel it can be improved or streamlined, but my tiny brain is failing me:

In utilities.py:

def get_filters(url, allowed):
    query = parse.urlsplit(url).query
    pack = dict(parse.parse_qsl(query))
    translated = {}

    for pk, pv in pack.items():
        for ak, av in allowed.items():
            if pk == ak:
                translated[av] = pv

    return translated

In views.py:

from utilities import get_filters

people = Person.objects.all()
url = request.get_full_path()

allowed_filters = {
    'location': 'person_location',
    'role': 'person_role',
}

filters = get_filters(url, allowed_filters)

if filters:
    filtered_query = people.filter(**filters)
else:
    filtered_query = people

if ('search' in request.GET) and request.GET['search'].strip():
    query_string = request.GET['search']
    query_search = get_query(query_string, ['person_first_name', 'person_last_name'])
    query_results = filtered_query.filter(query_search)
else:
    query_results = filtered_query

It does everything I need it to: if a URL parameter is in the allowed list, it takes that parameter and value, packs it into a dictionary, and shoves it into filter() to be unpacked by the interpreter.

This way whenever I want to add a new filter, I just add it in the allowed list and I don't have to touch anything else. I did it this way so I could use an alias like special_id=3 in the URL to target a relationship like person__special__special_id=3 without the URL getting cluttered like the Django admin side does.

Any suggestions for improving this?

\$\endgroup\$
2
  • \$\begingroup\$ my tiny brain is failing me switch to one of the others. \$\endgroup\$
    – greybeard
    May 13 '20 at 11:09
  • \$\begingroup\$ Heterogeneous multi-processing (global task scheduling) would be huge benefit, for sure! \$\endgroup\$
    – Xeuxs
    May 13 '20 at 19:07
0
\$\begingroup\$

You can change the first method to

def get_filters(url, allowed):
    query = parse.urlsplit(url).query
    pack = dict(parse.parse_qsl(query))
    translated = {}

    for pk, pv in pack.items():
        if pk in allowed:
            translated[allowed[pk]] = pv

    return translated

Remove this condition, it's useless.

if filters:
    filtered_query = people.filter(**filters)
else:
    filtered_query = people

and just use

filtered_query = people.filter(**filters)

Maybe add search to the allowed filters? and improve the method to handle multiple values for a specific key.

allowed_filters = {
    'location': 'person_location',
    'role': 'person_role',
    'search': ['person_first_name', 'person_last_name']
}

```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.