Skip to main content

Nag-free PostgreSQL ORM

Project description

Coming Soon: A Python ORM That Treats You Like Its 2026

Alchemy is complex, but Idli is simple.

Have Some Idli

(Doesn't work yet)

$ pip install idli
$ uv add idli

Goals

  • Act as a simple data persistence & query layer for simple Python apps (typical CRUD apps).
  • Primarily support solo devs and small teams who iterate fast. Not intended for those who need 4 approvals to create a new column.
  • Be as declarative as possible.
  • Keep your data layer code minimal and elegant.
  • Manage as much database administration as possible within the application.
  • Handle migrations natively, with least nagging.
  • Be framework agnostic.
  • Support both sync and async.
  • Be well documented.

What Could It Be Like?

from datetime import datetime
import uuid

from idli import connect

db = connect('postgresql://user:pwd@localhost/somedb')


@db.Model
class Task:
    id: uuid.UUID = uuid.uuid7 # initialize with function value
    title: str
    description: str | None # nullable column because None is an allowed type
    status: str = 'todo' #  initialize with default value as 'todo'
    created: datetime = datetime.now
    updated: datetime | None


task = Task(
    title = "Ship this ORM", 
    description = "Before the year ends",
)
task.save()

# tomorrow
task = Task.select(title = "Ship this ORM").one()
task.status = 'doing'
task.save()

# few weeks later
task = Task.select(title = "Ship this ORM").one()
task.update(status = 'done') # using .update will update the status and save it.

# next year
pending_tasks = Task.select(status__neq='done')
for task in pending_tasks:
    print(task.title, ',', 'Pending Since:', datetime.now()-task.created)

Migrations

Apart from Django ORM, there is no other Python ORM that I know of that handles database migrations natively. Even with that, I'm too lazy to 'make migrations', check them into my VCS, run them, etc. It's okay be to lazy and prioritize other things in life. Hence, Idli will support auto-migrations for non-destructive migrations. Destructive migrations will have to be done by hand. Suppose the above data model has to be extended a few days later:

from datetime import datetime
import uuid

from idli import connect, PrimaryKey, Index

db = connect(
    'postgresql://user:pwd@localhost/somedb',
    sambar_dip = True # this will automatically create tables, columns, and indexes defined below
)


@db.Model
class Task:
    id: uuid.UUID = uuid.uuid7 # initialize with function value
    title: str
    description: str | None # nullable column because None is an allowed type
    status: str = 'todo' #  initialize with default value as 'todo'
    created: datetime = datetime.now
    updated: datetime | None
    owner: User # newly created column referencing another table

    __idli__ = [
        Index('owner', '-created') # newly created Index
    ]


@db.Model
class User: # new table
    username: str
    full_name: str
    email: str
    send_task_reminders: bool = False

    __idli__ = [
        PrimaryKey('username')
    ]

This is inspired from GORM for Golang:

NOTE: AutoMigrate will create tables, missing foreign keys, constraints, columns and indexes. It will change existing column’s type if its size, precision changed, or if it’s changing from non-nullable to nullable. It WON’T delete unused columns to protect your data. - (from GORM docs: https://gorm.io/docs/migration.html)

Async

import asyncio
from datetime import datetime
import uuid

from idli import async_connect

db = async_connect('postgresql://user:pwd@localhost/somedb')


@db.Model
class Task:
    id: uuid.UUID = uuid.uuid7 # initialize with function value
    title: str
    description: str | None # nullable column because None is an allowed type
    status: str = 'todo' #  initialize with default value as 'todo'
    created: datetime = datetime.now
    updated: datetime | None


async def main():
    task = Task(
        title = "Ship this ORM", 
        description = "Before the year ends",
    )
    await task.save()


asyncio.run(main())

Project details


Download files

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

Source Distribution

idli-0.2.6.tar.gz (29.0 kB view details)

Uploaded Source

Built Distribution

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

idli-0.2.6-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

Details for the file idli-0.2.6.tar.gz.

File metadata

  • Download URL: idli-0.2.6.tar.gz
  • Upload date:
  • Size: 29.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for idli-0.2.6.tar.gz
Algorithm Hash digest
SHA256 a54ce4a032577a9ee132e09c0a35e72070413d16f1866d5f59e8f8ee8d1cfe68
MD5 d7047850e23b8c58058f5794d969b36d
BLAKE2b-256 9fd466fa4c1ec6aa472b70a460593834c88e18cadae192bdd108e03e5030d949

See more details on using hashes here.

File details

Details for the file idli-0.2.6-py3-none-any.whl.

File metadata

  • Download URL: idli-0.2.6-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for idli-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 f3724ca6f564b47903bf4d3e139c6a748a94e0092697b9cdb2fbfadbd2f30e0d
MD5 5d80deef65e98adeffb52baef36ee1eb
BLAKE2b-256 c8519fc321d4466fd005f7d9f3f9882d19fbed9e50069db04f872dd7bd7b3ee5

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