Book Image

Django: Web Development with Python

By : Aidas Bendoraitis, Samuel Dauzon, Arun Ravindran
Book Image

Django: Web Development with Python

By: Aidas Bendoraitis, Samuel Dauzon, Arun Ravindran

Overview of this book

Data science is hot right now, and the need for multitalented developers is greater than ever before. A basic grounding in building apps with a framework as minimalistic, powerful, and easy-to-learn as Django will be a useful skill to launch your career as an entrepreneur or web developer. Django is a web framework that was designed to strike a balance between rapid web development and high performance. This course will take you on a journey to become an efficient web developer thoroughly understanding the key concepts of Django framework. This learning path is divided into three modules. The course begins with basic concepts of the Django framework. The first module, Django Essentials, is like a practical guide, filled with many real-world examples to build highly effective Django web application. After getting familiar with core concepts of Django, it's time to practice your learning from the first module with the help of over 90 recipes available in this module. In the second module, Web Development with Django Cookbook, you'll learn varying complexities to help you create multilingual, responsive, and scalable websites with Django. By the end of this module, you will have a good understanding of the new features added to Django 1.8 and be an expert at web development processes.The next step is to discover the latest best practices and idioms in this rapidly evolving Django framework. This is what you'll be learning in our third module, Django Design Patterns and Best Practices. This module will teach you common design patterns to develop better Django code. By the end of the module, you will be able to leverage the Django framework to develop a fully functional web application with minimal effort.
Table of Contents (6 chapters)

Chapter 8. Raising Your Productivity with CBV

Class-based views (CBVs) are views generated from models. In simple terms, we can say that these are like ModelForms, in that they simplify the view and work for common cases.

CRUD is the short form we use when referring to the four major operations performed on a database: create, read, update, and delete. CBV is the best way to create pages that perform these actions very quickly.

Creating forms for creating and editing a model or database table data is a very repetitive part of the job of a developer. They may spend a lot of time in doing this properly (validation, prefilled fields, and so on). With CBV, Django allows a developer to perform CRUD operations for a model in less than 10 minutes. They also have an important advantage: if the model evolves and CBVs were well done, changing the model will automatically change the CRUD operations within the website. In this case, adding a line in our models allows us to save tens or hundreds of lines of code.

CBVs still have a drawback. They are not very easy to customize with advanced features or those that are not provided. In many cases, when you try to perform a CRUD operation that has some peculiarities, it is better to create a new view.

You might ask why we did not directly study them—we could have saved a lot of time, especially when adding a developer in the database. This is because these views are generic. They are suitable for simple operations that do not require a lot of changes. When we need a complex form, CBVs will not be useful and will even extend the duration of programming.

We should use CBVs because they allow us to save a lot of time that would normally be used in running CRUD operations on models.

In this chapter, we will make the most of our TasksManager application. Indeed, we will enjoy the time savings offered by the CBVs to move quickly with this project. If you do not understand the functioning of CBVs immediately, it doesn't matter. What we have seen so far in previous chapters already allows us to make websites.

In this chapter, we will try to improve our productivity by covering the following topics:

  • We will use the CreateView CBV to quickly build the page to add projects
  • We will see later how to display a list of objects and use the paging system
  • We will then use the DetailView CBV to display the project information
  • We will then learn how to change the data in a record with the UpdateView CBV
  • We will learn how to change the form generated by a CBV
  • We will then create a page to delete a record
  • Then, we will eventually create a child class of UpdateView to make using it more flexible in our application

The CreateView CBV

The CreateView CBV allows you to create a view that will automatically generate a form based on a model and automatically save the data in this form. It can be compared to ModelForm, except that we do not need to create a view. Indeed, all the code for this will be placed in the urls.py file except in special cases.

An example of minimalist usage

We will create a CBV that will allow us to create a project. This example aims to show that you can save even more time than with Django forms. We will be able to use the template used for the creation of forms in the previous chapter's project. Now, we will change our create_project URL as follows:

url (r'^create_project$', CreateView.as_view(model=Project, template_name="en/public/create_project.html", success_url = 'index'), name="create_project"),

We will add the following lines at the beginning of the urls.py file:

from django.views.generic import CreateView
from TasksManager.models import Project

In our new URL, we used the following new features:

  • CreateView.as_view: We call the method as_view of the CBV CreateView. This method returns a complete view to the user. Moreover, we return multiple parameters in this method.
  • model: This defines the model that will apply the CBV.
  • template_name: This defines the template that will display the form. As the CBV uses ModelForm, we do not need to change our create_project.html template.
  • success_url: This defines the URL to which we will be redirected once the change has been taken into account. This parameter is not very DRY because we cannot use the name property of the URL. When we extend our CBV, we will see how to use the name of the URL to be redirected.

That's all! The three lines that we have added to the urls.py file will perform the following actions:

  • Generate the form
  • Generate the view that sends the form to the template with or without errors
  • Data is sent by the user

We just used one of the most interesting features of Django. Indeed, with only three lines, we have been doing what would have taken more than a hundred lines without any framework. We will also write the CBV that will allow us to add a task. Have a look at the following code:

