Управление PDF с Django через шаблон и отправлено в виде вложения электронной почты
Я создаю сайт для регистрации студентов с помощью фреймворка Django.
Я прибыл в место, где мне нужно отобразить форму для пользователя, и я получил информацию, введенную после обработки, я должен отправить электронное письмо пользователю, содержащее введенную им информацию, поместив его в PDF-файл, который я должен сгенерировать. из шаблона, содержащего контекстный словарь.
На данный момент PDF-файл, который я могу создать, возможен только путем отправки его в браузер через функцию HttpResponse
, но проблема в том, что пользователь решает скачать его или нет, и у меня есть больше возможностей положить руку в pdf, чтобы отправить его в виде вложения.
Я думал открыть базу данных, где будет поле типа models.FileField
сгенерируйте pdf с помощью контекстного словаря через библиотеку xhtml2pdf
что я могу сохранить в базе данных с сигналом, а затем отправить письмо, приняв файл в качестве вложения.
Ни один из методов, которые я пытался достичь, на данный момент не является успешным. Вот мой код:
utils.py
from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type="application/pdf")
return None
models.py
from django.conf import settings
from django.db.models.signals import pre_save, post_save
from django.core.mail import EmailMessage, EmailMultiAlternatives
from django.db import models
# Create your models here.
class MyModel(models.Model):
order_id = models.CharField(max_length=255)
nom = models.CharField(max_length=255)
email = models.EmailField()
pdf = models.FileField(upload_to="pdfs", null=True, blank=True)
def create_order_id(instance, new_order_id=None):
order_id = instance.id
if new_order_id is not None:
order_id = new_order_id
qs = MyModel.objects.filter(order_id=order_id)
exists = qs.exists()
if exists:
new_order_id = "%s-%s" %(order_id.first().id)
return create_order_id(instance, new_order_id)
return order_id
def pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.order_id :
instance.new_order_id = create_order_id(instance)
def send_mail_insciption(instance):
subject = "Thank you"
from_email = settings.EMAIL_HOST_USER
to_email = [instance.email]
body = "Votre inscription"
email_pdf = EmailMultiAlternatives(
subject = subject,
body =body,
from_email = from_email,
to=to_email,
)
email_pdf.attach_alternative(instance.pdf, "application/pdf")
email_pdf.send()
def post_save_receiver(sender, instance, *args, **kwargs):
send_mail_insciption(instance)
pre_save.connect(pre_save_receiver, sender=MyModel )
post_save.connect(post_save_receiver, sender=MyModel)
#views.py
def pdf_genarete(request):
form = MyModelForm(request.POST or None)
if form.is_valid():
nom = form.cleaned_data.get("nom")
email = form.cleaned_data.get("email")
obj = MyModel.objects.create(nom=nom, email=email)
context = {"models_instance": obj}
pdf = render_to_pdf("pdfapp/template_pdf.html", context)
filename = "mypdf_{}.pdf".format(obj.order_id)
pdf.save()
obj.pdf.save(filename, File(BytesIO(pdf.content)))
return redirect(reverse("home"))
return render(request, "pdfapp/formulaire.html", {"form": form})
После выполнения вот ошибка на терминале:
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/db/models/base.py", line 769, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 178, in send
for receiver in self._live_receivers(sender)
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 178, in <listcomp>
for receiver in self._live_receivers(sender)
File "/home/michel/saintexupery/saintexupry/pdfapp/models.py", line 69, in post_save_receiver
send_mail_insciption(instance)
File "/home/michel/saintexupery/saintexupry/pdfapp/models.py", line 65, in send_mail_insciption
email_pdf.send()
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/message.py", line 294, in send
return self.get_connection(fail_silently).send_messages([self])
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/backends/smtp.py", line 110, in send_messages
sent = self._send(message)
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/backends/smtp.py", line 124, in _send
message = email_message.message()
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/message.py", line 254, in message
msg = self._create_message(msg)
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/message.py", line 440, in _create_message
return self._create_attachments(self._create_alternatives(msg))
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/message.py", line 450, in _create_alternatives
msg.attach(self._create_mime_attachment(*alternative))
File "/home/michel/saintexupery/env/lib/python3.6/site-packages/django/core/mail/message.py", line 393, in _create_mime_attachment
Encoders.encode_base64(attachment)
File "/usr/lib/python3.6/email/encoders.py", line 32, in encode_base64
encdata = str(_bencode(orig), 'ascii')
File "/home/michel/saintexupery/env/lib/python3.6/base64.py", line 534, in encodebytes
_input_type_check(s)
File "/home/michel/saintexupery/env/lib/python3.6/base64.py", line 520, in _input_type_check
raise TypeError(msg) from err
TypeError: expected bytes-like object, not FieldFile
1 ответ
В вашем коде у вас есть эта часть:
def send_mail_insciption(instance):
...
email_pdf.attach_alternative(instance.pdf, "application/pdf")
email_pdf.send()
Сообщение об ошибке (и traceback) говорит, что электронное письмо ожидает байтов в качестве вложения, но instance.pdf
это FieldFile
,
Попробуйте преобразовать файл в байты, возможно, используя instance.pdf.read()
и дайте нам знать, если это решит проблему.