Полный пересмотр логики поиска по email с стратегиями
Проблема: Поиск "team_x3m@" неправильно находит клиента "Наталья natulj@bk.ru" Причина: Использовался простой icontains для всех случаев Решение: Добавлена функция determine_search_strategy() которая определяет стратегию поиска на основе содержимого query: 1. email_prefix: query заканчивается на @ (например "team_x3m@") → Используется istartswith вместо icontains → Найдёт только email, начинающиеся с "team_x3m@" → НЕ найдёт "natulj@bk.ru" ✓ 2. email_domain: query начинается с @ (например "@bk") → Использует icontains для поиска по домену → Найдёт все *@bk.ru, *@bk.com и т.д. 3. email_full: query содержит обе части (например "test@bk.ru") → Поиск по полному email адресу 4. universal: query без @, 3+ символов (например "natul") → Поиск везде: по имени И по email → Это позволит найти "Наталья" и "natulj@bk.ru" 5. name_only: очень короткие запросы (1-2 символа) → Только поиск по имени (чтобы не было ложных срабатываний) Добавлены 23 unit-теста для покрытия всех сценариев: - email_prefix cases: team_x3m@, user_name@, test123@ - email_domain cases: @bk, @bk.ru, @mail.google.com - email_full cases: test@bk.ru, test@bk, user.name@mail.example.com - universal cases: natul, abc, наталь, Test123 - name_only cases: t, te, на - edge cases: пустая строка, @, множественные @ Все 23 теста проходят успешно ✓ Примеры работы после изменения: - team_x3m@ → ищет email^=team_x3m (НЕ найдёт natulj@bk.ru) - @bk → ищет все *@bk.* - natul → ищет везде (имя + email) - te → ищет только по имени (2 символа мало для email) - test@bk.ru → ищет test@bk.ru 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -111,6 +111,52 @@ def customer_delete(request, pk):
|
||||
|
||||
# === AJAX API ENDPOINTS ===
|
||||
|
||||
def determine_search_strategy(query):
|
||||
"""
|
||||
Определяет стратегию поиска на основе содержимого query.
|
||||
|
||||
На основе наличия и позиции символа @ определяет, по каким полям и как искать.
|
||||
|
||||
Возвращает tuple (strategy, search_value):
|
||||
- 'name_only': поиск только по имени (для очень коротких запросов)
|
||||
- 'email_prefix': поиск по началу email (query заканчивается на @)
|
||||
- 'email_domain': поиск по домену (query начинается с @)
|
||||
- 'email_full': полный поиск по email (query содержит обе части)
|
||||
- 'universal': поиск везде (имя + email, для средних запросов)
|
||||
|
||||
Примеры:
|
||||
- 'team_x3m@' → ('email_prefix', 'team_x3m')
|
||||
- '@bk' → ('email_domain', 'bk')
|
||||
- 'test@bk.ru' → ('email_full', 'test@bk.ru')
|
||||
- 'natul' → ('universal', 'natul')
|
||||
- 'te' → ('name_only', 'te')
|
||||
"""
|
||||
if '@' in query:
|
||||
local, _, domain = query.partition('@')
|
||||
|
||||
if not local:
|
||||
# Начинается с @: ищем по домену
|
||||
return ('email_domain', domain)
|
||||
|
||||
if not domain:
|
||||
# Заканчивается на @: ищем по префиксу email
|
||||
return ('email_prefix', local)
|
||||
|
||||
# Есть и локальная часть, и домен: полный поиск
|
||||
return ('email_full', query)
|
||||
|
||||
else:
|
||||
# Нет @: определяем по длине
|
||||
if len(query) < 2:
|
||||
return ('name_only', query)
|
||||
|
||||
if len(query) >= 3:
|
||||
return ('universal', query)
|
||||
|
||||
# 2 символа: только имя (слишком мало для поиска по email)
|
||||
return ('name_only', query)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def api_search_customers(request):
|
||||
"""
|
||||
@@ -154,21 +200,34 @@ def api_search_customers(request):
|
||||
# Ищем по имени, email или телефону
|
||||
# Используем Q-объекты для OR условий
|
||||
|
||||
# Определяем, нужно ли искать по email
|
||||
# Критерии: (@present AND 2+ chars after @) OR (no @ AND 3+ chars total)
|
||||
search_by_email = False
|
||||
if '@' in query:
|
||||
# Если есть @, то нужно 2+ символа после @
|
||||
parts = query.split('@')
|
||||
if len(parts) >= 2 and len(parts[-1]) >= 2:
|
||||
search_by_email = True
|
||||
elif len(query) >= 3:
|
||||
# Если нет @, требуем минимум 3 символа для поиска по email
|
||||
search_by_email = True
|
||||
# Определяем стратегию поиска на основе содержимого query
|
||||
strategy, search_value = determine_search_strategy(query)
|
||||
|
||||
q_objects = Q(name__icontains=query)
|
||||
if search_by_email:
|
||||
q_objects |= Q(email__icontains=query)
|
||||
# Строим Q-объект в зависимости от стратегии
|
||||
if strategy == 'name_only':
|
||||
# Поиск только по имени (для коротких запросов)
|
||||
q_objects = Q(name__icontains=search_value)
|
||||
|
||||
elif strategy == 'email_prefix':
|
||||
# Query вида "team_x3m@" — ищем email, начинающиеся с "team_x3m"
|
||||
# Это решает проблему: не найдёт "natulj@bk.ru"
|
||||
q_objects = Q(email__istartswith=search_value)
|
||||
|
||||
elif strategy == 'email_domain':
|
||||
# Query вида "@bk" — ищем все email с доменом "@bk.*"
|
||||
q_objects = Q(email__icontains=f'@{search_value}')
|
||||
|
||||
elif strategy == 'email_full':
|
||||
# Query вида "test@bk.ru" — полный поиск по email
|
||||
q_objects = Q(email__icontains=search_value)
|
||||
|
||||
elif strategy == 'universal':
|
||||
# Query вида "natul" (3+ символов) — ищем везде
|
||||
q_objects = Q(name__icontains=search_value) | Q(email__icontains=search_value)
|
||||
|
||||
else:
|
||||
# На случай неизвестной стратегии (не должно быть)
|
||||
q_objects = Q(name__icontains=query)
|
||||
|
||||
# Для телефона ищем по нормализованному номеру и по цифрам
|
||||
if phone_normalized:
|
||||
|
||||
Reference in New Issue
Block a user