from TasksManager.models import Project, Task
url (r'^create_task$', CreateView.as_view(model=Task, template_name="en/public/create_task.html", success_url = 'index'), name="create_task"),

We then need to duplicate the create_project.html template and change the link in the base.html template. Our new view is functional, and we used the same template for project creation. This is a common method because it saves a lot of time for the developer, but there is a more rigorous way to proceed.

To test the code, we can add the following link to the end of the article_content block of the index.html template:

<a href="{% url "create_task" %}">Create task</a>

Working with ListView

ListView is a CBV that displays a list of records for a given model. The view is generated to send a template object from which we view the list.

An example of minimalist usage

We will look at an example displaying the list of projects and create a link to the details of a project. To do this, we must add the following lines in the urls.py file:

from TasksManager.models import Project
from django.views.generic.list import ListView

Add the following URLs to the file:

url (r'^project_list$', ListView.as_view(model=Project, template_name="en/public/project_list.html"), name="project_list"),

We will create the template that will be used to display the results in a tabular form by adding the following lines in the article_content block after extending the base.html template:

<table>
<tr>
  <th>Title</th>
  <th>Description</th>
  <th>Client name</th>
</tr>
{% for project in object_list %}
  <tr>
    <td>{{ project.title }}</td>
    <td>{{ project.description }}</td>
    <td>{{ project.client_name }}</td>
  </tr>
{% endfor %}
</table>

We created the same list as in Chapter 6, Getting a Model's Data with Querysets, about the queryset. The advantage is that we used a lot less lines and we did not use any view to create it. In the next part, we will implement paging by extending this CBV.

Extending ListView

It is possible to extend the possibilities of the ListView CBV and customize them. This allows us to adapt the CBV to the needs of the websites. We can define the same elements as in the parameters in the as_view method, but it will be more readable and we can also override the methods. Depending on the type of CBV, spreading them allows you to:

  • Change the model and template as we did in the URL
  • Change the queryset to be executed
  • Change the name of the object sent to the template
  • Specify the URL that will redirect the user

We will expand our first CBV by modifying the list of projects that we have done. We will make two changes to this list by sorting by title and adding pagination. We will create the ListView.py file in the views/cbv module. This file will contain our customized listView. It is also possible to choose the architecture. For example, we could create a file named project.py to store all the CBVs concerning the projects. This file will contain the following code:

from django.views.generic.list import ListView 
# In this line, we import the ListView class
from TasksManager.models import Project

class Project_list(ListView): 
# In this line, we create a class that extends the ListView class.
  model=Project
  template_name = 'en/public/project_list.html' 
# In this line, we define the template_name the same manner as in the urls.py file.
  paginate_by = 5 
In this line, we define the number of visible projects on a single page.
  def get_queryset(self): 
In this line, we override the get_queryset() method to return our queryset.
    queryset=Project.objects.all().order_by("title")
    return queryset

We could also have set the queryset in the following manner:

queryset=Project.objects.all().order_by("title")

However, it may be useful to create a class that can be adapted to many cases. For the Project_list class to be interpreted in the URLs, we need to change our imports by adding the following line:

from TasksManager.views.cbv.ListView import Project_list

You must then change the URL. In this urls.py file, we will use the Project_list object without any parameters, as shown in the following code snippet; they are all defined in the ListView.py file:

url (r'^project_list$', Project_list.as_view(), name="project_list"),

From now on, the new page is functional. If we test it, we will realize that only the first five projects are displayed. Indeed, in the Project_list object, we defined a pagination of five items per page. To navigate through the list, we need to add the following code in the template before the end of the article_content block:

{% if is_paginated %}
  <div class="pagination">
    <span>
    {% if page_obj.has_previous %}
      <a href="{% url "project_list" %}?page={{ page_obj.previous_page_number }}">Previous</a>
    {% endif %}
    <span style="margin-left:15px;margin-right:15px;">
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
    </span>
    {% if page_obj.has_next %}
      <a href="{% url "project_list" %}?page={{ page_obj.next_page_number }}">Next</a>
    {% endif %}
    </span>
  </div>
{% endif %}

This part of the template allows us to create links to the preceding and following pages at the bottom of the page. With this example, we created a sorted list of projects with pagination very quickly. The extending of CBVs can be very convenient and allows us to adapt to more complex uses. After this complete example, we will create a CBV to display a list of developers. This list will be useful later in the book. We must add the following URL after importing the ListView class:

url (r'^developer_list$', ListView.as_view(model=Developer, template_name="en/public/developer_list.html"), name="developer_list"),

We then use an inherited template of base.html and put the following code in the article_content block:

<table>
  <tr>
    <td>Name</td>
    <td>Login</td>
    <td>Supervisor</td>
  </tr>
  {% for dev in object_list %}
    <tr>
      <td><a href="">{{ dev.name }}</a></td>
      <td>{{ dev.login }}</td>
      <td>{{ dev.supervisor }}</td>
    </tr>
  {% endfor %}
</table>

We will notice that the name of the developer is an empty link. You should refill it when we create the page that displays the details of the developer. This is what we will do in the next section with DetailView.

An example of minimalist usage

We will look at an example displaying the list of projects and create a link to the details of a project. To do this, we must add the following lines in the urls.py file:

