Как изменить 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-объектов.