Login and logout views

Edit the urls.py of your account application, like this:

from django.urls import path
from django.contrib.auth import views as auth_views
from . import views

urlpatterns = [
# previous login view
# path('login/', views.user_login, name='login'),
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

We comment out the URL pattern for the user_login view we have created previously to use the LoginView view of Django's authentication framework. We also add a URL pattern for the  LogoutView view.

Create a new directory inside the templates directory of your account application and name it registration. This is the default path where the Django authentication views expect your authentication templates to be. 

The django.contrib.admin module includes some of the authentication templates that are used for the administration site. We have placed the account application at the top of the INSTALLED_APPS setting so that Django uses our templates by default instead of any authentication templates defined in other apps.

Create a new file inside the templates/registration directory, name it login.html, and add the following code to it:

{% extends "base.html" %}

{% block title %}Log-in{% endblock %}

{% block content %}
<h1>Log-in</h1>
{% if form.errors %}
<p>
Your username and password didn't match.
Please try again.
</p>
{% else %}
<p>Please, use the following form to log-in:</p>
{% endif %}
<p class="login-form">
<form action="{% url 'login' %}" method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<p><input type="submit" value="Log-in"></p>
</form>
</p>
{% endblock %}

This login template is quite similar to the one we created before. Django uses the AuthenticationForm form located at django.contrib.auth.forms by default. This form tries to authenticate the user and raises a validation error if login was unsuccessful. In this case, we can look for errors using {% if form.errors %} in the template to check whether the credentials provided are wrong. Note that we have added a hidden HTML <input> element to submit the value of a variable called next. This variable is first set by the login view when you pass a next parameter in the request (for example, http://127.0.0.1:8000/account/login/?next=/account/).

The next parameter has to be a URL. If this parameter is given, the Django login view will redirect the user to the given URL after a successful login.

Now, create a logged_out.html template inside the registration template directory and make it look like this:

{% extends "base.html" %}

{% block title %}Logged out{% endblock %}

{% block content %}
<h1>Logged out</h1>
<p>You have been successfully logged out. You can <a href="{% url
"login" %}">log-in again</a>.</p>
{% endblock %}

This is the template that Django will display after the user logs out.

After adding the URL patterns and the templates for login and logout views, your website is ready for users to log in using Django authentication views.

Now, we will create a new view to display a dashboard when users log in to their account. Open the views.py file of your account application and add the following code to it:

from django.contrib.auth.decorators import login_required

@login_required
def dashboard(request):
return render(request,
'account/dashboard.html',
{'section': 'dashboard'})

We decorate our view with the login_required decorator of the authentication framework. The login_required decorator checks whether the current user is authenticated. If the user is authenticated, it executes the decorated view; if the user is not authenticated, it redirects the user to the login URL with the originally requested URL as a GET parameter named next. By doing so, the login view redirects users to the URL they were trying to access after they successfully log in. Remember that we added a hidden input in the form of our login template for this purpose.

We also define a section variable. We will use this variable to track the site's section that the user is browsing. Multiple views may correspond to the same section. This is a simple way to define the section that each view corresponds to.

Now, you will need to create a template for the dashboard view. Create a new file inside the templates/account/ directory and name it dashboard.html. Make it look like this:

{% extends "base.html" %}

{% block title %}Dashboard{% endblock %}

{% block content %}
<h1>Dashboard</h1>
<p>Welcome to your dashboard.</p>
{% endblock %}

Then, add the following URL pattern for this view in the urls.py file of the account application:

urlpatterns = [
# ...
path('', views.dashboard, name='dashboard'),
]

Edit the settings.py file of your project and add the following code to it:

LOGIN_REDIRECT_URL = 'dashboard'
LOGIN_URL = 'login'
LOGOUT_URL = 'logout'

The settings mentioned in the preceding code are as follows:

  • LOGIN_REDIRECT_URL: Tells Django which URL to redirect after a successful login if no next parameter is present in the request
  • LOGIN_URL: The URL to redirect the user to log in (for example, views using the login_required decorator)
  • LOGOUT_URL: The URL to redirect the user to log out

We are using the names of the URL patterns we previously defined using the name attribute of the path() function. Hardcoded URLs instead of URL names can also be used for these settings.

Let's summarize what you have done so far:

  • You have added the built-in Django authentication login and logout views to your project
  • You have created custom templates for both views and defined a simple dashboard view to redirect users after they log in
  • Finally, you have configured your settings for Django to use these URLs by default

Now, we will add login and logout links to our base template to put everything together. In order to do this, we have to determine whether the current user is logged in or not in order to display the appropriate link for each case. The current user is set in the HttpRequest object by the authentication middleware. You can access it with request.user. You will find a User object in the request even if the user is not authenticated. A non-authenticated user is set in the request as an instance of AnonymousUser. The best way to check whether the current user is authenticated is by accessing its read-only attribute is_authenticated.

Edit your base.html template and modify the <p> element with a header ID, like this:

<p id="header">
<span class="logo">Bookmarks</span>
{% if request.user.is_authenticated %}
<ul class="menu">
<li {% if section == "dashboard" %}class="selected"{% endif %}>
<a href="{% url "dashboard" %}">My dashboard</a>
</li>
<li {% if section == "images" %}class="selected"{% endif %}>
<a href="#">Images</a>
</li>
<li {% if section == "people" %}class="selected"{% endif %}>
<a href="#">People</a>
</li>
</ul>
{% endif %}

<span class="user">
{% if request.user.is_authenticated %}
Hello {{ request.user.first_name }},
<a href="{% url "logout" %}">Logout</a>
{% else %}
<a href="{% url "login" %}">Log-in</a>
{% endif %}
</span>
</p>

As you can see in the preceding code, we only display the site's menu to authenticated users. We also check the current section to add a selected class attribute to the corresponding <li> item in order to highlight the current section in the menu using CSS. We also display the user's first name and a link to log out if the user is authenticated, or a link to log in otherwise.

Now, open http://127.0.0.1:8000/account/login/ in your browser. You should see the login page. Enter a valid username and password and click on the Log-in button. You should see the following output:

You can see that the My dashboard section is highlighted with CSS because it has a selected class. Since the user is authenticated, the first name of the user is displayed on the right side of the header. Click on the Logout link. You should see the following page:

In the page mentioned in the preceding screenshot, you can see that the user is logged out, and, therefore, the menu of the website is not being displayed anymore. Now, the link on the right side of the header shows Log-in.

If you see the logout page of the Django administration site instead of your own log out page, check the INSTALLED_APPS setting of your project and make sure that django.contrib.admin comes after the account application. Both templates are located in the same relative path, and the Django template loader will use the first one it finds.