Несколько параметров фильтра в отношении внешнего ключа с функцией reduce

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

У меня есть размещаемая модель, которая имеет внешний ключ для Campaign и Size.

 class Campaign(models.Model):
     name = models.CharField(max_length=100)

class Size(models.Model):
     name = models.CharField(max_length=5)

class ToBePosted(models.Model):
     campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE, related_name='to_be_posted_posters')
     size = models.ForeignKey(Size, on_delete=models.CASCADE, related_name='to_be_posted_posters')
 

Мой набор запросов в views.py:

     def get_to_be_posted_queryset_with_filter(self, request):
        filter_params = ToBePostedParameterConverter(request.GET)
        queryset = ToBePosted.objects.all()
        return queryset.filter(filter_params.get_filter())
 

И helpers.py где находится преобразователь ToBePostedParameterConverter

 class ParameterConverter:
    # Convert url query params to queryset filter params
    query_patterns = {
        "campaign": 'to_be_posted__campaign__name',
        "size": 'reference__size__name',
    }

    def __init__(self, query_dict):
        self._query_dict = query_dict
        self._filter_params = []
        self._convert()

    def _convert(self):
        for key in self._query_dict:
            for search_key in self._query_dict.getlist(key):
                if query_param := self.query_patterns.get(key):
                    self._filter_params.append(Q(**{query_param: search_key}))

    def get_filter(self):
        if self._filter_params:
            return reduce(operator.or_, self._filter_params)
        return Q()


class ToBePostedParameterConverter(ParameterConverter):
    query_patterns = {
        "campaign": 'campaign__name',
        "size": 'size__name',
    }

    def get_filter(self):
        if self._filter_params:
            return reduce(operator.or_, self._filter_params)
        return Q()
 

Вопрос в том:

когда я пытаюсь отправить объект размером 666, но связанный только с кампаниями Acamp и Bcamp, я получаю все объекты, размер которых равен 666, независимо от указанных кампаний в URL

ПРИМЕР URL-АДРЕСА ЗАПРОСА С ПАРАМЕТРАМИ:

http://localhost:8000/api/v2/posters/get_lookups/?campaign=Acampamp;campaign=Bcampamp;size=666

Как я могу изменить код, чтобы получать только постеры, связанные с указанными кампаниями в параметрах url?

Я попытался использовать and_ operator в функции reduce. В этом случае он работает правильно, но я не могу указать более одной кампании в URL

Комментарии:

1. Вы хотите сделать что-то вроде этого return reduce(operator.and_, [reduce(operator.or_,self._size_filter_params),reduce(operator.or_,self._campaign_filter_params)])

2. Есть ли более многоразовый способ реализовать это? Потому что есть некоторые другие параметры фильтра, которые у меня есть