A minimal hackathon starter template. You get the scaffolding and database wiring — you build the models, routes, and CSV loading logic.
Stack: Flask · Peewee ORM · PostgreSQL · uv
You need to work with around the seed files that you can find in MLH PE Hackathon platform. This will help you build the schema for the database and have some data to do some testing and submit your project for judging. If you need help with this, reach out on Discord or on the Q&A tab on the platform.
- uv — a fast Python package manager that handles Python versions, virtual environments, and dependencies automatically.
Install it with:
For other methods see the uv installation docs.
# macOS / Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows (PowerShell) powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
- PostgreSQL running locally (you can use Docker or a local instance)
uv manages your Python version, virtual environment, and dependencies automatically — no manual python -m venv needed.
| Command | What it does |
|---|---|
uv sync |
Install all dependencies (creates .venv automatically) |
uv run <script> |
Run a script using the project's virtual environment |
uv add <package> |
Add a new dependency |
uv remove <package> |
Remove a dependency |
# 1. Clone the repo
git clone <repo-url> && cd mlh-pe-hackathon
# 2. Install dependencies
uv sync
# 3. Create the database
createdb hackathon_db
# 4. Configure environment
cp .env.example .env # edit if your DB credentials differ
# 5. Run the server
uv run run.py
# 6. Verify
curl http://localhost:5000/health
# → {"status":"ok"}mlh-pe-hackathon/
├── app/
│ ├── __init__.py # App factory (create_app)
│ ├── database.py # DatabaseProxy, BaseModel, connection hooks
│ ├── models/
│ │ └── __init__.py # Import your models here
│ └── routes/
│ └── __init__.py # register_routes() — add blueprints here
├── .env.example # DB connection template
├── .gitignore # Python + uv gitignore
├── .python-version # Pin Python version for uv
├── pyproject.toml # Project metadata + dependencies
├── run.py # Entry point: uv run run.py
└── README.md
- Create a file in
app/models/, e.g.app/models/product.py:
from peewee import CharField, DecimalField, IntegerField
from app.database import BaseModel
class Product(BaseModel):
name = CharField()
category = CharField()
price = DecimalField(decimal_places=2)
stock = IntegerField()- Import it in
app/models/__init__.py:
from app.models.product import Product- Create the table (run once in a Python shell or a setup script):
from app.database import db
from app.models.product import Product
db.create_tables([Product])- Create a blueprint in
app/routes/, e.g.app/routes/products.py:
from flask import Blueprint, jsonify
from playhouse.shortcuts import model_to_dict
from app.models.product import Product
products_bp = Blueprint("products", __name__)
@products_bp.route("/products")
def list_products():
products = Product.select()
return jsonify([model_to_dict(p) for p in products])- Register it in
app/routes/__init__.py:
def register_routes(app):
from app.routes.products import products_bp
app.register_blueprint(products_bp)import csv
from peewee import chunked
from app.database import db
from app.models.product import Product
def load_csv(filepath):
with open(filepath, newline="") as f:
reader = csv.DictReader(f)
rows = list(reader)
with db.atomic():
for batch in chunked(rows, 100):
Product.insert_many(batch).execute()from peewee import fn
from playhouse.shortcuts import model_to_dict
# Select all
products = Product.select()
# Filter
cheap = Product.select().where(Product.price < 10)
# Get by ID
p = Product.get_by_id(1)
# Create
Product.create(name="Widget", category="Tools", price=9.99, stock=50)
# Convert to dict (great for JSON responses)
model_to_dict(p)
# Aggregations
avg_price = Product.select(fn.AVG(Product.price)).scalar()
total = Product.select(fn.SUM(Product.stock)).scalar()
# Group by
from peewee import fn
query = (Product
.select(Product.category, fn.COUNT(Product.id).alias("count"))
.group_by(Product.category))- Use
model_to_dictfromplayhouse.shortcutsto convert model instances to dictionaries for JSON responses. - Wrap bulk inserts in
db.atomic()for transactional safety and performance. - The template uses
teardown_appcontextfor connection cleanup, so connections are closed even when requests fail. - Check
.env.examplefor all available configuration options.