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, UpdateView
Code language: Python (python)
Second, define the
class that inherits from the TaskUpdate
UpdateView
class. In the
class define the following attributes and methods:TaskUpdate
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.
is the target URL (task list) that Django will redirect to once a task is updated successfully.success_url
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 theform_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.