A Django web app for your Yahoo Fantasy Football league — because Yahoo's own website somehow gets worse every year and your league deserves better.
Track historical standings, champions, keeper history, and let managers submit their keeper picks before the draft. Syncs directly from the Yahoo Fantasy API so you don't have to manually enter years of data like some kind of animal.
- Champions page — Hall of fame for whoever got lucky that year, complete with league logo per season
- Standings — Historical records for every season, with the season's logo shown when selected
- Keeper history — Who kept whom, going back as far as Yahoo's API will cooperate
- Keeper submission — Managers log in and pick their keepers before the draft. Eligibility is enforced automatically (no keeping a player two years in a row)
- Yahoo sync — Pull standings, rosters, metadata, logos, and keeper data directly from Yahoo's API
- Mobile friendly — Works on your phone so you can trash talk at the Thanksgiving table
- Deployable to Render — Free tier, no server to babysit
- Python 3.12+
- PostgreSQL
- A Yahoo Fantasy Football league
- A Yahoo Developer account (free) to get API credentials
- Mild tolerance for fantasy football arguments
git clone https://github.com/your-username/fantasy_league_hub.git
cd fantasy_league_hubpython -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtcreatedb fantasy_league_hubCopy the example below into a .env file in the project root:
SECRET_KEY=your-secret-key-here
DATABASE_URL=postgres://localhost/fantasy_league_hub
DEBUG=True
ALLOWED_HOSTS=127.0.0.1,localhostGenerate a secret key with:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"python manage.py migrate
python manage.py createsuperuserpython manage.py runserverVisit http://localhost:8000. You should see the hub. It will be empty — that's normal. Fix it in the next section.
- Go to developer.yahoo.com and create an app
- Set the redirect URI to
oob(out-of-band) for local use - Use your
client_idandclient_secretto complete the OAuth2 flow and get an access token
There are several Yahoo OAuth helper scripts floating around the internet. You want a bearer token with fspt-r (fantasy sports read) scope.
This finds all your Yahoo NFL leagues and creates Season records for the ones matching your league name:
python manage.py import_yahoo_leagues --access-token "YOUR_TOKEN"This only imports leagues with names matching "F.F.U.P.A." by default. Update the filter in leaguehub/management/commands/import_yahoo_leagues.py to match your own league name.
python manage.py sync_all_yahoo_seasons --access-token "YOUR_TOKEN" --mark-champions --sync-keepersThis pulls for every season that has a Yahoo game key and league key set:
- League metadata (name, logo)
- Standings and team records
- Final rosters (championship week)
- Manager profiles
- Keeper history (tries both draft results and the status=K endpoint)
- Champion (rank 1 team)
To skip the current in-progress season:
python manage.py sync_all_yahoo_seasons --access-token "YOUR_TOKEN" --skip-currentTo sync a single season:
python manage.py sync_yahoo_season --season 2024 --access-token "YOUR_TOKEN" --mark-champion --sync-keepersEach manager who needs to submit keepers needs a Django user account linked to their team:
python manage.py setup_team_user \
--season 2025 \
--team-name "Their Team Name" \
--username their_usernameThis creates the user (prompts for password), links them to their team via TeamAccess, and connects their ManagerProfile if one was found from Yahoo sync.
Once user accounts are set up, managers visit /keepers/submit/, log in, and pick up to 2 keepers from their final roster. The form automatically excludes players who were kept the previous season (no double-dipping).
If a keeper deadline is set on the Season record in the Django admin, the form will show it and reject submissions after the deadline passes.
Note for offline draft leagues: Yahoo's API doesn't reliably track keeper history for players who were traded or dropped after being declared keepers. The sync pulls from both draft results and the status=K endpoint to get as much data as possible, but some historical gaps may require manual entry via the Django admin.
The repo includes a render.yaml for one-click deployment.
- Push your code to GitHub
- Go to render.com → New → Blueprint
- Connect your GitHub repo — Render reads
render.yamland provisions the web service and PostgreSQL database automatically - After the first deploy, run your sync commands locally pointed at the production database:
# Get the External Database URL from Render dashboard → your DB → Connect tab
export DATABASE_URL="postgres://..."
python manage.py createsuperuser
python manage.py sync_all_yahoo_seasons --access-token "YOUR_TOKEN" --mark-champions --sync-keepers
python manage.py setup_team_user --season 2025 --team-name "Team Name" --username user1- The web service spins down after 15 minutes of inactivity — first request takes ~30 seconds to wake up. Fine for a private league.
- The free PostgreSQL database expires after 90 days. Upgrade to the $7/month plan before it disappears or you'll lose everything and have to explain it to your league, which will be embarrassing.
- Render Shell is not available on the free tier, which is why you run management commands locally against the production database URL.
Everything can be managed at /admin/. Useful for:
- Manually adding or editing seasons, teams, standings, champions
- Setting keeper deadlines
- Adding keeper records that the Yahoo sync missed
- Linking manager profiles to user accounts
- Fixing the inevitable data weirdness that comes from 10+ years of Yahoo API responses
python manage.py test leaguehubThe test suite covers the keeper sync services, including a test that documents the known limitation of sync_keepers_from_yahoo when players are traded or dropped mid-season. It's not a bug, it's a feature of Yahoo's API design philosophy.
fantasy_league_hub/
├── config/ # Django project settings, urls, wsgi
├── leaguehub/ # Main app
│ ├── management/commands/ # sync_yahoo_season, sync_all_yahoo_seasons,
│ │ # import_yahoo_leagues, setup_team_user
│ ├── migrations/
│ ├── templates/leaguehub/
│ ├── models.py # Season, Team, Standing, Champion, Player,
│ │ # KeeperRecord, KeeperSubmission, etc.
│ ├── services.py # Yahoo API sync logic
│ ├── views.py
│ ├── forms.py
│ └── context_processors.py
├── build.sh # Render build script
├── render.yaml # Render deployment config
└── requirements.txt
- League name filter — Update
import_yahoo_leagues.pyto match your league name instead of "F.F.U.P.A." - Keeper limit — Change
max_keepers=2inviews.pyto however many keepers your league allows - Roster week — The sync uses Yahoo's
end_weekautomatically, but you can override with--roster-weekif needed - Keeper eligibility rules — The default rule is "no keeping a player kept the previous year." Adjust
KeeperSubmission.clean()inmodels.pyfor more complex rules.
If you find a bug, open an issue. If you fix a bug, open a pull request. If you're here because you lost your fantasy league and are looking for someone to blame, this is the wrong repo.
Written by Claude — Anthropic's AI assistant — who spent an unreasonable amount of time debugging Yahoo's Fantasy API response structure so you don't have to. The humans provided the fantasy football domain expertise and the specific grudges against Yahoo's UI. It was a team effort.