from TasksManager.models import Project
from django.views.generic.list import ListView

Add the following URLs to the file:

url (r'^project_list$', ListView.as_view(model=Project, template_name="en/public/project_list.html"), name="project_list"),

We will create the template that will be used to display the results in a tabular form by adding the following lines in the article_content block after extending the base.html template:

<table>
<tr>
  <th>Title</th>
  <th>Description</th>
  <th>Client name</th>
</tr>
{% for project in object_list %}
  <tr>
    <td>{{ project.title }}</td>
    <td>{{ project.description }}</td>
    <td>{{ project.client_name }}</td>
  </tr>
{% endfor %}
</table>

We created the same list as in Chapter 6, Getting a Model's Data with Querysets, about the queryset. The advantage is that we used a lot less lines and we did not use any view to create it. In the next part, we will implement paging by extending this CBV.

Extending ListView

It is possible to extend the possibilities of the ListView CBV and customize them. This allows us to adapt the CBV to the needs of the websites. We can define the same elements as in the parameters in the as_view method, but it will be more readable and we can also override the methods. Depending on the type of CBV, spreading them allows you to:

  • Change the model and template as we did in the URL
  • Change the queryset to be executed
  • Change the name of the object sent to the template
  • Specify the URL that will redirect the user

We will expand our first CBV by modifying the list of projects that we have done. We will make two changes to this list by sorting by title and adding pagination. We will create the ListView.py file in the views/cbv module. This file will contain our customized listView. It is also possible to choose the architecture. For example, we could create a file named project.py to store all the CBVs concerning the projects. This file will contain the following code:

from django.views.generic.list import ListView 
# In this line, we import the ListView class
from TasksManager.models import Project

class Project_list(ListView): 
# In this line, we create a class that extends the ListView class.
  model=Project
  template_name = 'en/public/project_list.html' 
# In this line, we define the template_name the same manner as in the urls.py file.
  paginate_by = 5 
In this line, we define the number of visible projects on a single page.
  def get_queryset(self): 
In this line, we override the get_queryset() method to return our queryset.
    queryset=Project.objects.all().order_by("title")
    return queryset

We could also have set the queryset in the following manner:

queryset=Project.objects.all().order_by("title")

However, it may be useful to create a class that can be adapted to many cases. For the Project_list class to be interpreted in the URLs, we need to change our imports by adding the following line:

from TasksManager.views.cbv.ListView import Project_list

You must then change the URL. In this urls.py file, we will use the Project_list object without any parameters, as shown in the following code snippet; they are all defined in the ListView.py file:

url (r'^project_list$', Project_list.as_view(), name="project_list"),

From now on, the new page is functional. If we test it, we will realize that only the first five projects are displayed. Indeed, in the Project_list object, we defined a pagination of five items per page. To navigate through the list, we need to add the following code in the template before the end of the article_content block:

{% if is_paginated %}
  <div class="pagination">
    <span>
    {% if page_obj.has_previous %}
      <a href="{% url "project_list" %}?page={{ page_obj.previous_page_number }}">Previous</a>
    {% endif %}
    <span style="margin-left:15px;margin-right:15px;">
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
    </span>
    {% if page_obj.has_next %}
      <a href="{% url "project_list" %}?page={{ page_obj.next_page_number }}">Next</a>
    {% endif %}
    </span>
  </div>
{% endif %}

This part of the template allows us to create links to the preceding and following pages at the bottom of the page. With this example, we created a sorted list of projects with pagination very quickly. The extending of CBVs can be very convenient and allows us to adapt to more complex uses. After this complete example, we will create a CBV to display a list of developers. This list will be useful later in the book. We must add the following URL after importing the ListView class:

url (r'^developer_list$', ListView.as_view(model=Developer, template_name="en/public/developer_list.html"), name="developer_list"),

We then use an inherited template of base.html and put the following code in the article_content block:

<table>
  <tr>
    <td>Name</td>
    <td>Login</td>
    <td>Supervisor</td>
  </tr>
  {% for dev in object_list %}
    <tr>
      <td><a href="">{{ dev.name }}</a></td>
      <td>{{ dev.login }}</td>
      <td>{{ dev.supervisor }}</td>
    </tr>
  {% endfor %}
</table>

We will notice that the name of the developer is an empty link. You should refill it when we create the page that displays the details of the developer. This is what we will do in the next section with DetailView.

Extending ListView

It is possible to extend the possibilities of the ListView CBV and customize them. This allows us to adapt the CBV to the needs of the websites. We can define the same elements as in the parameters in the as_view method, but it will be more readable and we can also override the methods. Depending on the type of CBV, spreading them allows you to:

  • Change the model and template as we did in the URL
  • Change the queryset to be executed
  • Change the name of the object sent to the template
  • Specify the URL that will redirect the user

We will expand our first CBV by modifying the list of projects that we have done. We will make two changes to this list by sorting by title and adding pagination. We will create the ListView.py file in the views/cbv module. This file will contain our customized listView. It is also possible to choose the architecture. For example, we could create a file named project.py to store all the CBVs concerning the projects. This file will contain the following code:

from django.views.generic.list import ListView 
# In this line, we import the ListView class
from TasksManager.models import Project

