Как отправить сгенерированный 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-файл, который большинство хостинг-провайдеров удаляют через некоторое время.