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

116 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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} цитат."))