class Project_list(ListView): 
# In this line, we create a class that extends the ListView class.
  model=Project
  template_name = 'en/public/project_list.html' 
# In this line, we define the template_name the same manner as in the urls.py file.
  paginate_by = 5 
In this line, we define the number of visible projects on a single page.
  def get_queryset(self): 
In this line, we override the get_queryset() method to return our queryset.
    queryset=Project.objects.all().order_by("title")
    return queryset

We could also have set the queryset in the following manner:

queryset=Project.objects.all().order_by("title")

However, it may be useful to create a class that can be adapted to many cases. For the Project_list class to be interpreted in the URLs, we need to change our imports by adding the following line:

from TasksManager.views.cbv.ListView import Project_list

You must then change the URL. In this urls.py file, we will use the Project_list object without any parameters, as shown in the following code snippet; they are all defined in the ListView.py file:

url (r'^project_list$', Project_list.as_view(), name="project_list"),

From now on, the new page is functional. If we test it, we will realize that only the first five projects are displayed. Indeed, in the Project_list object, we defined a pagination of five items per page. To navigate through the list, we need to add the following code in the template before the end of the article_content block:

{% if is_paginated %}
  <div class="pagination">
    <span>
    {% if page_obj.has_previous %}
      <a href="{% url "project_list" %}?page={{ page_obj.previous_page_number }}">Previous</a>
    {% endif %}
    <span style="margin-left:15px;margin-right:15px;">
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
    </span>
    {% if page_obj.has_next %}
      <a href="{% url "project_list" %}?page={{ page_obj.next_page_number }}">Next</a>
    {% endif %}
    </span>
  </div>
{% endif %}

This part of the template allows us to create links to the preceding and following pages at the bottom of the page. With this example, we created a sorted list of projects with pagination very quickly. The extending of CBVs can be very convenient and allows us to adapt to more complex uses. After this complete example, we will create a CBV to display a list of developers. This list will be useful later in the book. We must add the following URL after importing the ListView class:

url (r'^developer_list$', ListView.as_view(model=Developer, template_name="en/public/developer_list.html"), name="developer_list"),

We then use an inherited template of base.html and put the following code in the article_content block:

<table>
  <tr>
    <td>Name</td>
    <td>Login</td>
    <td>Supervisor</td>
  </tr>
  {% for dev in object_list %}
    <tr>
      <td><a href="">{{ dev.name }}</a></td>
      <td>{{ dev.login }}</td>
      <td>{{ dev.supervisor }}</td>
    </tr>
  {% endfor %}
</table>

We will notice that the name of the developer is an empty link. You should refill it when we create the page that displays the details of the developer. This is what we will do in the next section with DetailView.

The DetailView CBV

The DetailView CBV allows us to display information from a registration model. This is the first CBV we will study that has URL parameters. In order to view the details of a record, it will send its ID to the CBV. We will study some examples.

An example of minimalist usage

First, we will create a page that will display the details of a task. For this, we will create the URL by adding these lines in the urls.py file:

from django.views.generic import DetailView
from TasksManager.models import Task
url (r'^task_detail_(?P<pk>\d+)$', DetailView.as_view(model=Task, template_name="en/public/task_detail.html"), name="task_detail"),

In this URL, we added the parameter-sending aspect. We have already discussed this type of URL in an earlier chapter when we covered querysets.

Note

This time, we really need to name the parameter pk; otherwise, the CBV will not work. pk means primary key, and it will contain the ID of the record you want to view.

Regarding the template, we will create the en/public/task_detail.html template and place the following code in the article_content block:

<h4>
  {{ object.title }}
</h4>
<table>
  <tr>
    <td>Project : {{ object.project }}</td>
    <td>Developer : {{ object.app_user }}</td>
  </tr>
  <tr>
    <td>Importence : {{ object.importence }}</td>
    <td>Time elapsed : {{ object.time_elapsed }}</td>
  </tr>
</table>
<p>
  {{ object.description }}
</p>

In this code, we refer to the foreign keys Developer and Project. Using this syntax in the template, we call the __ unicode__() of the model in question. This enables the title of the project to be displayed. To test this piece of code, we need to create a link to a parameterized URL. Add this line to your index.html file:

<a href="{% url "task_detail" "1" %}">Detail first view</a><br />

This line will allow us to see the details of the first task. You can try to create a list of tasks and a link to DetailView in each row of the table. This is what we will do.

Extending DetailView

We will now create the page that displays the details of a developer and his/her tasks. To get it done, we'll override the DetailView class by creating a DetailView.py file in the views/cbv module and add the following lines of code:

from django.views.generic import DetailView
from TasksManager.models import Developer, Task

class Developer_detail(DetailView): 
  model=Developer
  template_name = 'en/public/developer_detail.html'
  def get_context_data(self, **kwargs):
    # This overrides the get_context_data() method.
    context = super(Developer_detail, self).get_context_data(**kwargs) 
    # This allows calling the method of the super class. Without this line we would not have the basic context.
    tasks_dev = Task.objects.filter(developer = self.object) 
    # This allows us to retrieve the list of developer tasks. We use self.object, which is a Developer type object already defined by the DetailView class.
    context['tasks_dev'] = tasks_dev 
    # In this line, we add the task list to the context.
    return context

We need to add the following lines of code to the urls.py file:

from TasksManager.views.cbv.DetailView import Developer_detail 
url (r'^developer_detail_(?P<pk>\d+)$', Developer_detail.as_view(), name="developer_detail"),

To see the main data and develop tasks, we create the developer_detail.html template. After extending from base.html, we must enter the following lines in the article_content block:

<h4>
  {{ object.name }}
</h4>
<span>Login : {{ object.login }}</span><br />
<span>Email : {{ object.email }}</span>
<h3>Tasks</h3>
<table>
  {% for task in tasks_dev %}
  <tr>
    <td>{{ task.title }}</td>
    <td>{{ task.importence }}</td>
    <td>{{ task.project }}</td>
  </tr>
  {% endfor %}
</table>

This example has allowed us to see how to send data to the template while using CBVs.

An example of minimalist usage

First, we will create a page that will display the details of a task. For this, we will create the URL by adding these lines in the urls.py file:

from django.views.generic import DetailView
from TasksManager.models import Task
url (r'^task_detail_(?P<pk>\d+)$', DetailView.as_view(model=Task, template_name="en/public/task_detail.html"), name="task_detail"),

In this URL, we added the parameter-sending aspect. We have already discussed this type of URL in an earlier chapter when we covered querysets.

Note

This time, we really need to name the parameter pk; otherwise, the CBV will not work. pk means primary key, and it will contain the ID of the record you want to view.

Regarding the template, we will create the en/public/task_detail.html template and place the following code in the article_content block:

<h4>
  {{ object.title }}
</h4>
<table>
  <tr>
    <td>Project : {{ object.project }}</td>
    <td>Developer : {{ object.app_user }}</td>
  </tr>
  <tr>
    <td>Importence : {{ object.importence }}</td>
    <td>Time elapsed : {{ object.time_elapsed }}</td>
  </tr>
</table>
<p>
  {{ object.description }}
</p>

In this code, we refer to the foreign keys Developer and Project. Using this syntax in the template, we call the __ unicode__() of the model in question. This enables the title of the project to be displayed. To test this piece of code, we need to create a link to a parameterized URL. Add this line to your index.html file:

<a href="{% url "task_detail" "1" %}">Detail first view</a><br />

This line will allow us to see the details of the first task. You can try to create a list of tasks and a link to DetailView in each row of the table. This is what we will do.

Extending DetailView

We will now create the page that displays the details of a developer and his/her tasks. To get it done, we'll override the DetailView class by creating a DetailView.py file in the views/cbv module and add the following lines of code:

from django.views.generic import DetailView
from TasksManager.models import Developer, Task

class Developer_detail(DetailView): 
  model=Developer
  template_name = 'en/public/developer_detail.html'
  def get_context_data(self, **kwargs):
    # This overrides the get_context_data() method.
    context = super(Developer_detail, self).get_context_data(**kwargs) 
    # This allows calling the method of the super class. Without this line we would not have the basic context.
    tasks_dev = Task.objects.filter(developer = self.object) 
    # This allows us to retrieve the list of developer tasks. We use self.object, which is a Developer type object already defined by the DetailView class.
    context['tasks_dev'] = tasks_dev 
    # In this line, we add the task list to the context.
    return context

We need to add the following lines of code to the urls.py file:

from TasksManager.views.cbv.DetailView import Developer_detail 
url (r'^developer_detail_(?P<pk>\d+)$', Developer_detail.as_view(), name="developer_detail"),

To see the main data and develop tasks, we create the developer_detail.html template. After extending from base.html, we must enter the following lines in the article_content block:

<h4>
  {{ object.name }}
</h4>
<span>Login : {{ object.login }}</span><br />
<span>Email : {{ object.email }}</span>
<h3>Tasks</h3>
<table>
  {% for task in tasks_dev %}
  <tr>
    <td>{{ task.title }}</td>
    <td>{{ task.importence }}</td>
    <td>{{ task.project }}</td>
  </tr>
  {% endfor %}
</table>

This example has allowed us to see how to send data to the template while using CBVs.

Extending DetailView

We will now create the page that displays the details of a developer and his/her tasks. To get it done, we'll override the DetailView class by creating a DetailView.py file in the views/cbv module and add the following lines of code:

from django.views.generic import DetailView
from TasksManager.models import Developer, Task

class Developer_detail(DetailView): 
  model=Developer
  template_name = 'en/public/developer_detail.html'
  def get_context_data(self, **kwargs):
    # This overrides the get_context_data() method.
    context = super(Developer_detail, self).get_context_data(**kwargs) 
    # This allows calling the method of the super class. Without this line we would not have the basic context.
    tasks_dev = Task.objects.filter(developer = self.object) 
    # This allows us to retrieve the list of developer tasks. We use self.object, which is a Developer type object already defined by the DetailView class.
    context['tasks_dev'] = tasks_dev 
    # In this line, we add the task list to the context.
    return context

We need to add the following lines of code to the urls.py file:

from TasksManager.views.cbv.DetailView import Developer_detail 
url (r'^developer_detail_(?P<pk>\d+)$', Developer_detail.as_view(), name="developer_detail"),

To see the main data and develop tasks, we create the developer_detail.html template. After extending from base.html, we must enter the following lines in the article_content block:

<h4>
  {{ object.name }}
</h4>
<span>Login : {{ object.login }}</span><br />
<span>Email : {{ object.email }}</span>
<h3>Tasks</h3>
<table>
  {% for task in tasks_dev %}
  <tr>
    <td>{{ task.title }}</td>
    <td>{{ task.importence }}</td>
    <td>{{ task.project }}</td>
  </tr>
  {% endfor %}
</table>

This example has allowed us to see how to send data to the template while using CBVs.

The UpdateView CBV

UpdateView is the CBV that will create and edit forms easily. This is the CBV that saves more time compared to developing without the MVC pattern. As with DetailView, we will have to send the logins of the record to the URL. To address UpdateView, we will discuss two examples:

  • Changing a task for the supervisor to be able to edit a task
  • Reducing the time spent to perform a task to develop

An example of minimalist usage

This example will show how to create the page that will allow the supervisor to modify a task. As with other CBVs, we will add the following lines in the urls.py file:

from django.views.generic import UpdateView
url (r'^update_task_(?P<pk>\d+)$', UpdateView.as_view(model=Task, template_name="en/public/update_task.html", success_url="index"), name="update_task"),

We will write a very similar template to the one we used for CreateView. The only difference (except the button text) will be the action field of the form, which we will define as empty. We will see how to fill the field at the end of this chapter. For now, we will make use of the fact that browsers submit the form to the current page when the field is empty. It remains visible so users can write the content to include in our article_content block. Have a look at the following code:

<form method="post" action="">
  {% csrf_token %} 
  <table>
    {{ form.as_table }} 
  </table>
  <p><input type="submit" value="Update" /></p>
</form>

This example is really simple. It could have been more DRY if we entered the name of the URL in the success_url property.

Extending the UpdateView CBV

In our application, the life cycle of a task is the following:

  • The supervisor creates the task without any duration
  • When the developer has completed the task, they save their working time

We will work on the latter point, where the developer can only change the duration of the task. In this example, we will override the UpdateView class. To do this, we will create an UpdateView.py file in the views/cbv module. We need to add the following content:

from django.views.generic import UpdateView
from TasksManager.models import Task
from django.forms import ModelForm
from django.core.urlresolvers import reverse

class Form_task_time(ModelForm): 
# In this line, we create a form that extends the ModelForm. The UpdateView and CreateView CBV are based on a ModelForm system.
  class Meta:
    model = Task
    fields = ['time_elapsed'] 
    # This is used to define the fields that appear in the form. Here there will be only one field.

class Task_update_time(UpdateView):
  model = Task
  template_name = 'en/public/update_task_developer.html'
form_class = Form_task_time 
# In this line, we impose your CBV to use the ModelForm we created. When you do not define this line, Django automatically generates a ModelForm.
  success_url = 'public_empty' 
  # This line sets the name of the URL that will be seen once the change has been completed.
  def get_success_url(self): 
  # In this line, when you put the name of a URL in the success_url property, we have to override this method. The reverse() method returns the URL corresponding to a URL name.
    return reverse(self.success_url)

We may use this CBV with the following URL:

from TasksManager.views.cbv.UpdateView import Task_update_time
url (r'^update_task_time_(?P<pk>\d+)$', Task_update_time.as_view(), name = "update_task_time"),

For the update_task_developer.html template, we just need to duplicate the update_task.html template and modify its titles.

An example of minimalist usage

This example will show how to create the page that will allow the supervisor to modify a task. As with other CBVs, we will add the following lines in the urls.py file:

from django.views.generic import UpdateView
url (r'^update_task_(?P<pk>\d+)$', UpdateView.as_view(model=Task, template_name="en/public/update_task.html", success_url="index"), name="update_task"),

We will write a very similar template to the one we used for CreateView. The only difference (except the button text) will be the action field of the form, which we will define as empty. We will see how to fill the field at the end of this chapter. For now, we will make use of the fact that browsers submit the form to the current page when the field is empty. It remains visible so users can write the content to include in our article_content block. Have a look at the following code:

<form method="post" action="">
  {% csrf_token %} 
  <table>
    {{ form.as_table }} 
  </table>
  <p><input type="submit" value="Update" /></p>
</form>

This example is really simple. It could have been more DRY if we entered the name of the URL in the success_url property.

Extending the UpdateView CBV

In our application, the life cycle of a task is the following:

  • The supervisor creates the task without any duration
  • When the developer has completed the task, they save their working time

We will work on the latter point, where the developer can only change the duration of the task. In this example, we will override the UpdateView class. To do this, we will create an UpdateView.py file in the views/cbv module. We need to add the following content:

from django.views.generic import UpdateView
from TasksManager.models import Task
from django.forms import ModelForm
from django.core.urlresolvers import reverse

class Form_task_time(ModelForm): 
# In this line, we create a form that extends the ModelForm. The UpdateView and CreateView CBV are based on a ModelForm system.
  class Meta:
    model = Task
    fields = ['time_elapsed'] 
    # This is used to define the fields that appear in the form. Here there will be only one field.

