I have a Django library application, wherein from a list of books, the customer can email a particular book's pdf file link that was originally uploaded using FileField by the admin. Now, the email is being sent/received successfully, however the pdf file is not getting attached.
I have also looked into other Stack Overflow references for the same, but I am unable to interpret the correct solution: Django email attachment of file upload
On clicking the email button, the form is submitted as follows: three hidden values are also being submitted on submitting the form, one of which is the book.file.url
.
<form method="POST" action ="{% url 'email_book' %}" enctype="multipart/form-data">
{% csrf_token %}
# correction made
<input type="hidden" name="book_title" value="{{ book.id }}">
<button type="submit" class="btn btn-info"><span class="glyphicon glyphicon-envelope"></span> Email</button>
</form>
In views.py, I have used Django's EmailMessage class as follows:
def send_email(request):
# corrections made, pdf file path is being retrieved
book = Book.objects.get(pk=int(request.POST.get('id')))
book_title = book.title
book_author = book.author
book_pdf = book.file.path #inplace of book.file.url
email_body = "PDF attachment below \n Book: "+book_title+"\n Book Author: "+book_author
try:
email = EmailMessage(
'Book request',
email_body,
'sender smtp gmail' + '<dolphin2016water@gmail.com>',
['madhok.simran8@gmail.com'],
)
# this is the where the error occurs
email.attach_file(book_pdf, 'application/pdf')
email.send()
except smtplib.SMTPException:
return render(request, 'catalog/index.html')
return render(request, 'catalog/dashboard.html')
The uploaded files are stored in /media/books_pdf/2018/xyz.pdf
. And the book.file.url contains the above file path, and yet the pdf file is not getting attached to the email.
So I am retrieving the file path dynamically using book.file.url
, and yet the code is right.
How do I retrieve that book's pdf file path/name required.
To retrieve the pdf file path, we have to use book.file.path
instead of book.file.url
.
The problem is that the attach_file()
method expects a filesystem path. You're not passing a path, you're passing the URL.
You could change your template to output the path into the hidden field - e.g.
<input type="hidden" name="book_pdf" value="{{ book.file.path }}">
But it might be better to pass the id
of the Book
, and then from that you can look up all the attributes you need. For example:
Pass the id
of the Book
in the template:
<form method="POST" action ="{% url 'email_book' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="book_id" value="{{ book.id }}">
<button type="submit" class="btn btn-info"><span class="glyphicon glyphicon-envelope"></span> Email</button>
</form>
Modify the view to look up the Book
from the id
:
def send_email(request):
book = Book.objects.get(pk=int(request.POST.get('id')))
book_title = book.title
book_author = book.author
book_pdf = book.file.path # Use the path of the book