Securing the Application⌗
Now that we can view our notes on the website, we are going to want a login system. Currently anyone can navigate to our website and see all of our notes. Not ideal. To secure our site we will be using a combination of Djangos built-in auth module and crispy forms. First off we will add the auth modules URLs to the project so open up the URLs file in the project directory and add the following. This will mean that all the account functions, such as logging in/out, password changes etc. are located underneath “/account/” of our website.
from .views import LoginView path('account/', include('django.contrib.auth.urls')), path('account/login', LoginView.as_view(), name='login')
We are overriding the default login page with our own one as we are going to be using a crispy form to make it look far nicer. We will do this using a view so we need to create a
views.py file inside the project directory
DjangoNotes/. Once you’ve opened the file, copy the following into it:
from django.contrib.auth import authenticate, login from django.urls import reverse_lazy from django.views import generic from .forms import LoginForm class LoginView(generic.FormView): form_class = LoginForm success_url = reverse_lazy('home') template_name = 'accounts/login.html' def form_valid(self, form): username = form.cleaned_data['username'] password = form.cleaned_data['password'] user = authenticate(username=username, password=password) if user is not None and user.is_active: login(self.request, user) return super(LoginView, self).form_valid(form) else: return self.form_invalid(form)
The class tells Django what to do and how to do when someone navigates to the login page. The form class used is one we will create shortly. If the user successfully logs in then they will be redirected to ‘home’ (root of our website). It also specifies which template to load. Once the form is submitted is does some basic data cleaning and attempts to authenticate the user against the database of users.
We now need to create our Form object. This defines what fields the form will have and the attributes it will contain. Create a new file in the same place as the views file and copy the following code to it. All we are doing here is defining 2 fields, username and password, and the submit button. The submit button has some extra code defining how it will look. In this case we want it to be a primary button.
from django.contrib.auth.forms import AuthenticationForm from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, ButtonHolder, Submit class LoginForm(AuthenticationForm): def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) self.helper = FormHelper() self.helper.layout = Layout( 'username', 'password', ButtonHolder( Submit('login', 'Login', css_class='btn-primary') ) )
Now we have defined the login system we can force the user to login when attempting to view either of our 2 pages. This can be done incredibly simple with the use of decorators. Edit your views file so it looks like the following. This tells the login system to direct the user to the
login_url if they access the page with authorization.
[ ... ] from django.contrib.auth.decorators import login_required @login_required(login_url="/account/login") def note_list(request, tag_slug=None): [ ... ] @login_required(login_url="/account/login") def note_detail(request, note): [ ... ]