Code Repository
Chapter 4 Rapidly Producing Flexible
HTML with Django Templates
In This Chapter
m Learn the utility of templates
m Create templates in the Django Template Language (DTL) to display the data in our models
m Use template filters and tags to output exactly what you want m Inherit template functionality to adhere to the DRY principle m Integrate Django’s external templates in our Python code
4.1
Introduction
Now that we have structured and created data, we must determine how the user will see these data. In this chapter, we create Django templates, which Django uses to display data and which act as the View in MVC architecture.
We begin the chapter by revisiting the Hello World example originally seen in Chapter 2: Hello World: Building a Basic Webpage in Django. By doing so, we gain perspective on what Django templates must achieve to easily and quickly display data. Once the goals are established, we build our templates. Finally, we see how Django allows us to interact with templates.
This chapter assumes basic understanding of HTML. The book does not provide a primer on the subject, as entire books have been written on the topic and free resources are available online. That said, if you understand the idea behind HTML tags and know that the <a>(anchor) tag creates hyperlinks, you are probably all set.
74 Chapter 4 Rapidly Producing Flexible HTML with Django Templates
4.2
Revisiting Hello World: The Advantages
of Templates
InChapter 2, we built a single webpage that displayed the textHello World!to the user. Building a webpage was a two-step process: we first defined what the webpage would display, and then we defined the URL that identified that webpage. Both of these steps are part of MVC architecture’s Controller, which we examine inChapter 5: Creating Webpages with Controllers in Django.
InChapter 2, Section 2.5, we discussed the fact that a dynamic website needs to use all three MVC components. In particular, we discussed the ability to generate webpages automatically based on data in a database. We can now communicate with a database, and to best illustrate the utility of the MVC View component, we will try again to build a dynamic webpage.
Because we destroyed our helloworld app at the end ofChapter 2, we cannot simply return to our code. Rather than create a new Django app, we will use our organizer app to create a webpage.
As before, creating a webpage is a two-step process. We first define the data that the webpage will display. This is simply a Python function in this case, called a function view
in Django, which returns a certain kind of data. Open/organizer/views.pyand
replace the contents with the code in Example 4.1.
Example 4.1:Project Code
organizer/views.pyinef2c075c3f
1 from django.http.response import HttpResponse 2
3
4 def homepage(request):
5 return HttpResponse('Hello (again) World!')
While the exact significance of therequestparameter or theHttpResponsecall should still seem a bit mysterious, you should be aware that this is Django’s representation of the HTTP request/response loop, as discussed inChapter 1: Starting a New Django Project. What’s more, we know from experience that any text passed to and returned by
HttpResponsewill be printed on the webpage.
The second step is to create a URL that identifies the webpage. As inChapter 2, we use
the project-wide URL configuration in/suorganizer/urls.pyto inform Django of
the existence of our function view, calledhomepage()this time. The pair of values passed tourl()denote the URL and the Python function that builds the website. In this case, the callurl(r'ˆ$', homepage)informs Django that the root webpage will call the homepage()view. Remember to first import the function into the file. The contents of /suorganizer/urls.pyshould now read as in Example 4.2.
4.2 Revisiting Hello World: The Advantages of Templates 75
Example 4.2:Project Code
suorganizer/urls.pyin95b20c151b
16 from django.conf.urls import include, url 17 from django.contrib import admin
18
19 from organizer.views import homepage 20
21 urlpatterns = [
22 url(r'ˆadmin/', include(admin.site.urls)), 23 url(r'ˆ$', homepage),
24 ]
We can immediately see the fruit of our labors. In the terminal, usemanage.pyto run Django’s test server, as in Example 4.3.
Example 4.3:Shell Code
$ ./manage.py runserver
Open a browser and navigate tohttp://127.0.0.1:8000/to see the page. You will
be greeted by the textHello (again) World!in your browser.
Now that we have models, we can do better than a simple hardcoded Hello World. We
can make our page dynamic! Let’s return to/organizer/views.pyand display actual
data on our page (Example 4.4). Specifically, let us list all of theTagobjects that exist in the database.
Example 4.4:Project Code
organizer/views.pyinc4a0b6a5b4
1 from django.http.response import HttpResponse 2
3 from .models import Tag 4
5
6 def homepage(request):
7 tag_list = Tag.objects.all()
8 output = ", ".join([tag.name for tag in tag_list]) 9 return HttpResponse(output)
Info
The codefrom .models import Tagis called an explicit relative import. It’s
equivalent tofrom organizer.models import Tag. However, as we are already
in theorganizerpackage, we do not need to specify it. If we ever choose to change the name of the package by renaming theorganizer/directory, we won’t need to change a relative import, whereas we would with an absolute import.
76 Chapter 4 Rapidly Producing Flexible HTML with Django Templates
We first add a relative import to ourTagmodel. In ourhomepage( ) function, we use the model manager to request allTagobjects. On line 6, we use a list comprehension to create a list of all of the tag names andjointhis list into a string, delineating each item with a comma and a space, which we assign to theoutputvariable. On line 7, we pass our outputvariable, containing our string ofTagnames, to theHttpResponseobject, and return it, effectively passing theTagdata to Django to become a webpage.
Reload the page in your browser (or browse back tohttp://127.0.0.1:8000/) to
see the change take place. You will see the list of the names of theTagobjects we inputted in the databaseChapter 3, which (depending on how closely you’re following along) will output the code in Example 4.5.
Example 4.5:HTML Code
django, education, mobile, video games, web
This is a great start! If we add an item to the database, ourhomepage()view will automatically show it for us. It’s like Django is automatically updating the content for us. As powerful as this is, it is too simple. Browsers expect our website to return a markup language such as HTML or JSON. At the moment, we would have to format this markup directly in our view. For example, a simple page listing the names of our tags might look something like Example 4.6.
Example 4.6:Project Code
organizer/views.pyindd5e4e1a71 6 def homepage(request):
7 tag_list = Tag.objects.all() 8 html_output = "<html>\n" 9 html_output += "<head>\n" 10 html_output += " <title>"
11 html_output += "Don't Do This!</title>\n" 12 html_output += "</head>\n"
13 html_output += "<body>\n" 14 html_output += " <ul>\n" 15 for tag in tag_list:
16 html_output += " <li>" 17 html_output += tag.name.title() 18 html_output += "</li>\n"
19 html_output += " </ul>\n" 20 html_output += "</body>\n" 21 html_output += "</html>\n" 22 return HttpResponse(html_output)
The code in Example 4.6 is cluttered and terrible, and it would be even worse for longer, more complicated HTML. Imagine being able to simply pass data to a pre-prepared document, which would format and present the data as desired. Imagine no more: this decoupling of presentation and logic is the reason that MVC splits View and Controller and why Django implements MVC Views as Django templates.
4.4 Choosing a Format, an Engine, and a Location for Templates 77