1

I am doing a table in React, fetching some data from my Django DB.
It has filters and I want them to call the API to get results if needed.

Thing is I have to duplicate a lot of lines whereas I am pretty sure there is a better way to do this.

Here is some part of the code:

        if ss_value and not es_value and not iv_value and not timestamp:
            queryset = DailyReport.objects.all().filter(station_departure=ss_value)
        elif not ss_value and es_value and not iv_value and not timestamp:
            queryset = DailyReport.objects.all().filter(station_arrival=es_value)
        elif not ss_value and not es_value and iv_value and not timestamp:
            queryset = DailyReport.objects.all().filter(is_virtual=iv_value)
        elif not ss_value and not es_value and not iv_value and timestamp:
            queryset = DailyReport.objects.all().filter(
                Q(timestamp__range=(min_dt, max_dt)) | Q(upload_timestamp__range=(min_dt, max_dt)))
            logger.debug(queryset)
        elif ss_value and es_value and not iv_value and not timestamp:
            queryset = DailyReport.objects.all().filter(station_departure=ss_value, station_arrival=es_value)
        elif ss_value and not es_value and iv_value and not timestamp:
            queryset = DailyReport.objects.all().filter(station_departure=ss_value, is_virtual=iv_value)

and it goes on and on.

Do you have any idea of a way to do it in a cleaner way ??

Thank you :)

Kimor
  • 532
  • 4
  • 17

3 Answers3

3

The technique you're missing has less to do with django and more to do with Python in general.

def myfunc1(arg1, arg2):
    print(arg1, arg2)

def myfunc2(arg1=None, arg2=None):
    print(arg1, arg2)

mylist = ['val1', 'val2']
mydict = {'arg1': 'val1', 'arg2': 'val2'}

Assuming you have the above:

myfunc1('val1', 'val2')
myfunc1(*mylist)

Are equivalent! Similarly:

myfunc2('val1', 'val2')
myfunc2(**mydict)

Are also equivalent!

You can pass a list into a function call as if they're the positional arguments with a single *, and you can pass a dictionary as keyword arguments with a double *

So ultimately what you want to do is build up a dictionary of things of the form:

filter_kwargs = {
   'django_filter_kwarg_name': 'django_filter_value'
}

So for you this might be:

# build up the dictionary (or maybe you can do this off the form, request.GET, etc
filter_kwargs = {
    'station_departure': ss_value,
    'station_arrival': es_value,
    ....
}
# do something here to filter out the empty/None key/values
filter_kwargs = {key: value if value for key, value in filter_kwargs.items}
# now get the queryset
queryset = DailyReport.objects.all().filter(**filter_kwargs)


Mike Sandford
  • 1,315
  • 10
  • 22
1

You could utilize the dictionary unpacking using **. When you have a list of filters, add them to a dictionary then unpack them into the queryset filter.

For Example:

Model.objects.filter(x=2, y=3)

# equivalent to

Model.objects.filter(**{"x":2, "y":3})

So your code can be done like so:

    queryset_filters = {}    
    if ss_value:
       queryset_filters['station_departure'] = ss_value
    if es_value:
       queryset_filters['station_arrival'] = es_value
    .
    .
    .
    
    queryset = DailyReport.objects.filter(**queryset_filters)
0

You can try assigning form actions to your buttons:

<form action="" method="post">
  <input type="submit" name="value1" value="Button Name" />
  <input type="submit" name="value2" value="Button Name" />
</form>

And then you can do

if "value1" in request.POST:
    qs = DailyReport.objects.filter(station_departure="value1")

Note that you will need to buttons, as there won't be any point if there's only one and HTML wouldn't allow so.

Reference

crimsonpython24
  • 2,223
  • 2
  • 11
  • 27