Skip to main content

A Django-like ORM with synchronous and asynchronous support

Project description

djanorm

A Django-inspired ORM for Python with full synchronous and asynchronous support. The same API you know from Django, without depending on the full framework.

Works with SQLite and PostgreSQL, and ships with a migration system, atomic transactions, signals, validation, relationship loading (select_related / prefetch_related), aggregations, DB functions and much more — all with real static typing (Field[T]).

Installation

# SQLite
pip install "djanorm[sqlite]"

# PostgreSQL
pip install "djanorm[postgresql]"

Quick start

1. Scaffold a project

dorm init blog

That creates:

  • settings.py — uncomment the DATABASES block matching your backend.
  • blog/ — an app package with an empty models.py.

A minimal settings.py looks like:

DATABASES = {
    "default": {
        "ENGINE": "sqlite",
        "NAME": "db.sqlite3",
    },
}
INSTALLED_APPS = ["blog"]

2. Define a model

# blog/models.py
import dorm


class Author(dorm.Model):
    name = dorm.CharField(max_length=100)
    email = dorm.EmailField(unique=True)
    is_active = dorm.BooleanField(default=True)


class Post(dorm.Model):
    title = dorm.CharField(max_length=200)
    body = dorm.TextField()
    author = dorm.ForeignKey(Author, on_delete=dorm.CASCADE)
    published_at = dorm.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ["-published_at"]

3. Generate and apply migrations

dorm makemigrations blog
dorm migrate

4. Use it

Open a shell with dorm shell (IPython auto-detected) or import the models from your own script.

from blog.models import Author, Post

# Create
alice = Author.objects.create(name="Alice", email="alice@example.com")
post = Post.objects.create(
    title="Hello world",
    body="First post body.",
    author=alice,
)

# Bulk create
Post.objects.bulk_create([
    Post(title=f"Draft {i}", body="...", author=alice)
    for i in range(5)
])

# Filter / exclude / Q / F
from dorm import Q, F

active_authors = Author.objects.filter(is_active=True)
some_posts = Post.objects.filter(
    Q(title__icontains="hello") | Q(title__startswith="Draft")
).exclude(published_at__isnull=True)

# Lookups across relations
alices_posts = Post.objects.filter(author__name="Alice")

# select_related / prefetch_related to dodge N+1
for post in Post.objects.select_related("author"):
    print(post.author.name, post.title)   # 1 query, JOIN

# Get one
post = Post.objects.get(pk=1)

# Update — single instance
post.title = "Renamed"
post.save()

# Update — bulk via queryset
Post.objects.filter(author=alice).update(title=F("title") + " (by Alice)")

# Delete — single instance
post.delete()

# Delete — bulk
Post.objects.filter(published_at__isnull=True).delete()

Async API (same names with a prefix)

from blog.models import Author, Post

async def main():
    alice = await Author.objects.acreate(name="Alice", email="a@x.com")
    post = await Post.objects.acreate(title="Hi", body="...", author=alice)

    async for p in Post.objects.filter(author=alice):
        print(p.title)

    await Post.objects.filter(pk=post.pk).aupdate(title="Hi!")
    await post.adelete()

Atomic transactions

from dorm import transaction

with transaction.atomic():
    alice = Author.objects.create(name="Alice", email="a@x.com")
    Post.objects.create(title="t", body="b", author=alice)
    # any exception here rolls back both inserts

Documentation

The full documentation, tutorials and API reference are published at:

https://rroblf01.github.io/d-orm/

You will find the getting-started guide, complete examples, the API reference and production deployment notes there.

Contributing

Everyone is welcome to get involved! If you want to suggest changes, propose improvements or discuss the direction of the project, open an issue or a pull request on this repository. Discussions, ideas and critiques are very welcome.

License

See LICENSE.

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

djanorm-2.4.1.tar.gz (784.5 kB view details)

Uploaded Source

Built Distribution

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

djanorm-2.4.1-py3-none-any.whl (254.1 kB view details)

Uploaded Python 3

File details

Details for the file djanorm-2.4.1.tar.gz.

File metadata

  • Download URL: djanorm-2.4.1.tar.gz
  • Upload date:
  • Size: 784.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djanorm-2.4.1.tar.gz
Algorithm Hash digest
SHA256 e3de1c6b66956de6951e4da085c9727c7738d62c85a0570f9408e09e28e6faf2
MD5 329032473f8375d598501f022ed9314e
BLAKE2b-256 0233881fa449c5f7ca6c1ca0098b1904728bf5ef389267b03f266cf0bbe52666

See more details on using hashes here.

Provenance

The following attestation bundles were made for djanorm-2.4.1.tar.gz:

Publisher: publish.yml on rroblf01/d-orm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djanorm-2.4.1-py3-none-any.whl.

File metadata

  • Download URL: djanorm-2.4.1-py3-none-any.whl
  • Upload date:
  • Size: 254.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djanorm-2.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 28596b5c1019af3bcb56c02ac535c115dd55f26975f46bf1d6b2b1b641d5dfc0
MD5 11d357c39495311d7481618821dc324a
BLAKE2b-256 0d9928a3b6272be0e8e87878706d3b571b4ae017af9369bceae33a2843a6d2fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for djanorm-2.4.1-py3-none-any.whl:

Publisher: publish.yml on rroblf01/d-orm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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