Добавлены фильтры для списка клиентов через django-filter

- Создан CustomerFilter с тремя фильтрами:
  * Есть заметки (has_notes)
  * Нет телефона (no_phone)
  * Нет email (no_email)

- Обновлен views.py для использования фильтров
- Добавлены чекбоксы фильтров в шаблон списка клиентов
- Фильтры работают совместно с поиском
- Кнопка Очистить отображается при активных фильтрах или поиске
This commit is contained in:
2026-01-03 14:50:24 +03:00
parent 63a965ae5c
commit 5ded404346
3 changed files with 101 additions and 7 deletions

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
"""
Фильтры для клиентов с использованием django-filter
"""
import django_filters
from django import forms
from .models import Customer
class CustomerFilter(django_filters.FilterSet):
"""
Фильтр для списка клиентов
Поддерживает фильтрацию по:
- Наличию заметок
- Отсутствию телефона
- Отсутствию email
"""
# Фильтр: есть заметки
has_notes = django_filters.BooleanFilter(
method='filter_has_notes',
label='Есть заметки',
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
)
# Фильтр: нет телефона
no_phone = django_filters.BooleanFilter(
method='filter_no_phone',
label='Нет телефона',
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
)
# Фильтр: нет email
no_email = django_filters.BooleanFilter(
method='filter_no_email',
label='Нет email',
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
)
class Meta:
model = Customer
fields = ['has_notes', 'no_phone', 'no_email']
def filter_has_notes(self, queryset, name, value):
"""Фильтр клиентов с заметками"""
if value:
return queryset.filter(notes__isnull=False).exclude(notes='')
return queryset
def filter_no_phone(self, queryset, name, value):
"""Фильтр клиентов без телефона"""
if value:
return queryset.filter(phone__isnull=True) | queryset.filter(phone='')
return queryset
def filter_no_email(self, queryset, name, value):
"""Фильтр клиентов без email"""
if value:
return queryset.filter(email__isnull=True) | queryset.filter(email='')
return queryset

View File

@@ -27,21 +27,48 @@
</div>
</div>
<!-- Поиск -->
<!-- Поиск и фильтры -->
<div class="card mb-3">
<div class="card-body">
<form method="get" class="row g-2">
<div class="col-md-8">
<form method="get" class="row g-3">
<!-- Поиск -->
<div class="col-md-6">
<input type="text" class="form-control" name="q" value="{{ query }}"
placeholder="Поиск по имени, email или телефону..."
autofocus>
</div>
<div class="col-md-4">
<div class="btn-group w-100" role="group">
<!-- Фильтры -->
<div class="col-md-6">
<div class="d-flex gap-3 align-items-center">
<div class="form-check">
{{ filter.form.has_notes }}
<label class="form-check-label" for="{{ filter.form.has_notes.id_for_label }}">
Есть заметки
</label>
</div>
<div class="form-check">
{{ filter.form.no_phone }}
<label class="form-check-label" for="{{ filter.form.no_phone.id_for_label }}">
Нет телефона
</label>
</div>
<div class="form-check">
{{ filter.form.no_email }}
<label class="form-check-label" for="{{ filter.form.no_email.id_for_label }}">
Нет email
</label>
</div>
</div>
</div>
<!-- Кнопки -->
<div class="col-12">
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary">
<i class="bi bi-search"></i> Поиск
<i class="bi bi-search"></i> Поиск / Фильтр
</button>
{% if query %}
{% if query or filter.form.has_notes.value or filter.form.no_phone.value or filter.form.no_email.value %}
<a href="{% url 'customers:customer-list' %}" class="btn btn-outline-secondary">
<i class="bi bi-x-circle"></i> Очистить
</a>

View File

@@ -13,6 +13,7 @@ import json
from decimal import Decimal
from .models import Customer, ContactChannel
from .forms import CustomerForm, ContactChannelForm
from .filters import CustomerFilter
def normalize_query_phone(q):
@@ -33,6 +34,10 @@ def customer_list(request):
# Исключаем системного клиента из списка
customers = Customer.objects.filter(is_system_customer=False)
# Применяем фильтры django-filter
customer_filter = CustomerFilter(request.GET, queryset=customers)
customers = customer_filter.qs
if query:
# Нормализуем номер телефона
phone_normalized = normalize_query_phone(query)
@@ -79,6 +84,7 @@ def customer_list(request):
'page_obj': page_obj,
'query': query,
'total_customers': paginator.count, # Используем count из paginator, чтобы избежать дублирования SQL запроса
'filter': customer_filter, # Добавляем фильтр в контекст
}
return render(request, 'customers/customer_list.html', context)