Project Overview & Django + MySQL Setup

Premier League Predictor: Django & MySQL

Chapter 1 · Project Overview & Django + MySQL Setup

This is the second of four courses building the exact same Premier League prediction tracker in four genuinely different architectures — Premier League Predictor (FastAPI & PostgreSQL, complete — see plpredict-fastapi1), Premier League Predictor (FastAPI & Redis), and Premier League Predictor (Astro) are its siblings, the latter two still outlined rather than generated yet. Where the FastAPI variant leaned into a real, typed API layer, this course leans into Django's own ready-made admin interface — a genuine fit for a project with this much real, recurring manual data entry.

What the App Actually Does

The shared spec every course in this set builds toward — a personal, weekly Premier League prediction tracker:

  • Track every fixture across a real 38-gameweek Premier League season, 20 teams, 10 fixtures per gameweek.
  • Record four real prediction sources per fixture: the user's own prediction, the BBC's expert prediction (currently Chris Sutton), that week's guest predictor(s) — genuinely variable, with multiple guests averaged into a single figure for the week — and the BBC's own published AI-generated prediction, manually transcribed rather than scraped or generated by this app.
  • Score two different things per prediction once a result is in — a correct score (the exact scoreline matched) and a correct result (the predicted win/draw/loss outcome matched, even if the scoreline itself didn't).
  • Maintain the real league table — points, goal difference, wins/draws/losses — alongside a second, parallel prediction league table ranking how each of the four real predictors is actually doing across the season.
  • Handle promotion and relegation between seasons — the bottom three teams auto-calculated and removed at season end; the three promoted teams entered manually.
The real point values, already confirmed — no need to re-derive them here
plpredict-fastapi1's own Chapter 6 resolved this directly with the user: 40 points for a correct score, 10 points for a correct result. This course reuses that same confirmed split rather than asking again — a real product decision, made once, that applies to every variant in this set.

Why Django + MySQL for This One

This project has a genuinely heavy, recurring manual-entry burden — 10 fixtures every gameweek, up to 5 real predictions per fixture, a real result entered for every fixture, three promoted teams typed in by name every season. That's exactly the shape of work Django's own admin interface exists to make fast: generated automatically from the models this course defines, with zero hand-built forms needed for the raw data-entry side of the job (Chapter 3). MySQL is the natural, familiar real-world pairing for a Django project — a genuinely different relational engine from the FastAPI variant's own PostgreSQL, letting the two reference implementations be read side by side later.

One real difference to keep in mind well before Chapter 5
The FastAPI/PostgreSQL variant's own Chapter 5 leaned on a genuine PostgreSQL-specific feature — a partial unique index (CREATE UNIQUE INDEX ... WHERE source != 'guest') — to allow multiple guest predictions per fixture while still enforcing exactly one user/expert/AI prediction each. MySQL has no equivalent mechanism — it doesn't support a WHERE clause on an index at all. This course will need a genuinely different real solution to the identical problem when Chapter 5 gets there — flagged honestly now, not silently discovered later.

Setting Up: Django & MySQL

A local Python install with pip, and a working local MySQL server, are assumed from here on. Creating the database first, with an explicit modern charset:

CREATE DATABASE pl_predictor CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

utf8mb4, not plain utf8 — MySQL's own historical utf8 charset is actually a restricted 3-byte encoding that can't store every real Unicode character (emoji included); utf8mb4 is the genuinely full implementation, and the standard real-world choice for a new MySQL database today.

# Create and activate a virtual environment python -m venv venv source venv/bin/activate # venv\Scripts\activate on Windows # Install Django and a MySQL driver pip install django mysqlclient
mysqlclient needs real build tools — PyMySQL is the easier development alternative
mysqlclient is a genuine C extension wrapping MySQL's own native client library — fast, but it needs real system build dependencies (libmysqlclient-dev on Debian/Ubuntu, Microsoft's C++ Build Tools on Windows) to install at all, unlike PostgreSQL's own psycopg2-binary, which ships pre-compiled. If that friction genuinely gets in the way during development, pip install PyMySQL plus two lines at the very top of manage.py — import pymysql; pymysql.install_as_MySQLdb() — makes Django use a pure-Python MySQL driver instead, with no compiled extension required at all. The real tradeoff: PyMySQL is genuinely slower under heavy load than mysqlclient, a real cost worth knowing about before choosing it for anything beyond local development.

Starting the Django Project

# Start the Django project and the predictor app django-admin startproject pl_predictor_site . python manage.py startapp predictor

Pointing the new project at the real MySQL database in pl_predictor_site/settings.py:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'pl_predictor', 'USER': 'root', 'PASSWORD': '', # set a real password in production 'HOST': 'localhost', 'PORT': '3306', 'OPTIONS': { 'charset': 'utf8mb4', }, } }

Add 'predictor' to INSTALLED_APPS, then confirm the connection works by running Django's own initial migrations against the real database:

python manage.py migrate python manage.py runserver
The OPTIONS charset setting matters as much as the database's own
Setting 'charset': 'utf8mb4' inside OPTIONS makes Django's own connection use the same full-Unicode charset the database was created with — a mismatch between the two (a utf8mb4 database with a connection defaulting to plain utf8) is a real, documented source of silent data corruption for anything outside the restricted 3-byte range, not just a cosmetic setting.

Where This Course Is Headed

A real Django-model schema for teams, seasons, gameweeks, and fixtures (Chapter 2); the Django admin as the real manual-entry tool for teams and fixtures (Chapter 3); the fast click-to-pair fixture-entry UI built outside the admin (Chapter 4); recording all four prediction sources, and a genuinely MySQL-specific answer to the partial-unique-index gap flagged above (Chapter 5); entering results and calculating the confirmed 40/10 scoring (Chapter 6); the real league table (Chapter 7); the prediction league table (Chapter 8); promotion and relegation (Chapter 9); styling and the gameweek/season selector (Chapter 10); deployment (Chapter 11); and a capstone integrating this predictor into the existing Astro-based site (Chapter 12).

Hands-On Exercises

Exercise 1

Explain why this course reuses the 40/10 point values confirmed in plpredict-fastapi1's own Chapter 6 rather than asking the question fresh, and what that implies for any future variant in this same set.

📄 View solution
Exercise 2

Explain why utf8mb4 is the correct charset choice for the pl_predictor database instead of plain utf8, and why the OPTIONS charset setting in DATABASES needs to match it.

📄 View solution
Exercise 3

Set up the pl_predictor MySQL database and a working Django project connected to it yourself (using either mysqlclient or the PyMySQL alternative), confirm python manage.py migrate runs successfully, and write one sentence explaining what that command actually confirmed.

📄 View solution

Chapter 1 Quick Reference

  • The shared app — a weekly Premier League prediction tracker: 4 real prediction sources per fixture, scored 40/10/0, across a real 38-gameweek season
  • Real point values (confirmed) — 40 for a correct score, 10 for a correct result, reused directly from plpredict-fastapi1's own Chapter 6
  • Why this variant — Django's own ready-made admin as a fast tool for this project's genuinely heavy manual-entry workload, paired with MySQL
  • Flagged early — MySQL has no equivalent to PostgreSQL's partial unique index; Chapter 5 will need a genuinely different real fix for the same guest-prediction problem
  • Database — MySQL, created as pl_predictor with explicit utf8mb4 charset
  • Driver choice — mysqlclient (fast, needs real build tools) or PyMySQL (pure Python, easier install, slower under load)
  • Next chapter: Data Modeling — teams, seasons, gameweeks & fixtures as Django models