1: Making a Django form
Our web app currently has a homepage and a products page but let's give users the chance to register and login in order to rate products and create a wishlist. First we will work on the user registration form and functionality, then we will move on to the services offered to the user once logged in.
In order to add custom forms to our web app, it's best to create a separate forms.py file that will contain all form-related code. While Django does have a built-in user authentication system for registering users, we will extend and customize it to include user emails.
Create a new forms.py file
env > mysite > main > (New File) forms.py
GIF
Create the new file in the mysite > main folder.
Customize the Django UserCreationForm in forms.py
env > mysite > main > forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
# Create your forms here.
class NewUserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
def save(self, commit=True):
user = super(NewUserForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
Add three Django imports to the top of the page. The first imports forms
from Django while the others import a UserCreationForm
and the User
model from Django's built-in authentication forms and models. The NewUserForm
takes in Django's pre-built registration form as a parameter since it extends its functionality. Then the email field is declared. Next, since the form is based on the User
model, the model is specified under class Meta:
along with the all of the user fields we would like included in our form.
Finally we write a short function that overwrites the default save
function to include the email field we added. Don't worry if this part is confusing, we just added an email field to our registration form.
2: Creating a register page
Now that we customized the UserCreationForm
, let's create a register HTML template to render the form in the browser page.
Create a register.html file
env > mysite > main > templates > main > (New File) register.html
GIF
Right click on the templates > main folder and click New File to create a file named register.html.
Code-it-yourself: Add Django template language to register.html
env > mysite > main > templates > main > register.html
{% extends 'main/header.html' %}
{% block content %}
<!-- Register page HTML will go here-->
{% endblock %}
Create register.html in the templates > main folder. Just like before, extend the header.html file so we can have access to the main HTML structural elements and Bootstrap CDN in register.html. Add the extends
, block content
, and endblock
tags in their correct positions. We'll fill in the rest of the HTML soon.
Code-it-yourself: Add register path to urls.py
env > mysite > main > urls.py
from django.urls import path
from . import views
app_name = "main"
urlpatterns = [
path("", views.homepage, name="homepage"),
...
path("register", views.register, name="register"), #add this
]
Add a register
path that connects to a register
function in views.py.
Add the register function to views.py
env > mysite > main > views.py
...
from .forms import NewUserForm #import NewUserForm from forms.py
# Create your views here.
...
def register(request):
form = NewUserForm
return render (request=request, template_name="main/register.html", context={"form":form})
Let's add the register
function to the views.py. First import NewUserForm
from .forms
at the top of the file. This is how we pass the form we created from forms.py to views.py. Next we need to pass the form to the register.html template as context. Add a new register function and declare a variable equal to the form we imported. Then return a render of the register.html template and pass the form as context.
Add HTML code inside block tags of register.html
env > mysite > main > templates > main > register.html
{% extends "main/header.html" %}
{% block content %}
<!--Register-->
<div class="container py-5">
<h1 class="font-weight-bold">Register</h1>
<hr>
<br>
<form method="POST">
{% csrf_token %}
{{ form }}
<br>
<button class="btn btn-primary" type="submit">Register</button>
</form>
<br><br>
<p>If you already have an account, <a href="/login">login</a> instead.</p>
</div>
{% endblock %}
Create a division with container as a class attribute. Next, nest a Register
header using the heading three element. Code a form element with a method="POST"
attribute for submission purposes. Next add the {% csrf_token %}
to prevent form submission forgery. Since we have passed the NewUserForm
as form
in the views.py function for this page, we can include the form with DTL by using double brackets: {{form}}
. Finally, the form will contain an HTML button element to submit the form. After the closing form tag and a few breaks, we'll include a link to a login page that we have not yet created but will add later.
NOTE: We use {% %}
for Python functions and {{ }}
for variables.
Add a link in the navbar to view the register page
env > mysite > main > templates > main > includes > navbar.html
<!--Navbar-->
<nav class="navbar navbar-expand-sm navbar-light bg-light">
<a class="navbar-brand" href="/">Encore</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarText">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/products">Products</a>
</li>
<li class="nav-item">
<a class="nav-link" href=" ">Blog</a>
</li>
<li class="nav-item">
<a class="nav-link" href=" ">Contact</a>
</li>
</ul>
<a class="btn btn-sm btn-primary m-2" href="/register">Register</a> <!--add this-->
</div>
</nav>
After the navbar-nav
unordered list, add an anchor element with an href
attribute that equals /register
. Remember, the href
attribute links to our urls.py file, which will then link to our register function in views.py.
View register page
GIF
Click on the Register link in the navbar. This will bring you to the http://127.0.0.1:8000/register page to view the register.html page. However, if we submit information into the form, the page will not work and a new user will not appear in the admin page. Why? Our register function in our views.py file is not configured to accept information. Instead, the page simply reloads. Let's fix that in the next step.
3: Allowing user registration
Since we set our form's method to POST in the previous step, we need to add a condition that checks for POST request methods in the existing register function. Then, we can save the register form and login the user.
Add functionality to the register form
env > mysite > main > views.py
from django.shortcuts import render, redirect #add this
from .models import Product
from django.core.paginator import Paginator
from .forms import NewUserForm
from django.contrib.auth import login #add this
...
def register(request):
if request.method == "POST":
form = NewUserForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect("main:homepage")
form = NewUserForm
return render (request=request, template_name="main/register.html", context={"form":form})
Go to the register
function in the views.py file. Make sure to import login
and redirect
at the top of the file. Then, add an if
condition to the register function check if the request method is a POST
, as opposed to a GET
request method.
You may have noticed when loading your homepage, a GET
request method appears in the Command Prompt/Terminal every time the page is loaded. GET
and POST
are two common HTTP request methods that signify when a user requests information (GET
) or sends information (POST
). Since users will submit information to the server to register, we set the method
of the request to be POST
in the register template.
If the request method is indeed "POST"
, then we create a form variable that equals a NewUserForm
and takes in the information that the user submitted as a parameter. We check if the form is valid so that the submitted information will work when we attempt to save a user. Next, we save the user, log them in and return a redirect to the homepage so that the user returns to the homepage.
The last two lines of the original register
function are still necessary since the user submits a GET
request method to initially view the register.html page and the form. In other words, when a user clicks on the register link in the navbar they will submit a GET
request method and when they click on the register button to create an account, they will submit a POST
request method. The register function handles the request methods accordingly.
Register a new user on the register page
GIF
Now that we added the necessary code to register a new user in the views.py file, let's try out the registration page. Go to http://127.0.0.1:8000/register and add a test user by submitting the registration form. Upon submission, your page will redirect to the homepage given the return redirect("main:homepage")
in the register function.
Then visit the Django admin at http://127.0.0.1:8000/admin/. You'll need to sign in with your previously created superuser username and password since this test user does not have superuser privileges. Once logged in to the superuser account in the admin, click "Users" to check if the test user was successfully added.