1: Installing Django crispy forms


We have increased the functionality of our web app, so let's work on the user experience (UX).  This means making sure our users understand what is happening on our site.  For example, the register form is rather ugly and users do not know if their registration was successful. They may be left wondering: Did the form work? and Do I need to register again?

Let's tackle these UX concerns with easy-to-use Python packages and built-in Django features to effectively bridge the disconnect between our web app and potential users.

 

Style the registration form

macOS Terminal

(Ctrl + C)
(env)User-Macbook:code user$>pip install django-crispy-forms

Windows Command Prompt

(Ctrl + C)
(env)C:\Users\Owner\desktop\code\env\mysite>pip install django-crispy-forms

Exit your development server with Ctrl + C and enter the above line of code to install a package that makes forms look nicer. The package is called django-crispy-forms.

 

env > mysite > mysite > settings.py

INSTALLED_APPS = [
    'main.apps.MainConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crispy_forms',  #add this
]

CRISPY_TEMPLATE_PACK = 'bootstrap4' #add this

Next add crispy_forms to your settings.py file and specify the template pack below. Crispy forms will not work if you forget to add both lines of code. 

 

Edit register.html 

env > mysite > main > templates > main > register.html

{% extends "main/header.html" %}

	{% block content %}

	{% load crispy_forms_tags %}   <!--add this-->        

	<!--Register--> 
	<div class="container py-5">
	    <h1 class="font-weight-bold">Register</h1>
	    <hr>
	    <br>
		<form method="POST">
			{% csrf_token %}
			{{ form|crispy }}         <!--add this-->            
			<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 %}

Then go to the register.html page to include crispy forms by loading in the crispy_form_tags near the top of the file and editing {{ form }} to {{ form|crispy }}.

 

View the updated form in the browser

Django crispy forms register page

Run the server again and reload the http://127.0.0.1:8000/register page. The form now has a cleaner design.








2: Django messages framework


Now that we have a register page template, a register url pattern in urls.py, and a register function in views.py, let's learn how to use Django's messages framework to prompt users when they register.  In other words, the framework allows us to use pop-up notifications to inform users if they successfully registered.  In the next few lessons, we will also use the messages framework to notify users when they login or logout.

 

Enable the messages framework

env > mysite > mysite > settings.py

INSTALLED_APPS = [
    ...
    'django.contrib.messages',
    ...
]
MIDDLEWARE = [
        ...
        'django.contrib.sessions.middleware.SessionMiddleware',
        ...
        'django.contrib.messages.middleware.MessageMiddleware',
        ...
    ]
TEMPLATES = [
			...
            'context_processors': [
								...
                'django.contrib.messages.context_processors.messages',
            ],
       ...

By default, the above three blocks of code should already be in the settings.py file, just make sure they are indeed in place.  "django.contrib.messages" under INSTALLED_APPS provides default message tags, middleware allows messages to be called before or after a view function runs, and the message context processors allows message popups to be loaded into templates without being passed as context in a function in views.py

 

Match default message tags with Bootstrap

env > mysite > mysite > settings.py

import os
from django.contrib.messages import constants as messages

...

CRISPY_TEMPLATE_PACK = 'bootstrap4'

MESSAGE_TAGS = {
        messages.DEBUG: 'alert-info',
        messages.INFO: 'alert-info',
        messages.SUCCESS: 'alert-success',
        messages.WARNING: 'alert-warning',
        messages.ERROR: 'alert-danger',
 }

...

Let's match Django's default message tags to a Bootstrap alert colors in our settings.py file. First import the Django messages at the top of the file. Add the MESSAGE_TAGS after the CRISPY_TEMPLATE_PACK line of code in the settings.py.  Remember, info represents teal, success is green, warning is yellow, and danger is red in the Bootstrap framework. Save the changes made to the file.

 

Create a messages.html file

env > mysite > main > templates > main > includes > (New File) messages.html

Create a messages.html fileGIF

In the templates > main > includes folder, right click on the includes folder and select New File to create a messages.html file.

 

Edit the messages.html file

env > mysite > main > templates > main > includes > messages.html

<!--Messages-->

{% for message in messages %}

	<div class="container-fluid mx-0 p-0 sticky-top">
	  	<div class="alert {{ message.tags }} alert-dismissible m-0 p-3" role="alert">
		    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
		    	<span aria-hidden="true">&times;</span>
		    </button>
	    	{{ message }}
	  	</div>
	</div>

{% endfor %}

In this file we will use the Django template language to include a for loop that iterates over any messages we call in our views.py. The type of message we call in the views.py file (i.e. messages.INFOmessages.SUCCESS) will determine the color of the alert. We also include a button to close the alert, and of course, the message itself. Save the changes to messages.html.

 

Include messages.html in the header.html

env > mysite > main > templates > main > header.html

<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>

    {% include 'main/includes/navbar.html' %}

    {% include 'main/includes/messages.html' %}
    
    {% block content %}

    {% endblock %} 
      
    <!-- Optional Javascript -->
    ...
  </body>
</html>

Open header.html and include the messages.html file before block content. No different than our navbar.html, messages.html will be included with our other web pages so users can receive notifications on any page they visit on our web app.  

 

Add messages to register function

env > mysite > main > views.py

...
from django.contrib import messages #import messages
    
    
...
    
def register(request):
	if request.method == "POST":
		form = NewUserForm(request.POST)
		if form.is_valid():
			user = form.save()
			login(request, user)
			messages.success(request, "Registration successful." )
			return redirect("main:homepage")
		messages.error(request, "Unsuccessful registration. Invalid information.")
	form = NewUserForm
	return render (request=request, template_name="main/register.html", context={"form":form})

Finally, we'll add two messages to the register function to inform users whether their registration was successful. Start by importing messages at the top of the page. The first notification will appear if the user registers successfully while the second notification will appear if the user registers unsuccessfully. Once again, make sure to import messages at the top of the file before calling on messages in the function. Save the changes made to the file.

You can register another user or wait until we add a login/logout function to test messages.  If you choose to register another user, you can always delete the user from the admin page.

Registration successful message






Quiz Questions


1. Which step is not necessary to add django-crispy-forms to a project?


2. What color is the following alert: messages.error(request, "Unsuccessful registration: invalid information")?s


3. Which is the correct way to include messages.html in header.html?


Next lesson


Check out the comments and debug buttons if you get stuck.