Т.к. эта статья — результат нескольких лет экспериментов, то букв будет много. Но — возможно — она сэкономит кому-то многие месяцы езды велосипедом по граблям, которые и описаны.
В общем случае речь идет даже не о Django, а о печати регламентированных документов из python с использованием шаблонизаторов.
Кому дальше читать лень — сразу скажу — проблема до конца не решена. Но более-менее рабочий вариант вырисовался.
1. Задача
Пользователь вводит данные в веб-форму
Сервер вставляет эти данные в шаблон печатной формы
И отдает пользователю в виде, пригодном для печати
2. Ограничения
Формы бывают “мягкие” (где точность не очень важна — например Договор или Счет) и “жесткие” (точность — максимальная, под сканер — например уведомление мигранта или заявление на УСН (форма 26.2-1)).
При этом даже “мягкие” формы должны печататься максимально близко к задуманному создателем (если я сказал, что границы — 1см, то пользователь должен получить документ с границами ровно 1см) и — особенно — учитывать разрывы страниц (см. формы 11001, 21001 и т.д.).
Обязательно — минимальные телодвижения по преобразованию исходного материала (как правило — .xls или .doc, цельнотянутые из «Консультаната» или «Гаранта»).
Т.к. речь идет о веб-приложении — крайне желательны отзывчивость и надежность решения => крайне желательна работа с нативными библиотеками python.
Желательна возможность размещения всего этого хозяйства на арендованном хостинге (в идеале — GAE).
Желательна возможность визуального редактирования шаблонов.
Желателен быстрый предварительный просмотр шаблона (а еще лучше — и результата).
Первый этап — выбор конечного формата. После недолгих размышлений с различных т.з. (кросс-платформенность, гарантированность результата, конвертируемость в) выбор пал на PDF.
Теперь — входные форматы и как их преобразовать.
3. Мягкие формы
ODF
Речь идет об Open Document Format — ODS, ODT и иже.
Здесь всё очень просто:
Редактируем шаблон в LibreOffice (оставляя место для данных).
Каким-то образом заполняем поля в Django.
Каким-то образом получаем PDF
Место для данных: или же добавляем user-defined поля в документ — или же прямо в текст вставляем {{ теги_django }}. В первом случае заполнение этих полей потом из python — скорее всего возможно, но я даже не представляю как (точнее — всё представляемое выглядит крайне заморочливо). Поэтому просто расставляем теги в виде текста.
В этом случае заполнение полей — элементарно — просто скармливаем шаблон шаблонизатору Django (ковыряние внутри шаблона библиотеками питона оставим гентушникам :-). А дабы не раззиповывать/зазиповывать документы при каждом пинке — документы сохраняются в *.fodX (Flat X) — один-единственный неупакованный xml. Шаблонеру скармливается как xml же.
Получение PDF — без вариантов — с помощью LibreOffice: скармливаем демону LibreOffice (libreofficed (где-то у убунтоводов нашел)) или unoconv или ручной работы запускалку LO в режиме демона. Все эти варианты — примерно одно и то же.
Достоинства
Можно сразу использовать нарытые в Интернетах документы (как правило — из “Консультанта”, в форматах Microsoft Office).
С редактированием шаблонов — никаких проблем.
Как и с предварительным просмотром.
Возможно — получение PDF об Google Docs — пока не пробовал. Но в том, что это будет реактивно — сомневаюсь уже сейчас (а в том, что некорректно — не сомневаюсь; попробуйте загрузить в гугледокс ту же форму 21001 от Консультанта (лежит на сайте налоговой)).
Недостатки
Иногда при записи шаблонов LibreOffice спонтанно гробит теги, вставляя внутрь {{..}} всякие span lang=”en-GB” и иже. Приходится потом вручную возвращать всё назад.
Просто фантастическая ресурсоемкость для сервера — CPU 100% (только одного, сколько бы их не было), сотни метров RAM, получение PDF — до минуты или после (форма 21001 — 50 секунд на P4-3.0). Java же.
Тянет за собой немеряно пакетов (Fedora, CentOS).
Наличие хоть какого-то X-сервера (Xvfb например).
Наверное, на каком-то хостинге и позволят развернуть LibreOffice — но я сильно сомневаюсь в nic.ru например. О GAE речь даже не идет.
Предварительного просмотра результата — нет.
Резюме
Как крайний запасной вариант — подходит. Но именно как крайний.
HTML
Здесь с редактированием шаблонов (руками) и шаблонизатором (искаропки) всё понятно. Остался один маленький, но главный вопрос — как получить PDF? Быстро, качественно, с разрывами страниц там, где надо. И вот здесь было больше всего экспериментов.
Многочисленные эксперименты с pure python html render (типа PISA и предков/наследников/форков) привели к одному важному (IMHO) выводу: чтобы получить гарантированный результат — надо использовать готовый html движок. Коих, как мы все знаем, аж 4 (из нормальных). Из них использовать в linux можно аж 2 — gecko и webkit. Вызвать gecko из python, скорее всего, возможно — но а) для этого нужен запущенный X (как в случае LibreOffice) и б) [полу]готового рецепта я не нашел.
Остался webkit:
PyQt4>Qt>WebKit>QPrinter (типа такого). Нативно (хоть и тащит с собой очень много), шустро — но pagebreak не ловит. Кроме того — нужны специальные танцы с DPI и ZoomFactor.
GTK>WebKit>GTK printer (типа такого такого). Нативно, шустро — но тоже page break не ловит.
Использовать специально доработанный webkit — wkhtmltopdf — в виде внешнего бинарника (сейчас именно этот вариант и используется) или через нативный python binding (в процессе, но есть небольшие проблемы). Нативно (если binding), шустро, ловит page-break, результат гарантирован.
Достоинства
Теоретически возможно визуальное редактирование.
Мгновенный предварительный просмотр (в виде html же) — как шаблона — так и результата.
Реактивная конвертация в PDF.
Pure python API конвертирования в PDF (это которое “в процессе”).
Недостатки
Всё-таки качественный HTML — ручной работы.
Сложные формы (типа 21001) придется самостоятельно писать или рисовать — ибо в Интернетах это — страшный .xls.
Т.к. используется либа/бинарник, собранные для Linux — на том же nic.ru (FreeBSD) ничего не получится (без костылей). О GAE речь по-прежнему не идет.
Резюме
Основной вариант для “мягких” документов. Но все-таки нужно искать качественный pure python html render — без флешей, JS и других мультиков — но с качественной обработкой CSS.
Возможно
На будущее рассматриваются форматы TeX, LaTeX, Lyx, docbook — но пока преимуществ не видать (особенно для “почти мягких” форм — типа той же 21001).
4. Жесткие формы
Здесь всё намного печальнее. Особенно в свете того, что здесь уже визуальный редактор крайне желателен.
Кроме того — в подавляющем большинстве (если не во всех) “жестких” форм РФ используются “квадратики” — когда текст разбивается на буквы — и каждая вписывается в свой квадратик (пример).
Отбросим первые попавшиеся (типа “натянуть текст на tiff”) и сразу перейдем к финалистам.
RML
Разработка компании Reportlab (да-да, python-reportlab — это их) — обыкновенный XML, позволяющий выделывать чудеса с PDF. Т.к. всем известный python-trml2pdf уже RIP (как мне честно отписал его разработчик) — пришлось взять этот trml2pdf и немного допилить, т.к. он не поддерживает многие интересные фичи RML, а покупать (а тем более — ломать) коммерческий rml2pdf мне запрещает религия.
Достоинства
Нативно
Шустро
Гибко
С хостингом (теоретически) проблем быть не должно — даже в GAE (не пробовал).
Недостатки
Строго ручная работа
Очень заморочливый синтаксис — когда надо смешать точное позиционирование (“graphics”) с “мягким” текстом (“flowables”) (отсюда, видимо, отсутствие визуального редактора).
Никакого предварительного просмотра — ни шаблона, ни результата.
Резюме
Запасной вариант для точных форм (особенно простых).
PDF-формы
Здесь всё очень просто: исходник в PDF — и конечный результат в PDF.
Берем исходную PDF-форму в левую руку
XFDF (простенький xml), обработанный встроенным шаблонером Django — в правую
сливаем их (populate) в новый PDF (“раскатанный” — flatten)
и отдаем пользователю
Проблема всего лишь одна — п.3.
На сегодняшний день нативного и корректно работающего python API для работы с PDF-формами не обнаружено (хотя poppler кое-что уже умеет — но пилить там, судя по всему, еще много), поэтому единственный приемлемый вариант — iText. Через pdftk или свой велосипед — это уже по вкусу.
Достоинства
В PDF-форму можно превратить что угодно (как — отдельный вопрос).
Можно даже редактировать (аналогично).
Абсолютно гарантированный результат.
Встроенные в формат PDF “квадратики” (combo).
Скорее всего — нет проблем с хостингом (возможно — и с GAE) — не пробовал.
Недостатки
Вызов внешнего приложения вместо python API.
Java же.
Резюме
Основной вариант для точных печатных форм.
5. Общее резюме
Итого на сегодня сформировалось:
“Мягкие” формы — html|webkit — но через довольно тяжелую, избыточную и не слишком портабельную библиотеку webkittox (и продолжать искать).
“Жесткие” формы — PDF-формы, но через костыль внешнюю JAVA-библиотеку (и продолжать насиловать poppler).
ODF и RML — как запасные варианты соответственно.
PS. Как всё это работает — можно посмотреть здесь — без ODF и RML, но последние предусмотрены.