Appointment Letter
In this video, we are going to create a feature to download appointment letter when the user schedules a slot for any vaccination campaign.
Report Lab
In this feature to download a appoinment letter, we will basically return a file response instead of http response from our django view.
But, we have to create a file from the server end based on the user data and it has to be a little bit dynamic.
Now, when I say file, I mean to say a pdf file and we are going to use a third party library named reportlab in order to create a pdf file and write on it.
So, lets download the reportlab first.
pip install reportlab
After that, add this library in the requirements.txt file
pip freeze > requirements.txt
Now, create a utils.py file in the vaccination app. And in this file, we are going create a function that takes some context and return a pdf file containing that context in form of text data.
# Import these when it is required
from reportlab.pdfgen import canvas
from reportlab.platypus import Paragraph
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle
from django.http import FileResponse
import io
def generate_pdf(context):
"""
Returns File Response with given context
"""
# At first, lets create a buffer.
buffer = io.BytesIO()
# This buffer will hold the PDF data before it's sent as a response.
# Now, we will create a Canvas object, using the buffer as its "file."
p = canvas.Canvas(buffer, pagesize=A4)
# Then, we will set the title of this pdf file by using setTitle method of the canvas.
p.setTitle(context["pdf_title"])
# After that, we will write the date that is coming from the context. This date is basically the current date time that we will provide in the context.
p.drawString(40, 800, context["date"])
# this drawString method takes X axis value, Y axis value and the content that we have to write at that location.
# Then, we will draw a line using the line method.
# This line method takes x1, y1, x2, y2 values.
p.line(20, 795, 570, 795)
# After that, we will write a text for the pdf subject in the middle of pdf file.
# We will set a little different font for this text
p.setFont("Helvetica-Bold", 14)
p.drawCentredString(300, 750, context["title"])
# Then, we will write the subtitle of the text.
p.setFont("Helvetica", 12)
p.drawCentredString(300, 700, context["subtitle"])
# Now, finally, we have to write the paragraph.
para_style = ParagraphStyle(
"paraStyle", fontSize=14, leading=20, firstLineIndent=25
)
para = Paragraph(context["content"], para_style)
para.wrapOn(p, 500, 200) # This value basically represents the dimension of paragraph in width and height
para.drawOn(p, 40, 600) # This value represents the location of paragraph where it will be shown.
# At last, close the pdf file and save it.
p.showPage()
p.save()
# Now, we have to set buffer seek to 0.
buffer.seek(0)
# It will help us to reset the buffer to the beginning so that we can read the file from start.
# After that we have to return the FileResponse.
return FileResponse(
buffer, as_attachment=True, filename=context["pdf_title"] + ".pdf"
)
Views
In the views.py file, at first import the generate pdf function.
from vaccination.utils import generate_pdf
Now, lets create a function based view to generate appointment letter.
from django.contrib.auth.decorators import login_required
@login_required
def appointment_letter(request, vaccination_id):
# In this function, at first we will query the vaccination object.
vaccination = Vaccination.objects.get(id=vaccination_id)
# Now, we will create a context and pass that context to generate pdf function.
context = {
"pdf_title": f"{vaccination.patient.get_full_name() } | Vaccination Appointment Letter",
"date": str(timezone.now()),
"title": "Appointment Letter",
"subtitle": "To Whom It May Concern",
"content": f"This is to inform that the {vaccination.campaign.vaccine.name } vaccination of Mr/Ms/Mrs {vaccination.patient.get_full_name() } is scheduled on { vaccination.slot.date }, { vaccination.slot.start_time } at { vaccination.campaign.center.name }.",
}
# At last return the generate_pdf with this context.
return generate_pdf(context)
URLS
Now, lets create a url path to access this view.
path("appointment-letter/<int:vaccination_id>/",views.appointment_letter,name="appointment-letter"),
After that, we have to add this url path in the vaccination-detail.html
<button class="btn btn-sm btn-primary m-1">
<a href="{% url 'vaccination:appointment-letter' object.id %}"><i class="fas fa-download"></i> Appointment Letter</a>
</button>
[Run the development server and see the changes]