diff --git a/lpon_site/frontend/utils.py b/lpon_site/frontend/utils.py index 05a18a2..1a80fa0 100644 --- a/lpon_site/frontend/utils.py +++ b/lpon_site/frontend/utils.py @@ -16,7 +16,7 @@ from django.utils.html import mark_safe from django.http import HttpRequest from django.db.models import Model from lpon_site.settings import ( - SLUG_MAX_LENGTH, KEY_SYNONYM, + SLUG_MAX_LENGTH, KEY_SYNONYM_EN, ) @@ -223,10 +223,10 @@ def update_synonyms_in_metadata( Универсальный хелпер для управления синонимами во всех моделях (TbLabel, TbArtist, TbMusicStyle и т.д.) Логика: - - При создании новой записи: добавляет текущее значение поля в SYNONYM - - При редактировании: если значение поля изменилось, добавляет ОБА (старое и новое) в SYNONYM + - При создании новой записи: добавляет текущее значение поля в SYN_EN + - При редактировании: если значение поля изменилось, добавляет ОБА (старое и новое) в SYN_EN - Очищает дубликаты в списке синонимов, сохраняя порядок - - Использует KEY_SYNONYM из settings как ключ в metadata словаре + - Использует KEY_SYN_EN из settings как ключ в metadata словаре Args: instance: Экземпляр модели (self из save методе). Обязателен! @@ -282,25 +282,25 @@ def update_synonyms_in_metadata( setattr(instance, metadata_field_name, metadata_dict) # Убеждаемся, что ключ 'SYNONYM' существует и это список - if KEY_SYNONYM not in metadata_dict or not isinstance(metadata_dict[KEY_SYNONYM], list): - metadata_dict[KEY_SYNONYM] = [] + if KEY_SYNONYM_EN not in metadata_dict or not isinstance(metadata_dict[KEY_SYNONYM_EN], list): + metadata_dict[KEY_SYNONYM_EN] = [] # ===== ДОБАВЛЯЕМ СИНОНИМЫ ===== # Добавляем синонимы при создании ИЛИ если значение поля изменилось if is_new or old_field_value != current_field_value: # Если поле было обновлено и значение изменилось - добавляем старое значение - if old_field_value and old_field_value not in metadata_dict[KEY_SYNONYM]: - metadata_dict[KEY_SYNONYM].append(old_field_value) + if old_field_value and old_field_value not in metadata_dict[KEY_SYNONYM_EN]: + metadata_dict[KEY_SYNONYM_EN].append(old_field_value) # Добавляем текущее значение если его еще нет в синонимах - if current_field_value not in metadata_dict[KEY_SYNONYM]: - metadata_dict[KEY_SYNONYM].append(current_field_value) + if current_field_value not in metadata_dict[KEY_SYNONYM_EN]: + metadata_dict[KEY_SYNONYM_EN].append(current_field_value) # ===== ОЧИЩАЕМ ДУБЛИКАТЫ ===== # Удаляем дубликаты в списке синонимов, сохраняя порядок # (может случиться если пользователь вручную редактировал метаданные) - if KEY_SYNONYM in metadata_dict and isinstance(metadata_dict[KEY_SYNONYM], list): - metadata_dict[KEY_SYNONYM] = list(dict.fromkeys(metadata_dict[KEY_SYNONYM])) + if KEY_SYNONYM_EN in metadata_dict and isinstance(metadata_dict[KEY_SYNONYM_EN], list): + metadata_dict[KEY_SYNONYM_EN] = list(dict.fromkeys(metadata_dict[KEY_SYNONYM_EN])) # ===== СООБЩАЕМ DJANGO ЧТО ПОЛЕ ИЗМЕНИЛОСЬ ===== # Для JSONField нужно явно сообщить что мы изменили содержимое @@ -383,7 +383,7 @@ def create_or_get_related_article( # Собираем синонимы из метаданных для SEO ключевых слов и исключаем текущее значение поля # из списка (оно будет добавлено первым для приоритета) - other_synonyms = [s for s in instance.__dict__.get(metadata_field_name, {}).get(KEY_SYNONYM, []) if str(s) != main_field_value] + other_synonyms = [s for s in instance.__dict__.get(metadata_field_name, {}).get(KEY_SYNONYM_EN, []) if str(s) != main_field_value] # Собираем все синонимы с текущим значением первым all_synonyms = [main_field_value] + other_synonyms if other_synonyms else [main_field_value] diff --git a/lpon_site/frontend/utils_validators.py b/lpon_site/frontend/utils_validators.py index 6fa4ab3..95beacc 100644 --- a/lpon_site/frontend/utils_validators.py +++ b/lpon_site/frontend/utils_validators.py @@ -14,7 +14,7 @@ from django.http import HttpRequest from django.forms import ModelForm from django.contrib import messages from lpon_site.settings import ( - KEY_SYNONYM, + KEY_SYNONYM_EN, VALIDATE_KEY__MATCH_TYPE, VALIDATE_KEY__MODEL, VALIDATE_KEY__VALUE, ValidateMatchType, MIN_SYNONYM_WORD_LENGTH ) @@ -143,7 +143,7 @@ def validate_for_duplicates( }) return duplicates_found - # ПРОВЕРКА 2: SYNONYM MATCH (совпадение с синонимами в метаданных других записей) + # ПРОВЕРКА 2:SYN_ENMATCH (совпадение с синонимами в метаданных других записей) # Ищем: есть ли текущее значение main_field в синонимах других записей? # Например, если у записи A синонимы=['Sony Music', 'SME Records'], # а мы добавляем запись B с основным полем 'Sony Music', это совпадение! @@ -159,7 +159,7 @@ def validate_for_duplicates( has_synonym=RawSQL( f""" EXISTS ( - SELECT 1 FROM json_each({metadata_field_name}, '$.{KEY_SYNONYM}') + SELECT 1 FROM json_each({metadata_field_name}, '$.{KEY_SYNONYM_EN}') WHERE LOWER(json_each.value) = %s ) """, @@ -179,8 +179,8 @@ def validate_for_duplicates( # основное поле + все синонимы из метаданных # Этот список переиспользуется на этапах 3 и 4, избегая дублирования логики raw_values_to_analyze = [main_field_value] - if KEY_SYNONYM in metadata_dict and isinstance(metadata_dict[KEY_SYNONYM], list): - raw_values_to_analyze.extend(metadata_dict[KEY_SYNONYM]) + if KEY_SYNONYM_EN in metadata_dict and isinstance(metadata_dict[KEY_SYNONYM_EN], list): + raw_values_to_analyze.extend(metadata_dict[KEY_SYNONYM_EN]) # ПРОВЕРКА 3: EXACT_SYNONYM_MATCH (точное совпадение синонимов текущей записи с синонимами других) # Ищем: есть ли синонимы из текущей записи в синонимах других записей? @@ -188,10 +188,10 @@ def validate_for_duplicates( # Например, если текущая запись имеет синонимы=['Polydor Records', 'Vertigo France'], # а запись A имеет синонимы=['Vertigo France', 'Swirl'], это совпадение! # Пользователь подтверждает - удалим конфликтующие синонимы из других записей. - if KEY_SYNONYM in metadata_dict and isinstance(metadata_dict[KEY_SYNONYM], list): + if KEY_SYNONYM_EN in metadata_dict and isinstance(metadata_dict[KEY_SYNONYM_EN], list): # Собираем все синонимы текущей записи с нормализацией current_synonyms = [ - normalize_string(syn) for syn in metadata_dict[KEY_SYNONYM] + normalize_string(syn) for syn in metadata_dict[KEY_SYNONYM_EN] ] # Удаляем дубликаты синонимов, сохраняя порядок @@ -215,7 +215,7 @@ def validate_for_duplicates( query_params = [] for normalized_synonym in current_synonyms: synonym_query_parts.append( - f"EXISTS (SELECT 1 FROM json_each({metadata_field_name}, '$.{KEY_SYNONYM}') WHERE LOWER(json_each.value) = %s)" + f"EXISTS (SELECT 1 FROM json_each({metadata_field_name}, '$.{KEY_SYNONYM_EN}') WHERE LOWER(json_each.value) = %s)" ) query_params.append(normalized_synonym) @@ -283,7 +283,7 @@ def validate_for_duplicates( if len(word) >= effective_min_word_len: word_search_conditions.append( f"""EXISTS ( - SELECT 1 FROM json_each({metadata_field_name}, '$.{KEY_SYNONYM}') + SELECT 1 FROM json_each({metadata_field_name}, '$.{KEY_SYNONYM_EN}') WHERE LOWER(json_each.value) LIKE %s )""" ) @@ -343,7 +343,7 @@ def remove_conflicting_synonyms_from_duplicates( remove_conflicting_synonyms_from_duplicates( duplicates_queryset, 'j_label_metadata', - metadata_dict.get(KEY_SYNONYM) or [], + metadata_dict.get(KEY_SYNONYM_EN) or [], ) """ # Нормализуем синонимы для удаления один раз @@ -354,10 +354,10 @@ def remove_conflicting_synonyms_from_duplicates( dup_metadata = getattr(duplicate_record, metadata_field_name) or {} # Если в метаданных есть синонимы, удаляем те, которые совпадают с нашим списком - if KEY_SYNONYM in dup_metadata and isinstance(dup_metadata[KEY_SYNONYM], list): + if KEY_SYNONYM_EN in dup_metadata and isinstance(dup_metadata[KEY_SYNONYM_EN], list): # Удаляем синонимы, которые совпадают с переданным списком - dup_metadata[KEY_SYNONYM] = [ - syn for syn in dup_metadata[KEY_SYNONYM] + dup_metadata[KEY_SYNONYM_EN] = [ + syn for syn in dup_metadata[KEY_SYNONYM_EN] if normalize_string(syn) not in normalized_to_remove ] # Сохраняем обновленные метаданные @@ -403,7 +403,7 @@ def build_search_report( search_words.update(re.split(r'\s+', main_value_normalized)) # Собираем слова из синонимов метаданных - metadata_synonyms = metadata_dict.get(KEY_SYNONYM) or [] + metadata_synonyms = metadata_dict.get(KEY_SYNONYM_EN) or [] for synonym in metadata_synonyms: # Применяем супер-нормализацию к каждому синониму syn_normalized = super_normalize_string(synonym) @@ -429,7 +429,7 @@ def build_search_report( # Получаем метаданные и синонимы dup_metadata = getattr(dup, metadata_field_name) or {} - dup_synonyms = dup_metadata.get(KEY_SYNONYM) or [] + dup_synonyms = dup_metadata.get(KEY_SYNONYM_EN) or [] # Ищем слово в основном поле и синонимах (case-insensitive) found_locations = [] @@ -667,7 +667,7 @@ def validate_entity_for_admin_form( remove_conflicting_synonyms_from_duplicates( duplicates_queryset, metadata_field_name, - metadata_dict.get(KEY_SYNONYM) or [], # Удаляем все синонимы текущей записи + metadata_dict.get(KEY_SYNONYM_EN) or [], # Удаляем все синонимы текущей записи ) # Выходим без ошибки в админку, т.к. пользователь "проверил и уверен!" # Конфликтующие синонимы удалены, запись сохранится нормально @@ -679,7 +679,7 @@ def validate_entity_for_admin_form( # Для каждого синонима текущей записи ищем, в каких записях он есть # Собираем текущие синонимы с нормализацией - current_synonyms_list = metadata_dict.get(KEY_SYNONYM) or [] + current_synonyms_list = metadata_dict.get(KEY_SYNONYM_EN) or [] # Строим словарь: {нормализованный синоним: {оригинальный синоним, запись1, запись2, ...}} synonym_to_records = {} @@ -694,7 +694,7 @@ def validate_entity_for_admin_form( # Ищем этот синоним в метаданных других записей for dup in duplicates_queryset: dup_metadata = getattr(dup, metadata_field_name) or {} - dup_synonyms = dup_metadata.get(KEY_SYNONYM) or [] + dup_synonyms = dup_metadata.get(KEY_SYNONYM_EN) or [] # Проверяем: есть ли текущий синоним в синонимах этой записи for dup_syn in dup_synonyms: diff --git a/lpon_site/lpon_site/settings.py b/lpon_site/lpon_site/settings.py index 4c1eb94..f408527 100644 --- a/lpon_site/lpon_site/settings.py +++ b/lpon_site/lpon_site/settings.py @@ -317,7 +317,8 @@ LOGGING = { SLUG_MAX_LENGTH = 60 # Ключи для типовых параметров в мета-полях (для TbLabel, TbSeller, TbArtist, TbMusicStyle и т.д.) -KEY_SYNONYM = 'SYNONYM' +KEY_SYNONYM_EN = 'SYN_EN' # Ключ для хранения синонимов на английском языке (для поиска по синонимам) и ДЛЯ ПАРСЕРОВ +KEY_SYNONYM_RU = 'SYN_RU' # Ключ для хранения синонимов на русском языке (для представления на фронтенд) # ДЛЯ ВАЛИДАЦИИ (поиска похожих исполнителей, стилей и т.д. (используется в TbLabel.matching_type, TbSeller.matching_type и т.д.) VALIDATE_KEY__MATCH_TYPE = 'MATCH_TYPE'