Skip to main content

FasORM

Laravel Eloquent-style ORM for FastAPI — expressive models, clean migrations, and an artisan-style CLI, powered by SQLAlchemy 2.0 & Alembic.

📖 Documentation: https://fasorm.sandeshsatyal.com.np

pip install fasorm

Quick Start

1. Initialise your project

fasorm init

Creates:

app/
    models/
    migrations/
    seeders/
.env
fasorm.config.py

2. Create a model

fasorm make:model User -m

Edit app/models/user.py:

from fasorm import Model, String, Boolean

class User(Model):
    name = String()
    email = String().unique()
    password = String()
    is_active = Boolean().default(True)

3. Edit the migration

app/migrations/2026_07_25_143000_create_users_table.py:

from fasorm.schema import Blueprint

def up(table: Blueprint):
    table.id()
    table.string("name")
    table.string("email").unique()
    table.string("password")
    table.boolean("is_active").default(True)
    table.timestamps()

def down(table: Blueprint):
    table.drop()

4. Run migrations

fasorm migrate
  FasORM  ·  Running migrations…

  3 migration(s) pending…

  ✅  2026_07_25_143000_create_users_table

  ✓  Migration successful. 1 migration(s) applied.

Models

Define a model

from fasorm import Model, String, Boolean, Timestamp, HasMany

class User(Model):
    name = String()
    email = String().unique()
    is_active = Boolean().default(True)
    posts = HasMany("Post")

Features:

  • Auto-generated id (BigInteger, autoincrement)
  • Auto-generated created_at and updated_at timestamps
  • Auto-generated __tablename__ from class name (User → users, BlogPost → blog_posts)

CRUD Operations

# Create
user = await User.create(name="Sandy", email="sandy@example.com")

# Find by ID
user = await User.find(1)
user = await User.find_or_fail(1)  # raises ModelNotFoundError

# Query
users = await User.where(is_active=True).get()
user = await User.where(email="sandy@example.com").first()
users = await User.where("age", ">=", 18).order_by("name").get()

# All
users = await User.all()

# Paginate
page = await User.paginate(per_page=20, page=1)

# Update
await user.update(name="New Name")

# Delete
await user.delete()

# First or create
user = await User.first_or_create(
    {"email": "sandy@example.com"},
    defaults={"name": "Sandy"}
)

# Update or create
user = await User.update_or_create(
    {"email": "sandy@example.com"},
    defaults={"name": "Updated Sandy"}
)

Relationships

from fasorm import Model, String, HasMany, BelongsTo

class User(Model):
    name = String()
    posts = HasMany("Post")

class Post(Model):
    title = String()
    user = BelongsTo("User")

# Eager loading (loaded relations are automatically included in to_dict / to_json)
users = await User.with_("posts").get()
total = await User.with_("posts").where(is_active=True).count()

# Relationship count aggregation (adds `posts_count` attribute)
users = await User.with_count("posts").get()
print(users[0].posts_count)  # → 3
users_dict = await User.with_count("posts").to_dict()  # → [{"id": 1, "name": "Sandy", "posts_count": 3}]

# Aggregates & Model classmethods
count = await User.count()
exists = await User.where(email="sandy@example.com").exists()
total_age = await User.sum("age")
avg_age = await User.avg("age")

Serialisation

# Model instance serialisation (automatically includes eager-loaded relations)
user.to_dict()   # → {"id": 1, "name": "Sandy", "posts": [...]}
user.to_json()   # → '{"id": 1, "name": "Sandy", "posts": [...]}'

# Direct query builder serialisation
users_dict = await User.with_("posts").to_dict()
users_json = await User.with_("posts").to_json()

# Pagination result serialisation
page = await User.paginate(per_page=20, page=1)
page.to_dict()   # → {"data": [...], "meta": {"total": 100, ...}}

Field Types

