Объединение фильтров для набора запросов Django - PullRequest
0 голосов
/ 09 ноября 2019

Допустим, у меня есть модели, которые выглядят так:

class Sauce(models.Model):
    ...

class Topping(models.Model):
    ...

class Pizza(models.Model):
    sauces = models.ManyToManyField(Sauce, related_name='pizzas')
    toppings = models.ManyToManyField(Topping, related_name='pizzas')
    geo_type = models.CharField(max_length=50, choices=(('NY', 'New York'), ('IT', 'Italy')))

Теперь у меня есть конечная точка, которая принимает параметры URL для фильтрации таблицы пиццы. Например, однажды я мог бы получить следующее:

{
    "sauces": [1, 4],
    "toppings": [4, 7],
    "geo_type": "NY"
}

Используя это, я просто отфильтровал бы, используя следующий код:

Pizza.objects.filter(sauces__in=url_params["sauces"], toppings__in=url_params["toppings"], geo_type=url_params["geo_type"])

И это будет прекрасно работать. Однако иногда я могу получить параметры URL, которые выглядят так:

{
    "sauces": [],
    "toppings": [4, 7],
    "geo_type": "NY"
}

Обратите внимание на пустой массив для параметра sauces. Это означает, что для этого запроса мне не нужны соусы, и это может быть что угодно. Теперь запрос будет выглядеть примерно так:

Pizza.objects.filter(toppings__in=url_params["toppings"], geo_type=url_params["geo_type"])

Еще раз, это работает как ожидалось. Однако проблема в том, что у меня есть много полей для фильтрации, а количество комбинаций огромно. Есть ли какие-нибудь, чтобы просто сказать моему набору запросов игнорировать фильтр, если это пустой массив? И если geo_type - пустая строка или ноль, он также должен игнорировать их. Надеюсь, я понял свою точку зрения.

Спасибо за любую помощь.

1 Ответ

1 голос
/ 09 ноября 2019

Пустые списки можно опустить, например, с помощью вспомогательной функции:

def filter_ignore_if_empty(qs, **kwargs):
    return qs.filter(**{k: v for k, v in kwargs.items() <b>if v != []</b>})

, а затем выполнить фильтрацию с помощью:

<b>filter_ignore_if_empty(</b>
    Pizza.objects.all(),
    sauces__in=url_params['sauces'],
    toppings__in=url_params['toppings'],
    geo_type=url_params['geo_type']
<b>)</b>
...