- 5.1 Introduction
- 5.2 The Purpose of Views and URL Configurations
- 5.3 Step-by-Step Examination of Django's Use of Views and URL Configurations
- 5.4 Building Tag Detail Webpage
- 5.5 Generating 404 Errors for Invalid Queries
- 5.6 Shortening the Development Process with Django View Shortcuts
- 5.7 URL Configuration Internals: Adhering to App Encapsulation
- 5.8 Implementing the Views and URL Configurations to the Rest of the Site
- 5.9 Class-Based Views
- 5.10 Redirecting the Homepage
- 5.11 Putting It All Together
5.2 The Purpose of Views and URL Configurations
A webpage consists of (1) the data contained in the webpage and (2) the URL (location) of the webpage. Django follows this abstraction by splitting the Controller into two parts. Django views give Django the data of the webpage. The URL associated with each view is listed in the URL configuration.
In the rest of this section, we expand on the nature and purpose of the URL configuration and views. To make the material more tangible, we then step through what happens when Django receives a request, detailing the actions the Controller takes.
5.2.1 Django URL Configurations
As discussed in Chapter 1, Section 1.2, webpages were originally quite basic. The webpage’s data were contained in a flat file (a text file, an HTML file, or a PDF file, for instance). The URL was literally the location of the file on the server. If a user directed his or her browser to http://awebsite.com/project1/important.pdf, the awebsite.com server would go to the project1 directory and fetch the important.pdf file to give to the user’s browser.
Because modern web frameworks generate webpages dynamically, URLs have ceased to be the actual path to the data. A URL is now an abstraction, and it represents the logical path to data. For instance, the path /startup/jambon-software obviously requests information about the JamBon Software startup, whereas the path /blog/2013/1/django-training/ is clearly a request for a blog post about Django classes published in January 2013.
The name Uniform Resource Locator is thus not quite right anymore, as we are not actually requesting the location of the data. Instead, we are simply identifying it. Appropriately, URLs are a direct subset of Uniform Resource Identifiers (URIs), as illustrated in Figure 5.2.
Figure 5.2: URLs are a subset of URIs
While there is some confusion surrounding the difference between URLs and URIs, RFC 39861 is quite clear on the topic (effectively superseding RFC 3305)2:
- A URI can be further classified as a locator, a name, or both. The term “Uniform Resource Locator” (URL) refers to the subset of URIs that, in addition to identifying a resource, provides a means of locating the resource by describing its primary access mechanism (e.g., its network “location”).
Every URL is thus a URI. However, a URL must specify a scheme to access the data, such as http or https, while a URI does not have to. According to this definition, the string /blog/2013/1/django-training/ is a URI, but the string http://site.django-unleashed.com/blog/2013/1/django-training/ is a URL despite the fact that the URL path is not an actual location. For this reason, Django continues to refer to URLs instead of URIs.
Because of the Hollywood principle (inversion of control), the URL configuration acts as a way to direct both users and Django to data. The URL configuration connects URLs to views: Django uses the URL configuration to find views. Django does not know the existence of any view without the URL configuration.
The URL configuration is a list of URL pattens. The URL pattern represents the two parts of a webpage: it maps a URI (the route/location/identifier) to a view (the data). Formally, the URI is a regular expression pattern, whereas the view is a Python callable. A URL configuration can also point to another URL configuration instead of a view, as we discuss in more depth in Section 5.7.1.
In Figure 5.3, each arrow is a URL pattern. Multiple URIs may point to a single view, but a single URI may not be defined more than once. The regular expression pattern in each URL pattern is how Django performs its matching. When Django receives an HTTP request, it tries to match the URL of the request to each and every regular expression pattern in each and every URL pattern. Upon finding a match, Django calls the view that the regular expression pattern maps to. Django uses the first match, meaning that the order of the list of URL patterns matters if there are several potential matches. If Django does not find a match, it returns an HTTP 404 error.
Figure 5.3: URL Configuration
In the example provided by Figure 5.3, if a user requested the URI /startup/, perhaps in a URL such as http://site.django-unleashed.com/startup/, then Django would call the startup_list() function view. Django automatically strips the root slash of the URL path (to Django, /startup/ becomes startup/).
We first coded a URL pattern in Chapter 2 and then again in Chapter 4. This last one, shown in Example 5.1, should still exist in suorganizer/urls.py.
Example 5.1: Project Code
suorganizer/urls.py in 95b20c151b
23 url(r'^$', homepage),
Requesting the root path of our website causes Django to call homepage(), coded in organizer/views.py. We walk through exactly how Django does this shortly.
5.2.2 Django Views
The view is where webpage data is generated. The developer uses the view to interact with the database, load and render the template, and perform any other logic necessary to displaying a webpage.
A Django view is any Python callable (function, class, or object) that meets the following two requirements:
- Accepts an HttpRequest object as argument
- Returns an HttpResponse object
An HttpRequest object contains all of the information about the page requested, any data the user is passing to the website, and any data the browser is sending about the user. The HttpResponse returns an HTTP code (please see Appendix A for information about HTTP codes) as well as any data the developer chooses to return to the user.
Because the nature of a view depends solely on its input and output, any Python callable can be a view. Typically, however, you will be using either functions or Django’s supplied classes to create views. For the moment, we build views using functions and wait until the end of the chapter to look at Django’s class-based views.
Developers often refer to Django views as view functions. This is rather confusing, as views are not limited to being functions (this was not the case historically, which is where the vocabulary originates). In this book, I refer to any callable that builds a webpage as a view. Any view that is built using a function is called a function view, and any view that is an object is called a class-based view (following the documentation’s nomenclature).
We currently have a function view coded in organizer/views.py, shown in Example 5.2.
Example 5.2: Project Code
organizer/views.py in f0d1985791
7 def homepage(request):
8 tag_list = Tag.objects.all()
9 template = loader.get_template(
10 'organizer/tag_list.html')
11 context = Context({'tag_list': tag_list})
12 output = template.render(context)
13 return HttpResponse(output)
We can see how the function in Example 5.2 adheres to view requirements: it accepts an HttpRequest object as the request argument and returns an HttpResponse object with the output of a rendered template. It is also clearly dynamic, generating content based on data in the database.
In this chapter, we focus on using the database to generate dynamic pages. In Chapter 9: Controlling Forms in Views, we generate dynamic pages based on not only the database but also the contents of the HttpRequest object. In Chapter 15: Creating Webpages with Django Flatpages, we also discuss the ability to make static/flat pages with views.