Skip to content

Adding models

Auto-discovery

bluefox-core automatically imports any models.py or */models.py files in your project. No configuration needed — just define your models and they'll be picked up.

Define a model

Create a module directory with a models.py file:

# users/models.py
from sqlalchemy import Column, Integer, String, Boolean
from bluefox_core import BluefoxBase


class User(BluefoxBase):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True, nullable=False)
    name = Column(String, nullable=False)
    is_active = Column(Boolean, default=True)

Don't forget the __init__.py:

mkdir users
touch users/__init__.py

Add an API

Create users/api.py with a router — it's auto-mounted at /users:

from fastapi import APIRouter

router = APIRouter()


@router.get("/")
async def list_users():
    return {"users": []}

No need to touch main.py. The router is discovered and mounted automatically.

Generate a migration

make migrate-make name=add_users

This compares your models against the database and creates a migration file in migrations/versions/.

Apply the migration

make migrate

Or just run make dev — migrations run automatically on startup.

Mount in dev compose

To get hot reload for your new module, add a volume mount in docker-compose.dev.yml:

app:
  volumes:
    - ./main.py:/app/main.py
    - ./models.py:/app/models.py
    - ./items:/app/items
    - ./users:/app/users        # add this
    - ./migrations:/app/migrations

Cross-module relationships

Models can reference each other across modules:

# todos/models.py
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
from sqlalchemy.orm import relationship
from bluefox_core import BluefoxBase


class Todo(BluefoxBase):
    __tablename__ = "todos"

    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    done = Column(Boolean, default=False)
    owner_id = Column(Integer, ForeignKey("users.id"), nullable=False)

    owner = relationship("User", back_populates="todos")

As long as both modules have a models.py, they'll both be discovered.