Creating a login view
We will start this section by using the Django authentication framework to allow users to log in to our website. Our view should perform the following actions to log in a user:
- Get the username and password by posting a form
- Authenticate the user against the data stored in the database
- Check whether the user is active
- Log the user into the website and start an authenticated session
First, we will create a login form. Create a new forms.py file in your account application directory and add the following lines to it:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
This form will be used to authenticate users against the database. Note that we use the PasswordInput widget to render its HTML input element, including a type="password" attribute, so that the browser treats it as a password input. Edit the views.py file of your account application and add the following code to it:
from django.http import HttpResponse
from django.shortcuts import render
from django.contrib.auth import authenticate, login
from .forms import LoginForm
def user_login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(request,
username=cd['username'],
password=cd['password'])
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse('Authenticated '\
'successfully')
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('Invalid login')
else:
form = LoginForm()
return render(request, 'account/login.html', {'form': form})
This is what our basic login view does: when the user_login view is called with a GET request, we instantiate a new login form with form = LoginForm() to display it in the template. When the user submits the form via POST, we perform the following actions:
- Instantiate the form with the submitted data with form = LoginForm(request.POST).
- Check whether the form is valid with form.is_valid(). If it is not valid, we display the form errors in our template (for example, if the user didn't fill in one of the fields).
- If the submitted data is valid, we authenticate the user against the database using the authenticate() method. This method takes the request object, the username, and the password parameters and returns the User object if the user has been successfully authenticated, or None otherwise. If the user has not been authenticated, we return a raw HttpResponse, displaying the Invalid login message.
- If the user was successfully authenticated, we check whether the user is active, accessing its is_active attribute. This is an attribute of Django's user model. If the user is not active, we return an HttpResponse that displays the Disabled account message.
- If the user is active, we log the user into the website. We set the user in the session by calling the login() method and return the Authenticated successfully message.
Note the difference between authenticate and login: authenticate() checks user credentials and returns a User object if they are right; login() sets the user in the current session.
Now, you will need to create a URL pattern for this view. Create a new urls.py file in your account application directory and add the following code to it:
from django.urls import path
from . import views
urlpatterns = [
# post views
path('login/', views.user_login, name='login'),
]
Edit the main urls.py file located in your bookmarks project directory, import include, and add the URL patterns of the account application, as follows:
from django.conf.urls import path, include
from django.contrib import admin
urlpatterns = [
path('admin/', admin.site.urls),
path('account/', include('account.urls')),
]
The login view can now be accessed by a URL. It is time to create a template for this view. Since you don't have any templates for this project, you can start by creating a base template that can be extended by the login template. Create the following files and directories inside the account application directory:
templates/
account/
login.html
base.html
Edit the base.html file and add the following code to it:
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/base.css" %}" rel="stylesheet">
</head>
<body>
<p id="header">
<span class="logo">Bookmarks</span>
</p>
<p id="content">
{% block content %}
{% endblock %}
</p>
</body>
</html>
This will be the base template for the website. As we did in our previous project, we include the CSS styles in the main template. You can find these static files in the code that comes along with this chapter. Copy the static/ directory of the account application from the chapter's source code to the same location in your project so that you can use the static files.
The base template defines a title block and a content block that can be filled with content by the templates that extend from it.
Let's fill in the template for our login form. Open the account/login.html template and add the following code to it:
{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
<h1>Log-in</h1>
<p>Please, use the following form to log-in:</p>
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Log in"></p>
</form>
{% endblock %}
This template includes the form that is instantiated in the view. Since our form will be submitted via POST, we will include the {% csrf_token %} template tag for CSRF protection. You learned about CSRF protection in Chapter 2, Enhancing Your Blog with Advanced Features.
There are no users in your database, yet. You will need to create a superuser first in order to be able to access the administration site to manage other users. Open the command line and execute python manage.py createsuperuser. Fill in the desired username, email, and password. Then, run the development server using the python manage.py runserver command and open http://127.0.0.1:8000/admin/ in your browser. Access the administration site using the credentials of the user you just created. You will see the Django administration site, including the User and Group models of the Django authentication framework.
It will look as follows:
Create a new user using the administration site and open http://127.0.0.1:8000/account/login/ in your browser. You should see the rendered template, including the login form:
Now, submit the form, leaving one of the fields empty. In this case, you will see that the form is not valid and displays errors, as follows:
Note that some modern browsers will prevent you from submitting the form with empty or erroneous fields. This is because of form validation done by the browser based on field types and restrictions per field. In this case, the form won't be submitted and the browser will display an error message for the fields that are wrong.
If you enter a non-existing user or a wrong password, you will get an Invalid login message.
If you enter valid credentials, you will get an Authenticated successfully message, like this: