Django UpdateView

Summary: in this tutorial, you’ll learn how to use the Django UpdateView class to create a class-based view that edits an existing object.

This tutorial begins where the Django CreateView tutorial left off.

Defining the UpdateView class

The UpdateView class allows you to create a class-based view that:

  • Display a form for editing an existing object.
  • Redisplay the form if it has validation errors.
  • Save changes of the object to the database.

The form is generated automatically from the object’s model unless you explicitly specify a form class.

To demonstrate the Django UpdateView class, we’ll create a view that edits a task of the Todo App.

To do that we modify the views.py of the todo app and define the TaskUpdate class that inherits from the UpdateView class like this:

# ...
from django.views.generic.edit import CreateView, UpdateView
from django.contrib import messages
from django.urls import reverse_lazy
from .models import Task


class TaskUpdate(UpdateView):
    model = Task
    fields = ['title','description','completed']
    success_url = reverse_lazy('tasks')
    
    def form_valid(self, form):
        messages.success(self.request, "The task was updated successfully.")
        return super(TaskUpdate,self).form_valid(form)

# ...Code language: Python (python)

How it works.

First, import the UpdateView from the django.views.generic.edit:

from django.views.generic.edit import CreateView, UpdateViewCode language: Python (python)

Second, define the TaskUpdate class that inherits from the UpdateView class. In the TaskUpdate class define the following attributes and methods:

  • model specifies the class of the object to be edited. Because we specify the Task as the model in this example.
  • fields is a list that specifies the form fields. In this example, we use title, description, and completed fields.
  • success_url is the target URL (task list) that Django will redirect to once a task is updated successfully.
  • form_valid() – the method is called once the form is posted successfully. In this example, we create a flash message and return the result of the form_valid() method of the superclass.

By default, the TaskUpdate class uses the task_form.html template from the templates/todo directory. Note that the CreateView and UpdateView classes share the same template name.

If you want to use a different template name, you can specify it using the template_name attribute.

Creating the task_form.html template

Modify the task_form.html template that shows the Update Task heading if the task variable is available in the template (editing mode) or Create Task otherwise (creating mode).

{%extends 'base.html'%}

{%block content%}

<div class="center">
 <form method="post" novalidate class="card">
 	{%csrf_token %}
 	<h2>{% if task %} Update {%else %} Create {%endif%} Task</h2>
	{% for field in form %}
		{% if field.name == 'completed' %}
			<p>
				{{ field.label_tag }}
				{{ field }}
			</p>
			{% if field.errors %}
        		<small class="error">{{ field.errors|striptags  }}</small> 
        	{% endif %}
		{% else %}
    		{{ field.label_tag }} 
        	{{ field }}
        	{% if field.errors %}
        		<small class="error">{{ field.errors|striptags  }}</small> 
        	{% endif %}
        {% endif %}
	{% endfor %}
	
	<div class="form-buttons">
		<input type="submit" value="Save" class="btn btn-primary"/>
		<a href="{%url 'tasks'%}" class="btn btn-outline">Cancel</a>
	</div>
	

</form>
</div>

{%endblock content%}
Code language: HTML, XML (xml)

Defining a route

Define a route in the urls.py of the todo app that maps a URL with the result of the as_view() method of the TaskUpdate class:

from django.urls import path
from .views import (
    home, 
    TaskList, 
    TaskDetail, 
    TaskCreate, 
    TaskUpdate
)


urlpatterns = [
    path('', home, name='home'),
    path('tasks/', TaskList.as_view(),name='tasks'),
    path('task/<int:pk>/', TaskDetail.as_view(),name='task'),
    path('task/create/', TaskCreate.as_view(),name='task-create'),
    path('task/update/<int:pk>/', TaskUpdate.as_view(),name='task-update'),
]
Code language: Python (python)

Including an edit link

Modify the task_list.html template to include the edit link for each task on the task list:

{%extends 'base.html'%}

{%block content%}

<div class="center">
	<h2>My Todo List</h2>
	{% if tasks %}
	<ul class="tasks">
		{% for task in tasks %}
			<li><a href="{% url 'task' task.id %}" class="{% if task.completed%}completed{%endif%}">{{ task.title }}</a> 
				 <div  class="task-controls">
				 	<a href="#"><i class="bi bi-trash"></i> </a>
					<a href="{%url 'task-update' task.id %}"><i class="bi bi-pencil-square"></i></a>
		         </div>
		    </li>
		{% endfor %}
	{% else %}
		<p>🎉 Yay, you have no pending tasks! <a href="{%url 'task-create'%}">Create Task</a></p>
	{% endif %}
	</ul>
</div>
{%endblock content%}
Code language: HTML, XML (xml)

If you edit a task from the todo list by appending three asterisks (***) to the title and mark the task as completed:

Click the Save button and you’ll see that the title and status of the task are updated:

You can download the final code for this Django UpdateView tutorial here.

Summary

  • Define a new class that inherits from the UpdateView class to create a class-based view that edits an existing object.
Did you find this tutorial helpful ?