Skip to main content

NextORM

CI PyPI Python License Docs Discord

Modern Python ORM with async support, full type annotations and a generator-expression query DSL.

Features

  • Type-annotated fieldsPK[int], Req[str], Opt[str], Set[T], Single[T]
  • Auto-save sessions — create entities inside db_session and they are committed automatically
  • PonyORM-compatible DSL — generator-expression queries, Entity[pk], Entity.get(), lifecycle hooks
  • Full async supportAsyncDatabase, await db.aselect(...), Entity.aselect(), Entity.aget()
  • Built-in migrations CLInextorm makemigrations / nextorm migrate
  • Three providers — SQLite, PostgreSQL (psycopg3), MariaDB
  • 100% branch coverage enforced in CI

Installation

pip install nextorm[sqlite]        # SQLite (aiosqlite)
pip install nextorm[postgres]      # PostgreSQL (psycopg3)
pip install nextorm[mariadb]       # MariaDB (asyncmy + PyMySQL)
pip install "nextorm[sqlite,postgres,mariadb]"   # all drivers

Quick start

from nextorm import Database, Entity, PK, Req, Opt, Set, Single, db_session


# Define entities — no database coupling required
class Tag(Entity):
    name: Req[str]
    products: Set["Product"]  # many-to-many back-reference


class Product(Entity):
    name: Req[str] = Req(64)  # positional shorthand: max_len=64
    price: Req[float]
    sku: Req[str] = Req(column="product_sku", unique=True)  # marker-call options
    tags: Set[Tag]  # many-to-many
    summary: Opt[str]  # Opt[str]/[LongStr] use empty string for None by default


# Create and connect the database
db = Database(entities=[Tag, Product])  # entities can also be auto-discovered
db.bind("sqlite", ":memory:")
db.generate_mapping(create_tables=True)

# Write — entities are tracked and committed automatically
with db_session:
    t = Tag(name="sale")
    p = Product(name="Widget", price=9.99, sku="WGT-1")
    p.tags.add(t)
# ← INSERT fires here; p.id and t.id are now set

# Read — class-level shortcuts (no explicit db reference needed)
widgets = Product.select().filter(Product.price < 20).fetch_all()
widget = Product.get(name="Widget")  # None if not found
widget = Product[1]  # KeyError if not found

Async quick start

import asyncio
from nextorm import AsyncDatabase, Entity, PK, Req, db_session


class Task(Entity):
    title: Req[str]
    done: Req[bool]


async def main() -> None:
    db = AsyncDatabase(entities=[Task])
    await db.bind("sqlite", ":memory:")
    await db.generate_mapping(create_tables=True)

    async with db_session:
        Task(title="Buy milk", done=False)

    pending = await Task.aselect().filter(Task.done == False).fetch_all()
    task = await Task.aget(title="Buy milk")  # None if not found
    print(pending)


asyncio.run(main())

Migrations

nextorm makemigrations   # generate a migration from model changes
nextorm migrate          # apply pending migrations
nextorm showmigrations   # list migration history

Migrating from PonyORM

NextORM's API is intentionally close to PonyORM's. The main differences:

PonyORM NextORM
class Product(db.Entity) class Product(Entity)
Required(str) Req[str]
Optional(str) Opt[str]
PrimaryKey(int, auto=True) PK[int]
Required(Order) (FK side) Single[Order]
Set("Line") (back-reference) Set["Line"]
select(p for p in Product if ...) identical
Product[42] identical
Product.get(name="x") identical

See the migration guide for details.

Documentation

Full docs at nextorm.readthedocs.io.

Community

Questions, ideas, and feedback are welcome in the NextORM Discord community.

  • 💬 Get help with models, queries, relations, and async usage
  • 🧪 Share bug reports with minimal reproductions
  • 🧭 Discuss roadmap ideas and RFCs
  • 📝 Suggest docs improvements

Join here: https://discord.gg/PevUtddqCM

Development

pdm install
pdm test          # run tests
pdm coverage      # tests + branch coverage (must be 100%)
pdm typecheck     # pyright + mypy
pdm lint          # ruff
pdm format        # ruff format
pdm docs-html     # build Sphinx docs

Acknowledgements

NextORM's API design and query DSL are heavily inspired by PonyORM, created by Alexander Kozlovsky, Alexey Malashkevich and Alexander Tischenko, released under the Apache License 2.0.

NextORM is a new, independent implementation and shares no source code with PonyORM.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nextorm-0.4.1.tar.gz (321.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nextorm-0.4.1-py3-none-any.whl (171.9 kB view details)

Uploaded Python 3

File details

Details for the file nextorm-0.4.1.tar.gz.

File metadata

  • Download URL: nextorm-0.4.1.tar.gz
  • Upload date:
  • Size: 321.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: pdm/2.28.0 CPython/3.13.14 Linux/6.17.0-1020-azure

File hashes

Hashes for nextorm-0.4.1.tar.gz
Algorithm Hash digest
SHA256 e5f482929c5c194134ff87fb8717938c3abcda84a058308af65a90fa998564fa
MD5 d542c4cb40855b7cf3c7bec1b5d6def4
BLAKE2b-256 d9ec5dc33d2a34745fce7655b76981642783ee68fee02a453c894cdd294dc36e

See more details on using hashes here.

File details

Details for the file nextorm-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: nextorm-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 171.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: pdm/2.28.0 CPython/3.13.14 Linux/6.17.0-1020-azure

File hashes

Hashes for nextorm-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 aae233ffa2c9841f7f8a13f6b82ff19882c579901be2271248fd233f3dd7f33c
MD5 a9de07928af1e6d7d0f42703c6d103d1
BLAKE2b-256 55c39f28c286cb3bf5484d09a08ca244149217459750f077d6e7035cacfed5e4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page