From 64880da11a6d8c526a790576b2442c66c1a6f74a Mon Sep 17 00:00:00 2001 From: erjemin Date: Tue, 30 Jun 2026 16:41:42 +0300 Subject: [PATCH] =?UTF-8?q?add:=20=D1=83=D0=BD=D0=B8=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=81=D0=B0=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D1=85=D0=B5=D0=BB?= =?UTF-8?q?=D0=BF=D0=B5=D1=80-=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20save()=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20(=D0=B8=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B8)=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=D1=82=D0=B0=D1=82=D0=B5=D0=B9?= =?UTF-8?q?=20=D0=B2=20TbArticle.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lpon_site/frontend/utils.py | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/lpon_site/frontend/utils.py b/lpon_site/frontend/utils.py index fd931c2..3810f9d 100644 --- a/lpon_site/frontend/utils.py +++ b/lpon_site/frontend/utils.py @@ -19,6 +19,7 @@ from lpon_site.settings import ( ValidateMatchType, MIN_SYNONYM_WORD_LENGTH ) + logger = logging.getLogger(__name__) @@ -1224,6 +1225,100 @@ def update_synonyms_in_metadata( 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, obj_field_name='s_label', article_title_field='s_article_title'): @@ -1333,3 +1428,4 @@ def generate_admin_save_message(request, obj, is_new, related_article, if related_article: msg += f' Связанная статья: «{article_title}» >> {article_info} {article_link}' messages.success(request, mark_safe(msg)) +