- 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.3 Step-by-Step Examination of Django’s Use of Views and URL Configurations
Nothing clarifies programming quite like walking through each step the code takes. Let’s find out what happens when we run our web server and navigate to http://127.0.0.1:8000/.
Before we can go to the webpage, we have to start Django. We do so with Example 5.3.
Example 5.3: Shell Code
$ ./manage.py runserver
Django loads the settings in suorganizer/settings.py, configuring itself. It then loads all of the URL patterns in the URL configuration into memory, which allows Django to match URLs quickly. Once set up, we can type http://127.0.0.1:8000/ into our browser.
Our browser begins by finding the server with the network location 127.0.0.1. That’s easy: that IP address always refers to the machine you’re using. Once it knows that, it looks at the scheme and path of the URL and sends an HTTP request for the path / to itself on port 8000. Django receives this request.
Django first translates the actual HTTP request (raw data) into an HttpRequest object (Python). Having this object in Python makes it easy for us and the framework to manipulate any information the browser is passing our site, as we shall discover in Chapter 9. Django takes the path in the HttpRequest object—currently /—and strips it of the first /. In this case, we are left with the empty string. Our new path is the empty string ".
Django’s next goal is to select a URL pattern. Django has the list of URL patterns in the URL configuration it loaded into memory when it first started up. Each URL pattern consists of at least two things: a regular expression pattern and a view. To select a URL pattern, Django tries to match the requested path—the empty string in this case—to each regular expression pattern of each URL pattern. Given our URL configuration, Django currently has only two options, shown in Example 5.4.
Example 5.4: Project Code
suorganizer/urls.py in 95b20c151b
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 ]
Each call to url() in Example 5.4 is a URL pattern. Django tries to match the empty string, derived from the URL path, to each of the regular expression patterns in the URL patterns above. The empty string very clearly does not match the text admin/. However, Django will select the second URL pattern because the regular expression r'^$' matches the empty string:
- The r informs Python the string is raw, meaning it does not escape any of the characters in the string.
- The ^ matches the beginning of a string.
- The $ matches the end of a string.
With the URL pattern url(r'^$', homepage) selected, Django calls the Python function the URL pattern points to. In this case, the URL pattern points to the homepage() Python function, imported via the call from organizer.views import homepage on line 19. When Django calls the view, it passes the HttpRequest object to the view.
We coded the view such that it loads tag data from the database, loads the tag list template, and renders the template with the Tag object data. We then pass this output to an HttpResponse object and return it to Django. Django translates this object into a real HTTP response and sends it back to our browser. Our browser then displays the webpage to us.
To clarify, the regular expression r'^a$' would match a request to http://127.0.0.1:8000/a. If we were to change the URL pattern from url(r'^$', homepage) to url(r'^home/$', homepage), we would now need to navigate to http://127.0.0.1:8000/home/ to run the homepage() function and display a list of tags.
Inversion of control should be apparent. We are not controlling Django. It translates HTTP requests and responses for us and handles the entire URL matching process. We are simply providing it with the data to use in these matches and telling it what to use to build the webpage (the view). And even then, we are relying heavily on the tools Django provides.
If we were to ask Django for a webpage that did not exist, such as http://127.0.0.1:8000/nonexistent/, Django would try to match nonexistent/ to the regular expression patterns in our URL configuration. When it did not find one, it would error. In production, Django would send back an HTTP 404 response. However, because we have DEBUG=TRUE in our suorganizer/settings.py file, Django instead tries to warn us of the problem and shows us a list of valid URL paths.