Как отправить сгенерированный PDF в качестве вложения в электронное письмо с помощью xhtml2pdf

Я генерирую PDF с помощью шаблона HTML и функции рендеринга xhtml2pdf. Мне нужно представление, которое может быстро сгенерировать и отправить этот PDF в поле электронной почты модели. Что-то, что не хранит pdf-файл где-либо, а просто использует временный файл для отправки вложения по электронной почте. Я получаю ошибки "Требуется байтоподобный объект". Буду признателен за любую помощь.

views.py

class Pdf(View):
    model = Pass

    def get(self, request, id=None, *args, **kwargs):
        today = timezone.now()
        guest = get_object_or_404(Pass,id=id)
        params = {
            'today': today,
            'guest': guest,
            'request': request
        }
        return Render.render('guestpass/pdf.html', params)

urls.py

path('export/pass/<int:id>/', views.Pdf.as_view(),name='print'),

Я делал нечто подобное в одном из своих проектов. Я создал PDF из html-шаблона и отправил его пользователю по электронной почте. Я использовал celery, так как генерация pdf и отправка по электронной почте могут отнимать много времени, но вам это не нужно, если только вы не чувствуете, что это вызывает проблемы с производительностью.

Код отправки почты выглядел примерно так:

from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.utils.html import strip_tags

def send_email(subject, html_content, to, attachments=None):
    try:
        text_content = strip_tags(html_content)
        email = EmailMultiAlternatives(
            subject,
            text_content,
            settings.EMAIL_HOST_USER,
            [to],
            attachments=attachments,
        )
        email.attach_alternative(html_content, "text/html")
        email.send()
        return True
    except Exception as e:
        print(e)
        return False

Эту функцию я использовал для создания PDF, поделитесь ею, так как вы получили ошибку "Требуются байтоподобные объекты.".

from django.template.loader import get_template

# for pdf generation
from xhtml2pdf import pisa


def render_to_pdf(template_name, context):
    """
    Shortcut function to render a template into a PDF.
    Returns PDF value.
    """

    template = get_template(template_name)
    html = template.render(context)
    pdf_data = pisa.CreatePDF(html)

    if pdf_data.err:
        raise Exception("Error generating PDF")

    return pdf_data.dest.getvalue()

И наконец, связав все это вместе, вы можете сделать такой вид:

def generate_pdf(order):
    """
    To give a sense of what you can do. Change it according to your use case
    """
    try:
        pdf_data = render_to_pdf("pdfs/xyz.html", {"order": order})
    except Exception as e:
        print(e)
        return False # handle error properly

    pdf_directory = "<project_name>/media/invoices"

    # create directory if not exists
    os.makedirs(pdf_directory, exist_ok=True)

    pdf_filename = os.path.join(pdf_directory, f"{uuid}.pdf")

    with open(pdf_filename, "wb") as f:
        f.write(pdf_data)

    email_html_content = render_to_string(
        "pdfs/confirmation.html",
        {
            "order": order,
        },
    )

    send_email(
        "Subject goes here",
        email_html_content,
        email_you_want_to_sent,
        attachments=[(pdf_filename, pdf_data, "application/pdf")],
    )

Вам придется создать временный PDF-файл, который большинство хостинг-провайдеров удаляют через некоторое время.

Вернуться на верх