Managing modules and contents

We have built views to create, edit, and delete course modules and contents. Now, we need a view to display all modules for a course and list contents for a specific module.

Edit the views.py file of the courses application and add the following code to it:

class ModuleContentListView(TemplateResponseMixin, View):
template_name = 'courses/manage/module/content_list.html'

def get(self, request, module_id):
module = get_object_or_404(Module,
id=module_id,
course__owner=request.user)

return self.render_to_response({'module': module})

This is ModuleContentListView. This view gets the Module object with the given ID that belongs to the current user and renders a template with the given module.

Edit the urls.py file of the courses application and add the following URL pattern to it:

path('module/<int:module_id>/',
views.ModuleContentListView.as_view(),
name='module_content_list'),

Create a new template inside the templates/courses/manage/module/ directory and name it content_list.html. Add the following code to it:

{% extends "base.html" %}

{% block title %}
Module {{ module.order|add:1 }}: {{ module.title }}
{% endblock %}

{% block content %}
{% with course=module.course %}
<h1>Course "{{ course.title }}"</h1>
<div class="contents">
<h3>Modules</h3>
<ul id="modules">
{% for m in course.modules.all %}
<li data-id="{{ m.id }}" {% if m == module %}
class="selected"{% endif %}>
<a href="{% url "module_content_list" m.id %}">
<span>
Module <span class="order">{{ m.order|add:1 }}</span>
</span>
<br>
{{ m.title }}
</a>
</li>
{% empty %}
<li>No modules yet.</li>
{% endfor %}
</ul>
<p><a href="{% url "course_module_update" course.id %}">
Edit modules</a></p>
</div>
<div class="module">
<h2>Module {{ module.order|add:1 }}: {{ module.title }}</h2>
<h3>Module contents:</h3>

<div id="module-contents">
{% for content in module.contents.all %}
<div data-id="{{ content.id }}">
{% with item=content.item %}
<p>{{ item }}</p>
<a href="#">Edit</a>
<form action="{% url "module_content_delete" content.id %}"
method="post">
<input type="submit" value="Delete">
{% csrf_token %}
</form>
{% endwith %}
</div>
{% empty %}
<p>This module has no contents yet.</p>
{% endfor %}
</div>
<h3>Add new content:</h3>
<ul class="content-types">
<li><a href="{% url "module_content_create" module.id "text" %}">
Text</a></li>
<li><a href="{% url "module_content_create" module.id "image" %}">
Image</a></li>
<li><a href="{% url "module_content_create" module.id "video" %}">
Video</a></li>
<li><a href="{% url "module_content_create" module.id "file" %}">
File</a></li>
</ul>
</div>
{% endwith %}
{% endblock %}

This is the template that displays all modules for a course and the contents of the selected module. We iterate over the course modules to display them in a sidebar. We iterate over the module's contents and access content.item to get the related Text, Video, Image, or File object. We also include links to create new text, video, image, or file contents.

We want to know which type of object each of the item objects is: Text, Video, Image, or File. We need the model name to build the URL to edit the object. Besides this, we could display each item in the template differently, based on the type of content it is. We can get the model for an object from the model's Meta class, by accessing the object's _meta attribute. Nevertheless, Django doesn't allow accessing variables or attributes starting with an underscore in templates to prevent retrieving private attributes or calling private methods. We can solve this by writing a custom template filter.

Create the following file structure inside the courses application directory:

templatetags/
__init__.py
course.py

Edit the course.py module and add the following code to it:

from django import template

register = template.Library()

@register.filter
def model_name(obj):
try:
return obj._meta.model_name
except AttributeError:
return None

This is the model_name template filter. We can apply it in templates as object|model_name to get the model name for an object.

Edit the templates/courses/manage/module/content_list.html template and add the following line below the {% extends %} template tag:

{% load course %}

This will load the course template tags. Then, replace the following lines:

<p>{{ item }}</p>
<a href="#">Edit</a>

Replace them with the following ones:

<p>{{ item }} ({{ item|model_name }})</p>
<a href="{% url "module_content_update" module.id item|model_name item.id %}">Edit</a>

Now, we display the item model in the template and use the model name to build the link to edit the object. Edit the courses/manage/course/list.html template and add a link to the module_content_list URL like this:

<a href="{% url "course_module_update" course.id %}">Edit modules</a>
{% if course.modules.count > 0 %}
<a href="{% url "module_content_list" course.modules.first.id %}">
Manage contents</a>

{% endif %}

The new link allows users to access the contents of the first module of the course, if any.

Open http://127.0.0.1:8000/course/mine/ and click the Manage contents link for a course that contains at least one module. You will see a page like the following one:

When you click on a module in the left sidebar, its contents are displayed in the main area. The template also includes links to add a new text, video, image, or file content for the module being displayed. Add a couple of different types of content to the module and take a look at the result. The contents will appear after Module contents like in the following example:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset