In the previous chapter, you used model inheritance and generic relationships to create flexible course content models. You also built a course management system using class-based views, formsets and AJAX ordering for contents. In this chapter, you will:
courses
We will start by creating a course catalog for students to browse existing courses and be able to enroll in them.
For our course catalog we have to build the following functionality:
Edit the views.py
file of the courses application and add the following code:
from django.db.models import Count from .models import Subject class CourseListView(TemplateResponseMixin, View): model = Course template_name = 'courses/course/list.html' def get(self, request, subject=None): subjects = Subject.objects.annotate( total_courses=Count('courses')) courses = Course.objects.annotate( total_modules=Count('modules')) if subject: subject = get_object_or_404(Subject, slug=subject) courses = courses.filter(subject=subject) return self.render_to_response({'subjects': subjects, 'subject': subject, 'courses': courses})
This is the CourseListView
. It inherits from TemplateResponseMixin
and View
. In this view, we perform the following tasks:
annotate()
method with the Count()
aggregation function for doing so.render_to_response()
method provided by TemplateResponseMixin
to render the objects to a template and return an HTTP response.Let's create a detail view for displaying a single course overview. Add the following code to the views.py
file:
from django.views.generic.detail import DetailView class CourseDetailView(DetailView): model = Course template_name = 'courses/course/detail.html'
This view inherits from the generic DetailView
provided by Django. We specify the model
and template_name
attributes. Django's DetailView
expects a primary key (pk) or slug URL parameter to retrieve a single object for the given model. Then it renders the template specified in template_name
, including the object in the context as object.
Edit the main urls.py
file of the educa
project and add the following URL pattern to it:
from courses.views import CourseListView urlpatterns = [ # ... url(r'^$', CourseListView.as_view(), name='course_list'), ]
We add the course_list
URL pattern to the main urls.py
file of the project because we want to display the list of courses in the URL http://127.0.0.1:8000/
and all other URLs for the courses
application have the /course/
prefix.
Edit the urls.py
file of the courses
application and add the following URL patterns:
url(r'^subject/(?P<subject>[w-]+)/$', views.CourseListView.as_view(), name='course_list_subject'), url(r'^(?P<slug>[w-]+)/$', views.CourseDetailView.as_view(), name='course_detail'),
We define the following URL patterns:
course_list_subject
: For displaying all courses for a subjectcourse_detail
: For displaying a single course overviewLet's build templates for the CourseListView
and CourseDetailView
views. Create the following file structure inside the templates/courses/ directory of the courses application:
course/
list.html
detail.html
Edit the courses/course/list.html
template and write the following code:
{% extends "base.html" %} {% block title %} {% if subject %} {{ subject.title }} courses {% else %} All courses {% endif %} {% endblock %} {% block content %} <h1> {% if subject %} {{ subject.title }} courses {% else %} All courses {% endif %} </h1> <div class="contents"> <h3>Subjects</h3> <ul id="modules"> <li {% if not subject %}class="selected"{% endif %}> <a href="{% url "course_list" %}">All</a> </li> {% for s in subjects %} <li {% if subject == s %}class="selected"{% endif %}> <a href="{% url "course_list_subject" s.slug %}"> {{ s.title }} <br><span>{{ s.total_courses }} courses</span> </a> </li> {% endfor %} </ul> </div> <div class="module"> {% for course in courses %} {% with subject=course.subject %} <h3><a href="{% url "course_detail" course.slug %}">{{ course.title }}</a></h3> <p> <a href="{% url "course_list_subject" subject.slug %}">{{ subject }}</a>. {{ course.total_modules }} modules. Instructor: {{ course.owner.get_full_name }} </p> {% endwith %} {% endfor %} </div> {% endblock %}
This is the template for listing available courses. We create an HTML list to display all Subject
objects and build a link to the course_list_subject
URL for each of them. We add a selected
HTML class to highlight the current subject, if any. We iterate over every Course
object, displaying the total number of modules and the instructor name.
Run the development server using the command python
manage.py runserver
and open http://127.0.0.1:8000/
in your browser. You should see a page similar to the following one:
The left sidebar contains all subjects, including the total number of courses for each of them. You can click any subject to filter the courses being displayed.
Edit the courses/course/detail.html
template and add the following code to it:
{% extends "base.html" %} {% block title %} {{ object.title }} {% endblock %} {% block content %} {% with subject=course.subject %} <h1> {{ object.title }} </h1> <div class="module"> <h2>Overview</h2> <p> <a href="{% url "course_list_subject" subject.slug %}">{{ subject.title }}</a>. {{ course.modules.count }} modules. Instructor: {{ course.owner.get_full_name }} </p> {{ object.overview|linebreaks }} </div> {% endwith %} {% endblock %}
In this template, we display the overview and details for a single course. Open http://127.0.0.1:8000/
in your browser and click one of the courses. You should see a page with the following structure:
We have created a public area for displaying courses. Next, we need to allow users to register as students and enroll in courses.