The full user-authentication lifecycle in Django, with testing at every step — The step-by-step tutorial I wish I had (part two)

In part one, we created the model for the "trivial website" in our authentication-and-testing tutorial. In this second part, we’ll create the first of our two views: The user’s profile page, which is only viewable to logged-in users. We’ll also be writing our first substantial tests.

Warning: The website cannot be viewed, and the tests can’t be run (successfully!), until the end of part three. Patience, Grasshopper.

The view

Save the following as/home/myname/django_auth_lifecycle/djauth_root/auth_lifecycle/view__profile.py

"""Renders web pages for the user-authentication-lifecycle project."""
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import render
from django.template import RequestContext
TMPL_BASE_DIR = 'auth_lifecycle/'
"""
The root of the (relative) template paths used in this file, as exists
in
/home/myname/django_files/django_auth_lifecycle/auth_lifecycle/templates/
Equal to 'auth_lifecycle/'
This rendundant 'auth_lifecycle' directory is recommended, because it
allows the templates to be 'namespaced'.
- https://docs.djangoproject.com/en/1.7/topics/http/urls/#url-namespaces
- https://docs.djangoproject.com/en/1.7/topics/http/urls/#topics-http-reversing-url-namespaces
"""
PROFILE_LOGGED_OUT_REDIRECT_URL_NAME='main_page'
"""
TEMPORARY VALUE, only while the login view does not exist. Once it's
created, change this to 'login', and eliminate this comment. This
is also used by the tests.
The 'main_page' will be created in the next post. The 'login' page
will be created in the post after that.
"""
@login_required(login_url=reverse_lazy(PROFILE_LOGGED_OUT_REDIRECT_URL_NAME))
def get_rendered(request):
"""
Displays information unique to the logged-in user.
This blindly passes the request context back to the template.
Before the login functionality exists, you can only view page in a
browser by commenting out the 'login_required' decorator, and adding
following three lines before the return:
from django.contrib.auth import authenticate, login
user = authenticate(username='admin', password='admin')
login(request, user)
- https://docs.djangoproject.com/en/1.7/topics/auth/default/#how-to-log-a-user-in
- https://docs.djangoproject.com/en/1.7/topics/auth/default/#django.contrib.auth.decorators.login_required
Regarding `reverse_lazy`:
- http://stackoverflow.com/questions/26446718/decorated-view-causing-a-viewdoesnotexist-error
"""
return render(request, TMPL_BASE_DIR + 'user_profile.html',
context_instance=RequestContext(request))

The template

Save the following as/home/myname/django_auth_lifecycle/djauth_root/auth_lifecycle/templates/auth_lifecycle/user_profile.html

Translation (internationalization) in all templates will be done by the i18n tag, which gives us access to the trans tag.

Our first substantial tests

When no user is logged in, the profile page should redirect them to the login page. Temporarily, until the login page is created, they’ll instead be redirected to the main page (which will be created in the next post, at which point we can actually run the tests).

When a user is logged in, all their private attributes, aside from the password, should exist somewhere in the rendered html. Test users are defined in test__utilities.py at the bottom of part one.

Save the following as/home/myname/django_auth_lifecycle/djauth_root/auth_lifecycle/test__view_profile.py

(The login_get_test_user used in future tests. And a reminder: The tests cannot be run and the website can’t be viewed, until the end of part three.)

In the next post, we’ll implement and test the second of two views: The main, publicly-available, aggregate-information page. And finally, we’ll actually use and test our trivial demo website. Then it’s onto authentication!