add: валидатор форм для избежания дублей (2) оформлено в хелпер

This commit is contained in:
2026-06-20 18:37:24 +03:00
parent 3d9f0a6b5d
commit 6a178c9c9b
3 changed files with 122 additions and 58 deletions

View File

@@ -2,22 +2,15 @@
# Регистрируем модели с удобным интерфейсом.
from django import forms
from django.db import models
from django.forms import TextInput, Textarea, URLField
from django.forms import Textarea
from django.contrib import admin
from django.utils.html import format_html, mark_safe
from django.core.exceptions import ValidationError
from django.urls import reverse
from lpon_site.settings import (
VALIDATE_KEY__MATCH_TYPE, VALIDATE_KEY__MODEL, VALIDATE_KEY__VALUE,
VALIDATE_VAL__IS_DUPLICATE
)
from easy_thumbnails.files import get_thumbnailer
from .models import (
TbImage, TbArticle, TbArtist, TbItem, TbLabel, TbSeller,
TbOffer, TbSource, TbOfferHistory, TbMusicStyle
)
from .utils import validate_for_duplicates
from .utils import validate_entity_for_admin_form
# ============================================================================
# АДМИНИСТРИРОВАНИЕ TbImage
@@ -467,54 +460,18 @@ class LabelAdminForm(forms.ModelForm):
def clean(self):
"""
Валидируем форму: проверяем на дубликаты основного поля s_label
Валидируем форму: проверяем на совпадения (дубликаты) основного поля s_label
"""
cleaned_data = super().clean()
# Получаем значения из очищенных данных
s_label = cleaned_data.get('s_label')
j_label_metadata = cleaned_data.get('j_label_metadata') or {}
if s_label:
# Вызываем валидатор для проверки дубликатов.
# Возвращает словарь: {VALIDATE_KEY__MATCH_TYPE: type, VALIDATE_KEY__VALUE: queryset, ...} или пустой словарь, если дубликатов нет
result = validate_for_duplicates(
model_class=TbLabel,
instance_pk=self.instance.pk, # pk экземпляра (None для новых)
main_field_value=s_label,
metadata_dict=j_label_metadata,
main_field_name='s_label',
metadata_field_name='j_label_metadata',
)
# Если найдены дубликаты, обрабатываем по типу совпадения
if VALIDATE_KEY__MATCH_TYPE in result:
match_type = result[VALIDATE_KEY__MATCH_TYPE]
duplicates_queryset = result[VALIDATE_KEY__VALUE]
if match_type == VALIDATE_VAL__IS_DUPLICATE:
# Точное совпадение основного поля — критическая ошибка
# Строим ссылки на дубликаты для быстрого перехода в админке
dup_links = []
for dup in duplicates_queryset:
# Получаем относительный URL для редактирования дубликата
# reverse вернет абсолютный путь, берем часть после /admin/
admin_url = reverse('admin:frontend_tblabel_change', args=[dup.pk])
# Делаем ссылку относительной (убираем начальный слэш)
rel_url = admin_url.lstrip('/')
dup_links.append(
f"<big><a href='{rel_url}'>#{dup.pk} '{dup.s_label}'</a></big>"
)
dup_list = ", ".join(dup_links)
raise ValidationError(
mark_safe(
f"ОШИБКА: Найден точный дубликат лейбла! "
f"Отредактируйте {dup_list} "
f"или используйте синонимы из найденной записи."
)
)
# Другие типы дубликатов обработаны будут позже
# Используем универсальный хелпер для проверки дубликатов
# Модель берется автоматически из self.Meta.model
validate_entity_for_admin_form(
self,
cleaned_data,
main_field_name='s_label',
metadata_field_name='j_label_metadata'
)
return cleaned_data