The video mentions copying code from the screen or transcript. This is a reference to the old, paid version of the course. I have now collated all the code together in one place in the source, which you can download here.
Django’s Generic Views
At the fundamental level, a view is a piece of code that accepts a request and returns a response. While all the views we have created so far have been function-based views, Django also has class-based views.
When Django was first created, there were only function-based views included with Django. As Django grew it was clear that, while function- based views covered simple cases well, extending and customizing them proved difficult.
Class-based views provide an alternative way for implementing views in Django. Note the use of the word alternative—there is nothing in Django stopping you from using function-based views if you want to.
Django’s class-based views are not designed to replace function-based views, but to provide the advantages of using classes in views. Advantages of class-based views include:
- Ability to implement HTTP methods like GET and POST as class methods, instead of conditional branching in code;
- Extending and adding functionality to basic classes with inheritance;
- Allowing the use of mixins and other object-oriented techniques; and
- Abstracting common idioms and patterns into generic views to make view development easier for common cases.
It’s this last point we will be covering in this module. In keeping with the common theme of aiding rapid development, Django’s developers have created several class-based generic views to aid in implementing common cases.
All of Django’s generic views inherit from the View class. In practice, you won’t often work with the View class directly. More often, you will work with the generic views that inherit from it.
There are two base views that inherit from the View class—TemplateView returns the named template with a context containing whatever was captured from the URL and RedirectView redirects to a given URL.
These base views provide most of the functionality needed to implement class-based views in Django and can either be inherited or used on their own. Let’s look at a quick example. Pause the video and enter the code into your editor or copy from the transcript:
You can see in line 22, the URL testpage creates a TemplateView class instance with the name of the template passed in as a parameter.
To test this navigate to testpage and your Django website will display a blank page template—all without you having to add a single line of view code.
In addition to the base views, Django provides several generic views to make view development easier. Most commonly used are the generic display views—DetailView and ListView—that we will be learning about in this module.
There are also generic editing views and generic date views provided by Django that are not covered in this course. If you do want to dig deeper into all the generic views I’ve provided a link in the resources section of the course.
Viewing Records with ListView
The first generic view we will be implementing on our website is ListView. Using the ListView class is very straight forward—first, let’s create a new class in our views.py. Pause the video and enter the code into your editor or copy from the transcript:
As you can see, the amount of code necessary to implement the generic view is minimal. Apart from line 3, where we import the ListView class, we only need another three lines of code to create the class:
- Line 9 is the class declaration;
- Line 10 tells Django which model to use for the view; and
- Line 11 tells Django what to name the QuerySet that is passed to the template.
Line 11 is not necessary for the class to function, however, without it the QuerySet passed to the template will be named object_list. This is not very user friendly for template designers and can lead to confusion when multiple generic views are used, so best to name it something meaningful.
Next, we need to update the URLs in our quotes app to include the new list view. Pause the video and enter the code into your editor or copy from the transcript (changes in bold):
This should be familiar by now. First, we include the QuoteList view from our views.py file, and then we create a URL configuration in the app that loads the QuoteList generic view.
To test that everything is OK so far, fire up the development server and navigate to http://127.0.0.1:8000/quote/show. If all your code is working correctly, Django should display a TemplateDoesNotExist error.
Take note of the Exception Value: field at the top of the error page. It should be set to quotes/quote_list.html.
I got you to run the server and trigger this error to illustrate a point. To make development faster and easier, Django’s generic views make some assumptions. One of them is that the name of the template for the generic view is going to be the model name with “_list.html” appended. In the case of our quote list view, the template name is assumed to be quote_list.html.
Like most things in Django, this default can be overridden, but without good reason, it’s best to stick with the default.
Now that we’ve tested the view and URLs, let’s go ahead and create and test the template. Create a new file in your templates\quotes folder and name it quote_list.html. Pause the video and enter the code into your editor or copy from the transcript:
There is nothing new here—we are simply creating a template that inherits from quote.html and rendering the name of the person requesting the quote in an HTML list.
Once you have saved the template, navigate to http://127.0.0.1:8000/quote/show and your webpage should look like this.
Now we’ve tested our template and new view to make sure they’re working, In the next lesson we’ll add fields and formatting to the template, so our list of quotes looks like something we can be proud of.
Improving the Quote List Template
Adding fields and formatting to our template to show a more useful quote list is quite easy and uses code and techniques that you have already learned earlier in the course.
As we’re displaying tabular information, we’ll be replacing the simple list we used to test the template with a table and rendering each quote record as a row in the table. While we are at it, I will introduce you to some new Django template tags and filters.
Go ahead now and replace the content block in your template with the following. Pause the video and enter the code into your editor or copy from the transcript:
The HTML in this code should be straight forward—we build a table and render each quote record as a row in the table. The additional style element in line 8 is to stop Chrome overriding our CSS and putting a border around the table cells. This style could also be added to your CSS file, but is small enough to sit neatly in your template without affecting readability.
The important work is done by the for loop between lines 14 and 23. Each field in the quote record is rendered as a table cell with additional formatting added by Django template filters:
In line 19 we apply the date filter to the quote submitted date. The format string “m-d-y” governs how the date is shown, e.g. 15th July, 2018 will display as “07-15-18”.
In line 20 we apply the same format string as submitted date to the quote date. We are also adding the default filter. This filter sets the default for the quotedate field to the word “pending” which will be substituted when the quote date is blank.
And in line 21 we’re using the default filter again; this time, the filter substitutes two dashes (–) when the quote price is zero.
One more thing to note before we move on—in line 15 we are using the cycle template tag for the first time. cycle is a built-in template tag that alternates between all the values listed inside the tag.
Cycle is extremely useful for applying CSS classes to alternate table rows, which is exactly what we are doing in this template code. In our case, the list only has two elements—a blank string (”) and the string “altrow”.
When this template renders, the odd rows will have the class attribute set to “quoterow” and the even rows will have the class attribute set to “quoterow altrow”.
Now that we have finished the template, we need to add some CSS to show our quotes in a nicely formatted table. Pause the video and enter the code into your editor or copy from the transcript:
If you save your files and run the development server, your quote list page should look like this.
The quote list looks great, but as you can see from the video, there is something wrong with the menu—the rest of the site pages are missing. This is because, if you remember from our previous work, the pages list is passed in as a context variable.
Django’s generic views make passing in context information very easy by defining a special method called get_context_data. We can implement this special method in our QuoteList class as follows. Pause the video and enter the code into your editor or copy from the transcript:
By default, get_context_data merges all context data from any parent classes of the current class. To ensure that this behavior is preserved in our own classes, the context is first created by inheriting from the base class in line 15. Then in line 16, we are simply adding the page_list querySet to the context dictionary. That’s all we need to do to add information to the context.
If you refresh your browser, all the menu items should appear.
Now we just need to add the quote list page to the menu by adding a link to the site base template. Pause the video and enter the code into your editor or copy from the transcript
Refresh your browser again and the completed quote list and menu should now display.
That’s it for this lesson – now we’ve created a page that lists all of our quotes, in the next lesson we’re going to write all the code necessary to show an individual quote in the front end.
Viewing a Single Record with DetailView
The next step is to create a view to show an individual quote. We will implement the detail view with the list/detail idiom—when a user clicks a link in the quote list, our Django project will open the corresponding quote record.
There are a few steps to get the new detail view up and running, but they’re all straight forward:
1. Create the new detail view—QuoteView;
2. Add a new URLconf that will display the detail view;
3. Create the detail view template;
4. Add some CSS so the detail view matches our site template; and
5. Modify the quote list template to link to the detail view.
Create the Detail View
Add the following view code to your views.py file. Pause the video and enter the code into your editor or copy from the transcript
As you can see, this code is almost identical to the list view code. At the top of the file, we add DetailView to the module imports. In line 19 we are inheriting from the DetailView class to create our QuoteView. Like the QuoteList view, QuoteView is a simple class with a single get_context_data method in lines 23 to 26 that returns a list of pages for rendering the menu.
Add the URLconf
The next step is to modify the urls.py file in our quotes app. Pause the video and enter the code into your editor or copy from the transcript
There are a couple of changes to the file. In line 4 we are adding the QuoteView view to our imports. In line 8 we are using another capturing group. The capturing group <int:pk> captures any integer at the end of the URL and passes it to the view in the parameter pk.
This is another of those little things Django does to make your life easier. If you pass a parameter named pk to a Django generic detail view, Django will automatically search the database for a record with a primary key equal to the value of pk. For example the URL /show/3 will search for a quote record with a primary key of “3”.
Create the Detail View Template
Next, create a new file named quote_detail.html in your templates directory. Pause the video and enter the code into your editor or copy from the transcript:
This is all standard HTML and Django template tags; there is nothing that should be new to you except in lines 15 and 16.
When you set a choices field for a Django form widget, Django saves the value of the field to the database, not the human-readable name. For example, when the STATUS_CHOICES on the sitestatus field is set to “New Site”, Django saves value “NEW” to the database.
When the value of sitestatus is retrieved from the database, this value would be passed to the template. Obviously, this is not what we want—we want to display the human-readable name.
Django makes this task easy by creating a special get_FIELD_display() method for each model field assigned a choices field. So, in our new view, get_sitestatus_display in line 15 is retrieving the human-readable name from the STATUS_CHOICES list and get_priority_display in line 16 is retrieving the same from the PRIORITY_CHOICES list.
Add CSS to Format Detail View
Next, we want the detail view to match our site template and the list view, so we need to add a couple more CSS classes to our main.css file:
This is just plain CSS. Add the classes anywhere you like in your CSS file although it’s most logical to group them with the quote list classes.
Modify Quote List Template
Finally, we need to make a small change to the quote list template. Pause the video and enter the code into your editor or copy from the transcript
By adding the HTML anchor tag, we turn the quote ID at the beginning of each record in the quote list into a hyperlink that redirects to the detail view.
Fire up the development server and navigate to http://127.0.0.1:8000/ quote/show. If all has gone according to plan, the quote ID’s in the quote list will now be hyperlinks. Click on any one of these links and it should open a detail view of the selected quote.