No Time Dad

A blog about web development written by a busy dad

Django Small Project - Workout Tracker (Pt 1)

Table of Contents for Project

Intro

As I’ve mentioned previously, I generally only work on my side projects for about an hour at a time. So I basically want to show what that hour might look like for me if I was build a small Django app from scratch. The main caveat here being that I am already comfortable with Django so I can move pretty quickly with it. If you are more comfortable with another framework then you should absolutely use that framework instead. The point is to maximize your productivity if you are short on time.

So for this project I am going to create a simple workout tracker. This project scratches a small itch I’ve had. Basically I just want to track my progress on some strength exercises I’ve been doing. Yes, I am aware that there are many apps that will do this but I like being in control of my data and I really just want something dead-simple that I can log in and look at at a glance.

Goals For This Session

  1. Scaffold the project
  2. User registration
  3. User login
  4. User logout

I always like to have an idea of what I want to accomplish during a working session. Ideally, these would be typed or written out somewhere but usually I just have a rough idea of what I want to accomplish in my head prior to sitting down to work.

I will be using sqlite for this project, but you could use whatever backend you’d like. For small projects sqlite is fine. It is a hard question to answer, but if you somehow anticipate that your project will grow, then configure your project for postgres.

These two items are things I think I can get done in an hour. Generally speaking, I usually overshoot this list. I’ll probably hold off on handling password management related tasks until later since they are a little more complex. I’ll also focus on just getting the views working and worry about styling later.

Scaffold The Project

  1. Create a directory for the project and cd into it
mkdir workout_track
cd workout_track
  1. Create and activate a virtual environment for the project:
virtualenv -p python3 venv
source venv/bin/activate
  1. Install Django (v3.1.6 for this post)
pip install django
  1. Use django-admin to create a project and cd into the project directory
django-admin startproject workout_track_project
cd workout_track_project
  1. Use django-admin to create an application in the project
django-admin startapp tracker
  1. Add the tracker app to the INSTALLED_APPS list settings.py
# workout_track/workout_track_project/settings.py
...
INSTALLED_APPS = [
    'tracker',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
...
  1. Run makemigrations and migrate (the former command might not have any output but I tend to just run it anyways)
python manage.py makemigrations
python manage.py migrate
  1. Start the server
python manage.py runserver
  1. Verify your see the default Django splash screen at http://127.0.0.1:8000

User Management - Login

Once users are able to signup, they also need to be able to login.

  1. Create the HTML templates for the views
# from the tracker app directory
mkdir -p templates/registration/
touch templates/registration/login.html
  1. Create a urls.py file for the tracker app
# from the tracker app directory
touch urls.py
  1. Update the urls.py file for the tracker app created in step 2 with an an app_name and url mapping to Django’s built-in LoginView
# workout_track/workout_track_project/tracker/urls.py
from django.urls import path
from django.contrib.auth.views import LoginView

app_name = "tracker"
urlpatterns = [
  path("login", LoginView.as_view(), name="login")
]
  1. Update the project urls.py to include the track app’s urls.py
# workout_track/workout_track_project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('tracker/', include('tracker.urls')),
    path('admin/', admin.site.urls),
]
  1. Visit http://127.0.0.1:8000/tracker/login and confirm you are shown a blank page
  2. Update tracker/templates/registration/login.html to include the login form
<form method="POST">
  {% csrf_token %} {{form.as_p }}
  <input type="submit" value="Login" />
</form>
  1. Refresh the page at http://127.0.0.1:8000/tracker/login and confirm you are shown the form. You can try to log in with a random username and password, but we don’t have any users yet so you should be shown an error.

User Management - Logout

Let’s go ahead and add a logout view. Again, we’ll use a view that Django provides for us out of the box.

  1. Update your tracker/urls.py to include a path to the LogoutView.
# workout_track/workout_track_project/tracker/urls.py
from django.urls import path
from django.contrib.auth.views import LoginView, LogoutView

from tracker.views import HomeView, UserSignupView

app_name = "tracker"
urlpatterns = [
  path('login', LoginView.as_view(), name="login"),
  path('logout', LogoutView.as_view(), name="logout"),
]

User Management - Registration