Field SQL Type Notes
String(length=255) VARCHAR(n)
Char(length=255) CHAR(n) Fixed-length string
Text() TEXT
TinyText() TINYTEXT / TEXT
MediumText() MEDIUMTEXT / TEXT
LongText() LONGTEXT / TEXT
Integer() INTEGER
BigInteger() BIGINT
SmallInteger() SMALLINT
TinyInteger() TINYINT / SMALLINT
MediumInteger() MEDIUMINT / INTEGER
UnsignedInteger() UNSIGNED INT
UnsignedBigInteger() UNSIGNED BIGINT
UnsignedSmallInteger() UNSIGNED SMALLINT
UnsignedTinyInteger() UNSIGNED TINYINT
Float(precision) FLOAT
Decimal(precision, scale) NUMERIC(p,s)
Boolean() BOOLEAN
Date() DATE
Time() TIME
TimeTz() TIME WITH TZ Timezone aware
DateTime() DATETIME
DateTimeTz() DATETIME WITH TZ Timezone aware
Timestamp() TIMESTAMP WITH TZ Timezone aware
TimestampTz() TIMESTAMP WITH TZ Timezone aware
Year() YEAR / INTEGER
Json() JSON / JSONB
Jsonb() JSONB / JSON Native on PG
Uuid() UUID / CHAR(36) Native on PG
Ulid() CHAR(26) 26-char sortable ID
IpAddress() VARCHAR(45) IP Address
MacAddress() VARCHAR(17) MAC Address
Enum(values) ENUM
Set(values) SET / ENUM Set of values
Vector(dimension) VECTOR(n) / TEXT pgvector on PG
Array(item_type) ARRAY / JSON Native on PG
Binary(length) LARGEBINARY

All fields support chaining: .nullable(), .unique(), .default(value), .index(), .comment(text)


CLI Commands

Command Description
fasorm init Scaffold project structure
fasorm make:model Name [-m] Create a model (optionally with migration)
fasorm make:migration name Create a migration file
fasorm make:seeder Name Create a seeder file
fasorm migrate Run pending migrations
fasorm rollback [--steps N] Rollback last N batches
fasorm refresh Rollback all + re-migrate
fasorm fresh [--seed] Drop all + migrate + seed
fasorm seed [--class Name] Run seeders
fasorm status Show migration status

FastAPI Integration

from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from fasorm import get_session, init_db
from fasorm.config import load_config

app = FastAPI()

@app.on_event("startup")
async def startup():
    config = load_config()
    init_db(config)

@app.get("/users")
async def list_users():
    users = await User.all()
    return [u.to_dict() for u in users]

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    user = await User.find_or_fail(user_id)
    return user.to_dict()

Architecture

                FastAPI
                   │
                FasORM
                   │
          ─────────┼─────────
          │                 │
      SQLAlchemy         Alembic
          │                 │
      PostgreSQL          SQLite
      MySQL               MariaDB

FasORM is an opinionated layer on top of SQLAlchemy 2.0 and Alembic — not a replacement.


License

MIT

Metadata

Release files for fasorm 0.1.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fasorm 0.1.11
File Size Uploaded
fasorm-0.1.11.tar.gz 43.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fasorm 0.1.11
File Interpreter ABI Platform
fasorm-0.1.11-py3-none-any.whl Python 3 none any Details

Total release size: 88.0 kB

Release files / fasorm-0.1.11.tar.gz

Download URL fasorm-0.1.11.tar.gz
Size 43.1 kB
Tags Source
SHA-256 checksum
How to use checksums
899655287171c1de13f99234e216c27f53b5b5ddce4bbfabb3e0c020ad0b10dc
BLAKE2b-256 checksum
How to use checksums
311347724967ef6b339d8476290503f0cd7e6cff232cca7981fb734dc6ecb568
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / fasorm-0.1.11-py3-none-any.whl

Download URL fasorm-0.1.11-py3-none-any.whl
Size 44.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f9fd103940261e790125ed3a1f5a4e7d32bce9433d221f948db5cb6029b472e1
BLAKE2b-256 checksum
How to use checksums
0dcefaf191307e33aad2dfdcdd0d1c4f42c29dd8ad6504f5e5acf47cc93cd699
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

0.1.11 This release

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page