class Task_update_time(UpdateView):
  model = Task
  template_name = 'en/public/update_task_developer.html'
form_class = Form_task_time 
# In this line, we impose your CBV to use the ModelForm we created. When you do not define this line, Django automatically generates a ModelForm.
  success_url = 'public_empty' 
  # This line sets the name of the URL that will be seen once the change has been completed.
  def get_success_url(self): 
  # In this line, when you put the name of a URL in the success_url property, we have to override this method. The reverse() method returns the URL corresponding to a URL name.
    return reverse(self.success_url)

We may use this CBV with the following URL:

from TasksManager.views.cbv.UpdateView import Task_update_time
url (r'^update_task_time_(?P<pk>\d+)$', Task_update_time.as_view(), name = "update_task_time"),

For the update_task_developer.html template, we just need to duplicate the update_task.html template and modify its titles.

Extending the UpdateView CBV

In our application, the life cycle of a task is the following:

  • The supervisor creates the task without any duration
  • When the developer has completed the task, they save their working time

We will work on the latter point, where the developer can only change the duration of the task. In this example, we will override the UpdateView class. To do this, we will create an UpdateView.py file in the views/cbv module. We need to add the following content:

from django.views.generic import UpdateView
from TasksManager.models import Task
from django.forms import ModelForm
from django.core.urlresolvers import reverse

class Form_task_time(ModelForm): 
# In this line, we create a form that extends the ModelForm. The UpdateView and CreateView CBV are based on a ModelForm system.
  class Meta:
    model = Task
    fields = ['time_elapsed'] 
    # This is used to define the fields that appear in the form. Here there will be only one field.

class Task_update_time(UpdateView):
  model = Task
  template_name = 'en/public/update_task_developer.html'
form_class = Form_task_time 
# In this line, we impose your CBV to use the ModelForm we created. When you do not define this line, Django automatically generates a ModelForm.
  success_url = 'public_empty' 
  # This line sets the name of the URL that will be seen once the change has been completed.
  def get_success_url(self): 
  # In this line, when you put the name of a URL in the success_url property, we have to override this method. The reverse() method returns the URL corresponding to a URL name.
    return reverse(self.success_url)

We may use this CBV with the following URL:

from TasksManager.views.cbv.UpdateView import Task_update_time
url (r'^update_task_time_(?P<pk>\d+)$', Task_update_time.as_view(), name = "update_task_time"),

For the update_task_developer.html template, we just need to duplicate the update_task.html template and modify its titles.

The DeleteView CBV

The DeleteView CBV can easily delete a record. It does not save a lot of time compared to a normal view, but it cannot be burdened with unnecessary views. We will show an example of task deletion. For this, we need to create the DeleteView.py file in the views/cbv module. Indeed, we need to override it because we will enter the name of the URL that we want to redirect. We can only put the URL in success_url, but we want our URL to be as DRY as possible. We will add the following code in the DeleteView.py file:

from django.core.urlresolvers import reverse
from django.views.generic import DeleteView
from TasksManager.models import Task

class Task_delete(DeleteView):
  model = Task
  template_name = 'en/public/confirm_delete_task.html'
  success_url = 'public_empty'
  def get_success_url(self):
    return reverse(self.success_url)

In the preceding code, the template will be used to confirm the deletion. Indeed, the DeleteView CBV will ask for user confirmation before deleting. We will add the following lines in the urls.py file to add the URL of the deletion:

from TasksManager.views.cbv.DeleteView import Task_delete
url(r'task_delete_(?P<pk>\d+)$', Task_delete.as_view(), name="task_delete"),

To finish our task suppression page, we will create the confirm_delete_task.html template by extending base.html with the following content in the article_content block:

<h3>Do you want to delete this object?</h3>
<form method="post" action="">
  {% csrf_token %} 
  <table>
    {{ form.as_table }} 
  </table>
  <p><input type="submit" value="Delete" /></p>
</form>

Going further by extending the CBV

CBVs allow us to save a lot of time during page creation by performing CRUD actions with our models. By extending them, it is possible to adapt them to our use and save even more time.

Using a custom class CBV update

To finish our suppression page, in this chapter, we have seen that CBVs allow us to not be burdened with unnecessary views. However, we have created many templates that are similar, and we override the CBV only to use the DRY URLs. We will fix these small imperfections. In this section, we will create a CBV and generic template that will allow us to:

  • Use this CBV directly in the urls.py file
  • Enter the name property URLs for redirection
  • Benefit from a template for all uses of these CBVs

Before writing our CBV, we will modify the models.py file, giving each model a verbose_name property and verbose_name_plural. For this, we will use the Meta class. For example, the Task model will become the following:

class Task(models.Model):
  # fields
  def __str__(self):
    return self.title
  class Meta:
    verbose_name = "task"
    verbose_name_plural = "tasks"

We will create an UpdateViewCustom.py file in the views/cbv folder and add the following code:

from django.views.generic import UpdateView
from django.core.urlresolvers import reverse

