Django WeasyPrint эффективно использует память при больших наборах данных
Я использую WeasyPrint в Django для создания PDF-файла. Однако при обработке около 11 000 записей он потребляет все доступные ресурсы, выделенные модулю Kubernetes. В результате модуль перезапускается, и я так и не получаю сгенерированный PDF-файл по электронной почте.
Существуют ли:
- Есть ли какие-нибудь облегченные библиотеки PDF, которые могут более эффективно создавать PDF-файлы для тысяч записей?
- Есть ли какие-либо методы оптимизации в WeasyPrint (или в целом) для сокращения использования ресурсов и успешного создания PDF-файла?
Я столкнулся с такой же проблемой, когда WeasyPrint потреблял более 8 ГБ оперативной памяти для больших PDF-файлов. Вот что у меня сработало
Решение 1: Переключился на ReportLab (Это решило проблему)
Я заменил WeasyPrint на ReportLab, и объем используемой памяти сократился с 8 ГБ до менее чем 500 МБ:
python
from reportlab.platypus import SimpleDocTemplate, Table
import io
def generate_pdf(queryset):
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer)
elements = []
# This iterator prevents loading all records at once
for batch in queryset.iterator(chunk_size=1000):
data = [[record.field1, record.field2] for record in batch]
elements.append(Table(data))
doc.build(elements)
return buffer.getvalue()
Сгенерировал PDF-файл объемом 11 000 записей за 45 секунд, используя всего 400 МБ оперативной памяти. Стиль более простой, но на самом деле он завершенный.
Решение 2: Обработка фрагментов (Работает, но медленнее)
Когда мне приходилось использовать WeasyPrint для создания сложных макетов, я обрабатывал их по частям:
python
from PyPDF2 import PdfMerger
import gc
def generate_large_pdf(queryset):
merger = PdfMerger()
# Process 500 records at a time
for i in range(0, queryset.count(), 500):
chunk = queryset[i:i+500]
html = render_to_string('template.html', {'records': chunk})
pdf = HTML(string=html).write_pdf()
merger.append(io.BytesIO(pdf))
# This is crucial - forces garbage collection
del html, pdf
gc.collect()
output = io.BytesIO()
merger.write(output)
return output.getvalue()
Это позволило сохранить объем памяти менее 1 ГБ, но заняло 3-4 минуты для 11 000 записей.
Что не сработало:
Увеличение объема оперативной памяти модуля до 16 ГБ - просто отсрочило сбой
Использование флага
--optimize-size
в WeasyPrint - минимальное улучшениеПытаюсь использовать wkhtmltopdf - те же проблемы с памятью
Моя рекомендация: Используйте ReportLab для PDF-файлов с большим объемом данных, используйте WeasyPrint только для сложных требований к дизайну с небольшими наборами данных (>1000 записей).