Как изменить Q с AND на OR - Python с Django

У меня есть простая электронная коммерция, в которой мне нужен фильтр продуктов для пользователей. В данном случае я хочу фильтровать автомобили по цвету через checkbox form. Но когда я делаю for на выбранных цветах, он создает фильтр Q(AND: ), а я хотел, чтобы это был фильтр Q(OR: ). Как мне его изменить?

Index.html:

<div class="widgets-area mb-9">
  <h2 class="widgets-title mb-5">Cores</h2>
  <div class="widgets-item">
      <form id="widgets-checkbox-form" action="{% url 'carro_filtro' %}" method="GET">
        <ul class="widgets-checkbox">
          {% for cor in cores %}
          <li>
              <input class="input-checkbox" type="checkbox" id="color-selection-{{ cor.id }}" name="termo" value="{{ cor.nome_cor }}">
              <label class="label-checkbox mb-0" for="color-selection-{{ cor.id }}">
                {{ cor.nome_cor }}
              </label>
          </li>
          {% endfor %}
        </ul>
        <input type="submit" class="btn btn-custom-size lg-size btn-primary w-100 mb-5 mt-5" value="Filtrar">
      </form>
  </div>
</div>

Urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.CarView.as_view(), name='shop'),
    path('filtro/', views.CarroFiltro.as_view(), name='carro_filtro'),
]

Views.py:

class CarView(ListView):
    model = Car
    template_name = 'shop/index.html'
    paginate_by = 12
    context_object_name = 'cars'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['personalizacoes'] = Shop.objects.filter(
            publicado_shop=True).order_by('-id').first()
        context['categorias'] = Categoria.objects.all()
        context['cores'] = Cor.objects.all()

        return context

    def get_queryset(self):
        qs = super().get_queryset()
        categoria = self.kwargs.get('nome_categoria', None)

        if not categoria:
            qs = qs.filter(publicado=True).order_by('-id')
            return qs

        qs = qs.filter(
            categoria_carro__nome_categoria__iexact=categoria, publicado=True).order_by('-id')
        return qs


class CarroFiltro(CarView):

    def get_queryset(self):
        qs = super().get_queryset()
        queries = []
        selected_colors = self.request.GET.getlist('termo')

        for selected_color in selected_colors:
            if selected_color is not None:
                queries.append(Q(cor__nome_cor__icontains=selected_color))

        qs = qs.filter(*queries)

        print('X'*100)

        print('1)')
        print(queries)

        print('X'*100)

        print('2)')
        print(*queries)

        print('X'*100)

        return qs

Views.py печатает результаты: введите описание изображения здесь

Вкратце

Я получаю:

(AND: ('cor__nome_cor__icontains', 'Branco')) (AND: ('cor__nome_cor__icontains', 'Preto'))

Я хочу получить:

(OR: ('cor__nome_cor__icontains', 'Branco'), ('cor__nome_cor__icontains', 'Preto'))

Скорее, чем

qs = qs.filter(*queries)

Я бы предложил что-то вроде

from functools import reduce
import operator

combined_q_expr = reduce(operator.or_, queries)
qs = qs.filter(combined_q_expr)

(Поместите импорт в начало файла)

Это то же самое, что делать

Q(value=foo) | Q(value=bar | Q(price=10)

для всех ваших Q-объектов.

Вернуться на верх