Summary: in this tutorial, you’ll learn how to use the Django FormView
class to create a registration form for the Todo app.
This tutorial begins where the Django LoginView tutorial left off.
The Django FormView
class allows you to create a view that displays a form. We’ll use the FormView
class to create a registration form for the Todo App.
Creating a signup form
Create form.spy
file in the users
app and define the RegisterForm
class as follows:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
email = forms.EmailField(max_length=254)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2', )
Code language: Python (python)
The RegisterForm
uses the User
model and displays the username, email, password1, and password2 fields.
Defining a RegisterView class
Define the RegisterView
class in views.py
of the users.py
app:
from django.urls import reverse_lazy
from django.views.generic.edit import FormView
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login
from django.contrib.auth.models import User
from .forms import RegisterForm
class RegisterView(FormView):
template_name = 'users/register.html'
form_class = RegisterForm
redirect_authenticated_user = True
success_url = reverse_lazy('tasks')
def form_valid(self, form):
user = form.save()
if user:
login(self.request, user)
return super(RegisterView, self).form_valid(form)
Code language: Python (python)
The RegisterView class inherits from the FormView class and has the following attributes and methods:
template_name
specifies the name of the template for rendering the signup form.form_class
specifies the form (RegisterForm
) used in the template.redirect_authenticated_user
is set to True to redirect the user once authenticated.success_url
specifies the URL to redirect once the user signs up successfully. In this example, it redirects the user to the task list.form_valid()
method is called once the form is submitted successfully. In this example, we save theUser
model and log the user in automatically.
Defining the registration route
Define a route that maps the registration URL register/
with the result of the as_view()
method of the RegisterView
class in the urls.py
of the users
app:
from django.urls import path
from django.contrib.auth.views import LogoutView
from .views import MyLoginView, RegisterView
urlpatterns = [
path('login/', MyLoginView.as_view(),name='login'),
path('logout/', LogoutView.as_view(next_page='login'),name='logout'),
path('register/', RegisterView.as_view(),name='register'),
]
Code language: Python (python)
Create a registration template
Create a register.html
in the templates/users
directory of the users
app with the following code:
{%extends 'base.html'%}
{%block content%}
<div class="center">
<form method="post" novaldiate class="card">
{% csrf_token %}
<h2 class="text-center">Create your account</h2>
{% for field in form %}
{{ field.label_tag }}
{{ field }}
{% if field.errors %}
<small class="error">{{ field.errors|striptags }}</small>
{% endif %}
{% endfor %}
<input type="submit" value="Register" class="btn btn-primary full-width">
<hr>
<p class="text-center">Already have an account? <a href="{% url 'login'%}">Login Here</a></p>
</form>
</div>
{%endblock content%}
Code language: HTML, XML (xml)
The form in the users/register.html
is the RegisterForm
class that we defined in the forms.py
file.
Adding registration link to the login and navigation
Modify the login.html
template by adding the registration link:
{%extends 'base.html'%}
{%block content%}
<div class="center">
<form method="post" class="card" novalidate>
{% csrf_token %}
<h2 class="text-center">Log in to your account</h2>
{% for field in form %}
{{ field.label_tag }}
{{ field }}
{% if field.errors %}
<small>{{ field.errors|striptags }}</small>
{% endif %}
{% endfor %}
<input type="submit" value="Login" class="btn btn-primary full-width">
<hr>
<p class="text-center">Forgot your password <a href="#">Reset Password</a></p>
<p class="text-center">Don't have a account? <a href="{%url 'register'%}">Join Now</a></p>
</form>
</div>
{%endblock content%}
Code language: HTML, XML (xml)
Also, modify the base.html
template by adding the registration link to the navigation and homepage:
{%load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'css/style.css' %}" />
<title>Todo List</title>
</head>
<body>
<header class="header">
<div class="container">
<a href="{%url 'home'%}" class="logo">Todo</a>
<nav class="nav">
<a href="{%url 'home'%}"><i class="bi bi-house-fill"></i> Home</a>
{% if request.user.is_authenticated %}
<a href="{% url 'tasks' %}"><i class="bi bi-list-task"></i> My Tasks</a>
<a href="{% url 'task-create' %}"><i class="bi bi-plus-circle"></i> Create Task</a>
<a href="#">Hi {{request.user | title}}</a>
<a href="{% url 'logout' %}" class="btn btn-outline">Logout</a>
{% else %}
<a href="{% url 'login' %}" class="btn btn-outline">Login</a>
<a href="{% url 'register' %}" class="btn btn-primary">Join Now</a>
{% endif %}
</nav>
</div>
</header>
<main>
<div class="container">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{message.tags}}">
{{message}}
</div>
{% endfor %}
{% endif %}
{%block content %}
{%endblock content%}
</div>
</main>
<footer class="footer">
<div class="container">
<p>© Copyright {% now "Y" %} by <a href="https://www.pythontutorial.net">Python Tutorial</a></p>
</div>
</footer>
</body>
</html>
Code language: HTML, XML (xml)
home.html
{%extends 'base.html'%}
{%load static %}
{%block content%}
<section class="feature">
<div class="feature-content">
<h1>Todo</h1>
<p>Todo helps you more focus, either work or play.</p>
<a class="btn btn-primary cta" href="{% url 'register' %}">Get Started</a>
</div>
<img src="{%static 'images/feature.jpg'%}" alt="" class="feature-image">
</section>
{%endblock content%}
Code language: HTML, XML (xml)
If you open the registration URL:
http://127.0.0.1:8000/register/
Code language: Python (python)
you’ll see the registration form:
Once registered successfully, you’ll be logged in automatically:
However, we have one issue. Jane can view, update, and delete other users’ tasks.
To fix this, you need to filter the tasks that belong to the currently logged user in all the classes by adding the get_queryset()
methods to the TaskList
, TaskDetail
, TaskCreate
, TaskUpdate
, TaskDelete
classes.
from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from .models import Task
class TaskList(LoginRequiredMixin, ListView):
model = Task
context_object_name = 'tasks'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tasks'] = context['tasks'].filter(user=self.request.user)
return context
class TaskDetail(LoginRequiredMixin, DetailView):
model = Task
context_object_name = 'task'
def get_queryset(self):
base_qs = super(TaskDetail, self).get_queryset()
return base_qs.filter(user=self.request.user)
class TaskUpdate(LoginRequiredMixin, 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)
def get_queryset(self):
base_qs = super(TaskUpdate, self).get_queryset()
return base_qs.filter(user=self.request.user)
class TaskDelete(LoginRequiredMixin, DeleteView):
model = Task
context_object_name = 'task'
success_url = reverse_lazy('tasks')
def form_valid(self, form):
messages.success(self.request, "The task was deleted successfully.")
return super(TaskDelete,self).form_valid(form)
def get_queryset(self):
base_qs = super(TaskDelete, self).get_queryset()
return base_qs.filter(user=self.request.user)
Code language: Python (python)
Now, if you log in as Jane, you’ll see an empty todo list:
If you create a new task, you’ll see only that task in the todo list:
If you attempt to access John’s tasks while logging in as Jane, you’ll get a 404 error like this:
You can download the complete code here.
Summary
- Use Django
FormView
to create a view that displays a form.