QDG Knowledge Base Read-only viewer QWebHub
overview

Overview

Version 1 · Initial project documentation created from CLAUDE.md, PLAN.md, and README.md

Historical version

Runner Form

A Django horse-racing form viewer. Users log in and browse runner (horse), jockey, and trainer profiles with race-by-race history and computed career stats.

Purpose

Entity URL pattern What it shows
Runner (horse) /form/runner/<horse_id>/ Past runs, career stats, brief or detailed tab (?tab=brief|detailed, ?date=, ?race=)
Jockey /form/jockey/<jockey_id>/ Ride history, strike-rate, top runners/trainers
Trainer /form/trainer/<trainer_id>/ Training history, strike-rate breakdowns

The index route (/form/runner/) redirects to a default example horse.

Architecture

Browser
  │ HTTP GET/POST
  ▼
views.py            HTTP handlers, @custom_login_required decorator
  │
  ▼
queries.py          raw SQL via django.db.connection, no ORM models
  │
  ▼
MySQL "qdg" DB (138.226.220.168:3306)
  tables: runner, run, race, meeting, jockey, trainers, courses, country,
          trial_race, trial_run
  │
  ▼
Django Templates (.html) + static CSS/JS

There is no Django ORM — all DB access is raw SQL via django.db.connection inside queries.py. The two helpers _fetchall(sql, params) and _fetchone(sql, params) return list[dict] / dict.

Components

  • config/settings.py — DB config, installed apps, cache, static files.
  • runner_form/queries.py — all SQL queries and Python-side stats computation.
  • runner_form/views.py — HTTP handlers + @custom_login_required decorator.
  • runner_form/urls.py — app routes, mounted at /form/ by config/urls.py.
  • runner_form/templates/runner_form/ — login.html, brief-form.html, detailed-form.html (largest template), jockey_form.html, trainer_form.html, error.html.
  • runner_form/static/runner_form/ — single stylesheet css/runner_form.css; minimal js/runner_form.js (click-to-toggle notes/stewards row on past-run rows). Heavier interactions (pagination, read-more, race picker) are inline <script> blocks inside detailed-form.html.

Data layer patterns

  • get_runner_form_data(horse_id) — horse + runs + stats, cached 120s.
  • get_jockey_form_data(jockey_id) — jockey + rides + stats.
  • get_trainer_form_data(trainer_id) — trainer + entries + stats.
  • get_trial_runs(horse_id) — barrier trial data from trial_race / trial_run.
  • search_form(q) — searches horses / meetings / races by name, cached 120s.
  • get_available_dates() — race dates for the date-picker, cached 300s.
  • _normalise_runs(rows) — adds display_* keys + computed flags (is_winner, is_placed, gear_list).
  • compute_stats(runs) — career/last5/by-distance/by-track/by-class aggregations.
  • Cache key pattern: runner_form:<entity>:<id>, Django's default in-memory (per-process) cache backend.

JSON API (used by the templates' date/meeting/race picker via fetch())

/form/api/dates/                     → available race dates
/form/api/meetings/?date=            → venues for a date
/form/api/races/?date=&meeting=      → races for a meeting
/form/api/runners/?race_id=          → runners in a race
/form/api/search/?q=                 → search across horses, meetings, races

Authentication

Custom session auth, not Django's built-in auth system. Login is a hard-coded admin / dev password check in views.py; the @custom_login_required decorator checks request.session['is_authenticated']. Must be replaced before production — see [[bugs]].

Development

.\venv\Scripts\Activate.ps1
python manage.py runserver
# http://127.0.0.1:8000/

Hard-refresh (Ctrl+Shift+R) after static file changes to bypass the browser cache.

Stack: Django, MySQL (remote, no ORM), Django Templates, vanilla JS. Environment: Windows 11, Python venv, IIS/wFastCGI in production.

Known data gaps

trial_race.class_level, sot, and time_winner_sec are NULL for every row in the current DB — these fields display as — until the source data is populated. run.vp_* sectional columns (vp_1200/800/600/400/200) are NULL for pre-2021 races; the app falls back to run.pos_1200, run.pos_800, run.pos_turn, run.pos_settling.

See [[quick-reference]] for routes and commands, and [[bugs]] for open issues and production hardening items.

Updated by Claude on Aug. 12, 2026, 9:35 a.m. · Task: create project documentation