So now we will add a registration view and simple home page view that users are reidrected to once they’re registered. We’ll add an authentication check to the home page view template for debugging purposes right now.

  1. Create HTML files for the home page and the signup page
touch templates/registration/signup.html
touch templates/tracker/home.html
  1. Create the HomeView in tracker/views.py
# workout_track/workout_track_project/tracker/views.py
from django.views.generic.base import TemplateView

class HomeView(TemplateView):
    template_name = 'tracker/home.html'
  1. Add a path in tracker/urls.py for the HomeView
# workout_track/workout_track_project/tracker/urls.py
from django.urls import path
from django.contrib.auth.views import LoginView

from tracker.views import HomeView

app_name = "tracker"
urlpatterns = [
  path('', HomeView.as_view(), name="home"),
  path('login', LoginView.as_view(), name="login"),
  path('logout', LogoutView.as_view(), name="logout"),

]
  1. Update tracker/templates/tracker/home.html to include an authentication check and basic header
<h1>Tracker Home Page</h1>
{% if user.is_authenticated %} Hello, {{user.username}}! {% else %} Please
<a href="{% url 'tracker:login' %}">Login</a> {% endif %}
  1. Verify that the page is displayed at http://127.0.0.1:8000/tracker/
  2. Create a view for the signup page using Django’s built-in UserCreationForm in tracker/views.py
# workout_track/workout_track_project/tracker/views.py
from django.contrib.auth.forms import UserCreationForm
from django.views.generic.edit import FormView
from django.views.generic.base import TemplateView
from django.contrib.auth import login
from django.contrib.auth.models import User
from django.urls import reverse_lazy

class HomeView(TemplateView):
    template_name = 'tracker/home.html'

class UserSignupView(FormView):
    model = User
    form_class = UserCreationForm
    success_url = reverse_lazy('tracker:home')
    template_name = 'registration/signup.html'

    def form_valid(self, form):
        user = form.save()
        login(self.request, user)
        return super().form_valid(form)
  1. Map the new UserSignupView to a path in tracker/urls.py
# workout_track/workout_track_project/tracker/urls.py
from django.urls import path
from django.contrib.auth.views import LoginView

from tracker.views import HomeView, UserSignupView

app_name = "tracker"
urlpatterns = [
  path('', HomeView.as_view(), name="home"),
  path('login', LoginView.as_view(), name="login"),
  path('logout', LogoutView.as_view(), name="logout"),
  path('signup', UserSignupView.as_view(), name="signup")
]
  1. Update tracker/templates/tracker/signup.html to include the form instance provided by Django
<form method="POST">
  {% csrf_token %} {{form.as_p}}
  <input type="submit" value="Signup" />
</form>
  1. Test out the new signup form by creating a user: joe:test123456789 at http://127.0.0.1:8001/tracker/signup. Once you click “Signup” with a valid username and password you should be redirected to the home page view and see the username you entered displayed, “Hello, joe!” (if you used the credentials above).

Update Redirect Urls

Everything is mostly working at this point but we’ll need to specify where we want Django to redirect the users on login and logout.

  1. Update your project’s settings.py to include the following namespaced urls
# workout_track/workout_track_project/settings.py
...
LOGIN_URL = 'tracker:login'
LOGOUT_REDIRECT_URL = 'tracker:login'
LOGIN_REDIRECT_URL = 'tracker:home'
...

Testing

So now we have user registration, login, and logout. Let’s test everything out.

  1. Visit http://127.0.0.1:8001/tracker/logout in your browser to ensure you are logged out.
  2. Create a new user at http://127.0.0.1:8001/tracker/signup and ensure you are taking to the home page with your username displayed
  3. Visit http://127.0.0.1:8001/tracker/logout again
  4. Visit http://127.0.0.1:8001/tracker/login and login with the user credentials you created in step 1 and ensure you are taken to the home page and the username is displayed.

Wrapping Up

That is pretty much it for now. If you are comfortable with Django than this should take less than an hour for sure. It is totally fine if it took more than an hour or each part took an hour! Part of this is just learning how to use the web framework, and you might not be super familiar with it yet.

In part 2 we will go over adding the core functionality to our workout tracker. Including models, views, and templates for tracking workouts.