class UpdateViewCustom(UpdateView):
  template_name = 'en/cbv/UpdateViewCustom.html' 
  # In this line, we define the template that will be used for all the CBVs that extend the UpdateViewCustom class. This template_name field can still be changed if we need it.
  url_name="" 
  # This line is used to create the url_name property. This property will help us to define the name of the current URL. In this way, we can add the link in the action attribute of the form.
  def get_success_url(self):
  # In this line, we override the get_success_url() method by default, this method uses the name URLs.
    return reverse(self.success_url)
  def get_context_data(self, **kwargs): 
  # This line is the method we use to send data to the template.
    context = super(UpdateViewCustom, self).get_context_data(**kwargs) 
    # In this line, we perform the super class method to send normal data from the CBV UpdateView.
    model_name = self.model._meta.verbose_name.title() 
    # In this line, we get the verbose_name property of the defined model.
    context['model_name'] = model_name 
    # In this line, we send the verbose_name property to the template.
    context['url_name'] = self.url_name \
    # This line allows us to send the name of our URL to the template.
    return context

We then need to create the template that displays the form. For this, we need to create the UpdateViewCustom.html file and add the following content:

{% extends "base.html" %}
{% block title_html %}
  Update a {{ model_name }} 
  <!-- In this line, we show the type of model we want to change here. -->
{% endblock %}
{% block h1 %}
  Update a {{ model_name }} 
{% endblock %}
{% block article_content %}
  <form method="post" action="{% url url_name object.id %}"> <!-- line 2 -->
  <!-- In this line, we use our url_name property to redirect the form to the current page. -->
    {% csrf_token %} 
    <table>
      {{ form.as_table }} 
    </table>
    <p><input type="submit" value="Update" /></p>
  </form>
{% endblock %}

To test these new CBVs, we will change the update_task URL in the following manner:

url (r'^update_task_(?P<pk>\d+)$', UpdateViewCustom.as_view(model=Task, url_name="update_task", success_url="public_empty"), name="update_task"),

The following is a screenshot that shows what the CBV will display:

Using a custom class CBV update

Using a custom class CBV update

To finish our suppression page, in this chapter, we have seen that CBVs allow us to not be burdened with unnecessary views. However, we have created many templates that are similar, and we override the CBV only to use the DRY URLs. We will fix these small imperfections. In this section, we will create a CBV and generic template that will allow us to:

  • Use this CBV directly in the urls.py file
  • Enter the name property URLs for redirection
  • Benefit from a template for all uses of these CBVs

Before writing our CBV, we will modify the models.py file, giving each model a verbose_name property and verbose_name_plural. For this, we will use the Meta class. For example, the Task model will become the following:

class Task(models.Model):
  # fields
  def __str__(self):
    return self.title
  class Meta:
    verbose_name = "task"
    verbose_name_plural = "tasks"

We will create an UpdateViewCustom.py file in the views/cbv folder and add the following code:

from django.views.generic import UpdateView
from django.core.urlresolvers import reverse

class UpdateViewCustom(UpdateView):
  template_name = 'en/cbv/UpdateViewCustom.html' 
  # In this line, we define the template that will be used for all the CBVs that extend the UpdateViewCustom class. This template_name field can still be changed if we need it.
  url_name="" 
  # This line is used to create the url_name property. This property will help us to define the name of the current URL. In this way, we can add the link in the action attribute of the form.
  def get_success_url(self):
  # In this line, we override the get_success_url() method by default, this method uses the name URLs.
    return reverse(self.success_url)
  def get_context_data(self, **kwargs): 
  # This line is the method we use to send data to the template.
    context = super(UpdateViewCustom, self).get_context_data(**kwargs) 
    # In this line, we perform the super class method to send normal data from the CBV UpdateView.
    model_name = self.model._meta.verbose_name.title() 
    # In this line, we get the verbose_name property of the defined model.
    context['model_name'] = model_name 
    # In this line, we send the verbose_name property to the template.
    context['url_name'] = self.url_name \
    # This line allows us to send the name of our URL to the template.
    return context

We then need to create the template that displays the form. For this, we need to create the UpdateViewCustom.html file and add the following content:

{% extends "base.html" %}
{% block title_html %}
  Update a {{ model_name }} 
  <!-- In this line, we show the type of model we want to change here. -->
{% endblock %}
{% block h1 %}
  Update a {{ model_name }} 
{% endblock %}
{% block article_content %}
  <form method="post" action="{% url url_name object.id %}"> <!-- line 2 -->
  <!-- In this line, we use our url_name property to redirect the form to the current page. -->
    {% csrf_token %} 
    <table>
      {{ form.as_table }} 
    </table>
    <p><input type="submit" value="Update" /></p>
  </form>
{% endblock %}

To test these new CBVs, we will change the update_task URL in the following manner:

url (r'^update_task_(?P<pk>\d+)$', UpdateViewCustom.as_view(model=Task, url_name="update_task", success_url="public_empty"), name="update_task"),

The following is a screenshot that shows what the CBV will display:

Using a custom class CBV update

Summary

In this chapter, we have learned how to use one of the most powerful features of Django: CBVs. With them, developers can run efficient CRUD operations.

We also learned how to change CBVs to suit our use by adding pagination on a list of items or displaying the work of a developer on the page that displays the information for this user.

In the next chapter, we will learn how to use session variables. We will explore this with a practical example. In this example, we will modify the task list to show the last task accessed.