Files
2020-dq/dicquo/web/management/commands/reprocess_typography.py
T
2026-02-19 20:00:41 +03:00

116 lines
5.0 KiB
Python

from django.core.management.base import BaseCommand
from web.models import TbDictumAndQuotes
try:
from etpgrf.typograph import Typographer
from etpgrf.layout import LayoutProcessor
from etpgrf.hyphenation import Hyphenator
from etpgrf.sanitizer import SanitizerProcessor
except ImportError:
print("Ошибка: библиотека etpgrf не найдена. Пожалуйста, установите её через 'poetry add etpgrf'")
Typographer = None
class Command(BaseCommand):
help = 'Переобрабатывает все цитаты через etpgrf с "санитайзером" и "висячей пунктуацией: слева"'
def add_arguments(self, parser):
parser.add_argument(
'--dry-run',
action='store_true',
help='Запустить без сохранения изменений в БД',
)
parser.add_argument(
'--limit',
type=int,
help='Ограничить количество обрабатываемых записей',
)
parser.add_argument(
'--offset',
type=int,
default=0,
help='Пропустить первые N записей (использовать вместе с limit)',
)
def handle(self, *args, **options):
if not Typographer:
self.stdout.write(self.style.ERROR('Библиотека Etpgrf отсутствует.'))
return
# Настройки типографа
settings = {
'langs': ['ru'],
'process_html': True, # Обрабатываем как HTML
'quotes': True,
'layout': LayoutProcessor(langs=['ru'], process_initials_and_acronyms=True, process_units=True),
'unbreakables': True,
'hyphenation': Hyphenator(langs=['ru'], max_unhyphenated_len=12),
'symbols': True,
'hanging_punctuation': 'left', # ВАЖНО: Слева
'mode': 'mixed',
'sanitizer': SanitizerProcessor(mode='etp'), # ВАЖНО: Санитайзинг включен (очистит старую разметку)
}
self.stdout.write(f"Настройка Типографа с параметрами: {settings}")
typographer = Typographer(**settings)
qs = TbDictumAndQuotes.objects.all().order_by('id')
start_index = options['offset']
end_index = None
if options['limit']:
end_index = start_index + options['limit']
if end_index:
qs = qs[start_index:end_index]
else:
qs = qs[start_index:]
count = qs.count()
self.stdout.write(f"Найдено {count} цитат для обработки (сдвиг {start_index})...")
# Попытка импортировать tqdm для красоты, если нет - обычный счетчик
try:
from tqdm import tqdm
iterator = tqdm(qs, total=count)
except ImportError:
iterator = qs
processed_count = 0
for dq in iterator:
try:
# Берем исходный текст.
# Если в szContent уже лежит старый HTML (Муравьев), санитайзер 'etp' его вычистит.
source_text = dq.szContent
if not source_text:
continue
new_html = typographer.process(source_text)
# Обрабатываем intro если есть
new_intro_html = ""
if dq.szIntro:
new_intro_html = typographer.process(dq.szIntro)
if options['dry_run']:
self.stdout.write(f"[{dq.id}] Будет обновлено. Предпросмотр: {new_html[:50]}...")
else:
dq.szContentHTML = new_html
if new_intro_html:
dq.szIntroHTML = new_intro_html
# Сохраняем в обход метода save(), чтобы не триггерить ничего лишнего,
# или вызываем save(), если там теперь пусто (в нашей новой моделе save пустой).
# Используем update_fields для скорости.
dq.save(update_fields=['szContentHTML', 'szIntroHTML'])
processed_count += 1
if not isinstance(iterator, qs.__class__): # Если это не tqdm
if processed_count % 10 == 0:
self.stdout.write(f"Обработано {processed_count}/{count}...", ending='\r')
except Exception as e:
self.stdout.write(self.style.ERROR(f"Ошибка обработки id={dq.id}: {e}"))
self.stdout.write(self.style.SUCCESS(f"\nГотово! Обработано {processed_count} цитат."))