add: универсальная хелпер-функция для save() моделей для создания (и проверки) связанных статей в TbArticle.
This commit is contained in:
@@ -19,6 +19,7 @@ from lpon_site.settings import (
|
|||||||
ValidateMatchType, MIN_SYNONYM_WORD_LENGTH
|
ValidateMatchType, MIN_SYNONYM_WORD_LENGTH
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -1224,6 +1225,100 @@ def update_synonyms_in_metadata(
|
|||||||
setattr(instance, metadata_field_name, metadata_dict)
|
setattr(instance, metadata_field_name, metadata_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def create_or_get_related_article(instance, article_type, main_field_name, metadata_field_name, related_fk_field_name):
|
||||||
|
"""
|
||||||
|
Создает или получает связанную статью для сущности модели.
|
||||||
|
|
||||||
|
Универсальный хелпер для создания статей при сохранении лейблов, артистов и т.д.
|
||||||
|
|
||||||
|
Алгоритм:
|
||||||
|
1. Получает значение FK поля напрямую через getattr() (никаких запросов в БД)
|
||||||
|
2. Если статья найдена → возвращает её
|
||||||
|
3. Если FK поле пусто → создает новую статью с автоматическими SEO параметрами
|
||||||
|
|
||||||
|
Параметры:
|
||||||
|
-----------
|
||||||
|
instance : django.db.models.Model
|
||||||
|
Экземпляр модели (TbLabel, TbArtist, TbMusicStyle и т.д.)
|
||||||
|
Должен иметь поле k_{type}_to_article для привязки статьи
|
||||||
|
|
||||||
|
article_type : TbArticle.ArticleType
|
||||||
|
Тип статьи (например, TbArticle.ArticleType.LABEL)
|
||||||
|
|
||||||
|
main_field_name : str
|
||||||
|
Имя основного поля сущности (например, 's_label' для TbLabel)
|
||||||
|
|
||||||
|
metadata_field_name : str
|
||||||
|
Имя поля метаданных со словарем синонимов (например, 'j_label_metadata')
|
||||||
|
|
||||||
|
related_fk_field_name : str
|
||||||
|
Имя FK поля в модели instance (например, 'k_label_to_article')
|
||||||
|
Передается явно из save() модели
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TbArticle: Созданная или найденная статья
|
||||||
|
|
||||||
|
Пример использования в TbLabel.save():
|
||||||
|
article = create_or_get_related_article(
|
||||||
|
self,
|
||||||
|
TbArticle.ArticleType.LABEL,
|
||||||
|
's_label',
|
||||||
|
'j_label_metadata',
|
||||||
|
'k_label_to_article'
|
||||||
|
)
|
||||||
|
self.k_label_to_article = article
|
||||||
|
"""
|
||||||
|
from .models import TbArticle
|
||||||
|
|
||||||
|
# Получаем verbose_name модели для универсальности
|
||||||
|
verbose_name = instance._meta.verbose_name # "Лейбл", "Артист" и т.д.
|
||||||
|
|
||||||
|
# Генерируем slug используя verbose_name (более гибко чем хардкод)
|
||||||
|
# "Лейбл" → "label", "Артист" → "artist"
|
||||||
|
article_slug_default = make_slug(slug_it=verbose_name)
|
||||||
|
|
||||||
|
# Получаем значение основного поля (например, "Sony Records")
|
||||||
|
main_field_value = getattr(instance, main_field_name, '')
|
||||||
|
|
||||||
|
# ===== ПОПЫТКА НАЙТИ СУЩЕСТВУЮЩУЮ СТАТЬЮ =====
|
||||||
|
# Получаем статью через FK поле напрямую (никаких запросов в БД)
|
||||||
|
try:
|
||||||
|
article = getattr(instance, related_fk_field_name)
|
||||||
|
if article:
|
||||||
|
# FK поле содержит статью - возвращаем её
|
||||||
|
return article
|
||||||
|
except:
|
||||||
|
# FK поле не существует или пусто, создаем новую
|
||||||
|
pass
|
||||||
|
|
||||||
|
# ===== СТАТЬЯ НЕ ПРИВЯЗАНА. СОЗДАËМ НОВУЮ СТАТЬЮ =====
|
||||||
|
|
||||||
|
# Собираем синонимы из метаданных для SEO ключевых слов и исключаем текущее значение поля
|
||||||
|
# из списка (оно будет добавлено первым для приоритета)
|
||||||
|
other_synonyms = [s for s in instance.__dict__.get(metadata_field_name, {}).get(KEY_SYNONYM, []) if str(s) != main_field_value]
|
||||||
|
|
||||||
|
# Собираем все синонимы с текущим значением первым
|
||||||
|
all_synonyms = [main_field_value] + other_synonyms if other_synonyms else [main_field_value]
|
||||||
|
synonyms_str = ", ".join(str(s) for s in all_synonyms)
|
||||||
|
|
||||||
|
# Создаем объект статьи
|
||||||
|
article = TbArticle(
|
||||||
|
s_article_title=f"[{verbose_name}] {main_field_value} (auto-make)", # Техническое название для админки
|
||||||
|
s_article_title_html=main_field_value,
|
||||||
|
seo_title=main_field_value,
|
||||||
|
seo_keywords=f"{synonyms_str}, {verbose_name}, {article_slug_default}",
|
||||||
|
seo_description=f"{main_field_value} ({verbose_name}): информация.",
|
||||||
|
l_article_type=article_type,
|
||||||
|
b_article_published=True,
|
||||||
|
slug=make_slug(slug_it=main_field_value, slug_default=article_slug_default),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Сохраняем статью
|
||||||
|
article.save()
|
||||||
|
|
||||||
|
return article
|
||||||
|
|
||||||
|
|
||||||
def generate_admin_save_message(request, obj, is_new, related_article,
|
def generate_admin_save_message(request, obj, is_new, related_article,
|
||||||
obj_field_name='s_label',
|
obj_field_name='s_label',
|
||||||
article_title_field='s_article_title'):
|
article_title_field='s_article_title'):
|
||||||
@@ -1333,3 +1428,4 @@ def generate_admin_save_message(request, obj, is_new, related_article,
|
|||||||
if related_article:
|
if related_article:
|
||||||
msg += f' Связанная статья: «{article_title}» >> {article_info} {article_link}'
|
msg += f' Связанная статья: «{article_title}» >> {article_info} {article_link}'
|
||||||
messages.success(request, mark_safe(msg))
|
messages.success(request, mark_safe(msg))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user