A Django-based web application for managing and participating in DataTalks.Club courses.
The platform supports course administration, homework and project submissions, peer review workflows, course leaderboards, and API access to course data.
- User authentication: registration and login for students and instructors.
- Course management: instructors can create and manage courses.
- Homework and projects: students can submit homework and projects.
- Peer reviews: students can evaluate project submissions from their peers.
- Leaderboard: course rankings based on submitted work and scores.
- API access: authenticated endpoints for course, homework, project, graduate, certificate, and OpenAPI data.
- Health check: a public endpoint for service monitoring.
├── accounts/ # User accounts and authentication
├── api/ # OpenAPI schema and API tests
├── cadmin/ # Custom admin views
├── course_management/ # Django project settings and root configuration
├── courses/ # Course, homework, project, and review logic
├── data/ # Public and authenticated data API views
├── deploy/ # Deployment scripts
├── docs/ # Project documentation
├── notebooks/ # Analysis notebooks
├── templates/ # Shared Django templates
- Python 3.13
- uv
- Docker and Docker Compose, for containerized local development
Install uv with the official installer:
curl -LsSf https://astral.sh/uv/install.sh | shInstall Python 3.13 and project dependencies:
uv python install 3.13
uv sync --devUse SQLite for local development:
export DATABASE_URL="sqlite:///db/db.sqlite3"Prepare the database:
make migrationsCreate an admin user:
make adminLoad sample data:
make dataRun the development server:
make runThe app will be available at:
http://localhost:8000
Useful direct Django commands:
uv run python manage.py makemigrations
uv run python manage.py migrate
uv run python manage.py createsuperuser
uv run python manage.py runserver 0.0.0.0:8000Run the Django test suite:
make testsDirect command:
uv run python manage.py test --timing --durations 30One-time scripts and temporary debug files should go in .tmp/, which is
ignored by git.
Start the app and PostgreSQL with Docker Compose:
docker-compose up --buildCompose starts:
web: the Django application on port 8000db: PostgreSQL 17ngrok: optional TCP tunnel for the database
The app will be available at:
http://localhost:8000
Build and run the application image without Compose:
docker build -t course_management .DBDIR=`cygpath -w ${PWD}/db`
docker run -it --rm \
-p 8000:80 \
--name course_management \
-e DATABASE_URL="sqlite:////data/db.sqlite3" \
-e SITE_ID="${SITE_ID}" \
-v ${DBDIR}:/data \
course_managementOpen a shell in the running container:
docker exec -it course_management bashThe public health check endpoint returns service status and version:
GET /api/health/
Example:
curl http://localhost:8000/api/health/Response:
{
"status": "ok",
"version": "0.1.0"
}In local development, the version comes from the VERSION environment
variable and falls back to local-development-build-version-not-configured.
Most /api endpoints require token authentication:
Authorization: Token <token>
Example:
TOKEN="TEST_TOKEN"
HOST="http://localhost:8000"
COURSE="fake-course"
HOMEWORK="hw1"
curl \
-H "Authorization: Token ${TOKEN}" \
"${HOST}/api/courses/${COURSE}/homeworks/${HOMEWORK}/submissions"Run make data to create sample data, including an authentication token.
See endpoints.md for API documentation, including:
- OpenAPI specification
- Public course criteria
- Public health check
- Public leaderboard data
- Homework data
- Project data
- Graduate data
- Certificate updates
- Course management API
OAuth is optional for local testing.
To configure Google OAuth locally:
- Go to the admin panel at
http://localhost:8000/admin. - Add a record to
Sites. - Use
localhost:8000for the display name and domain name. - Note the site ID, usually
2. - Add a record to
Social applications. - Use
GoogleDTCas the name andGoogleas the provider. - Ask for the local OAuth keys. Do not share them publicly.
- Attach the application to the localhost site.
Export the local site ID:
export SITE_ID=2Restart the app:
uv run python manage.py runserver 0.0.0.0:8000Then log out as admin and log in with Google.
Example SSH config for an RDS tunnel:
Host bastion-tunnel
HostName <IP>
User ubuntu
IdentityFile c:/Users/alexe/.ssh/<KEY>.pem
LocalForward 5433 dev-course-management-cluster.cluster-cpj5uw8ck6vb.eu-west-1.rds.amazonaws.com:5432
ServerAliveInterval 60
Connect to the bastion:
ssh bastion-tunnelConnect to PostgreSQL through the tunnel:
pgcli -h localhost -p 5433 -u pgusr -d coursemanagementWhen connecting for the first time, create the dev and prod databases:
CREATE DATABASE dev;
CREATE DATABASE prod;Open a Django shell against dev:
export DATABASE_URL="postgresql://pgusr:${DB_PASSWORD}@localhost:5433/dev"
export SECRET_KEY="${DJANGO_SECRET}"
uv run python manage.py shellOpen a Django shell against prod:
export DATABASE_URL="postgresql://pgusr:${DB_PASSWORD}@localhost:5433/prod"
export SECRET_KEY="${DJANGO_SECRET}"
uv run python manage.py shellFind a user by email:
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.get(email="test@gmail.com")