A database-first ORM for PostgreSQL
Project description
halfORM
⚠️ BREAKING CHANGES in v1.0.0
ho_get()is now public and returns adictdirectly. It raisesNotFoundError(0 rows) orMultipleRowsError(> 1 row) instead of counting first.Deprecated query-builder setters removed —
ho_limit,ho_offset,ho_order_by,ho_distinctno longer exist as setters. Pass these as keyword arguments toho_select():# Before (0.x) rel.ho_limit = 10 rel.ho_order_by = 'name' list(rel) # After (1.0) list(rel.ho_select(limit=10, order_by='name'))
FKEYS_PROPERTIES/FKEYSclass attributes removed — useFkeysonly.
ho_cast()now raisesCastErrorif the target is not in the PostgreSQL inheritance hierarchy of the relation.See CHANGELOG.md for the full list of changes.
halfORM is a database-first ORM for PostgreSQL. Your schema lives in the database; halfORM introspects it at runtime and gives you Python objects to work with your data. No migrations, no code generation.
The central idea: a Relation object is a predicate. It describes the
logical condition that rows must satisfy to belong to the relation. Its
extension — the set of rows currently satisfying the predicate in the
database — is what you read, update, or delete.
Key features
- Database-first — the schema lives in PostgreSQL, not in Python classes.
- Predicate model — relations are predicates; set operators (
|,&,-) compose them before any SQL is sent. - FK navigation — join across tables (and views) by setting FK attributes;
explicit
Fkeysdict for views where PostgreSQL stores no FK metadata. - Sync + async — every executor has an
a-prefixed async counterpart (ho_aselect,ho_ainsert, …). - Bulk load —
ho_copy/ho_acopyfor high-throughput inserts via PostgreSQLCOPY. - No magic — queries are built from the predicate you describe and executed
only when you call an executor.
ho_mogrify()shows the exact SQL.
Install
pip install half_orm
Requires psycopg 3 (psycopg[binary]).
Configure
# ~/.half_orm/blog
[database]
name = blog
user = alice
password = secret
host = localhost
Usage
from half_orm.model import Model
from half_orm.relation_errors import NotFoundError, MultipleRowsError
blog = Model('blog')
Post = blog.get_relation_class('blog.post')
Author = blog.get_relation_class('blog.author')
# Insert — returns the inserted row as a dict
alice = Author(
first_name='Alice', last_name='Martin', email='alice@example.com'
).ho_insert()
# Query — Author(last_name='Martin') is a predicate, not a query
for row in Author(last_name='Martin').ho_select('id', 'email'):
print(row)
# Get exactly one row
try:
author = Author(last_name='Martin').ho_get()
except NotFoundError:
print("no such author")
except MultipleRowsError:
print("ambiguous — more than one author named Martin")
# FK navigation — no JOIN written by hand
post = Post(id=1)
post.author_fk.set() # join all authors
for row in post.ho_select(json_agg={'author_fk': ['first_name', 'last_name']}):
print(row['author_fk']) # {'first_name': 'Alice', 'last_name': 'Martin'}
# Set operators — compose predicates before hitting the database
recent = Post(created_at=('>', '2024-01-01'))
featured = Post(featured=True)
combined = recent | featured # UNION
print(combined.ho_count())
# Update / delete
Author(id=alice['id']).ho_update(email='alice@newdomain.com')
Author(id=alice['id']).ho_delete()
Documentation
Extensions
| Extension | Description |
|---|---|
| half-orm-dev | Development tools — half_orm dev project scaffolding, patch management, and schema synchronisation. |
License
halfORM is licensed under the GPL-3.0 license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file half_orm-1.0.0rc6.tar.gz.
File metadata
- Download URL: half_orm-1.0.0rc6.tar.gz
- Upload date:
- Size: 74.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45fc2571966e7510076d97d9f84e779b3d9770e658d4e4e541106f3e5f091a0a
|
|
| MD5 |
22261431fe19cdc5115458fc3579aebc
|
|
| BLAKE2b-256 |
7c4faa1d5ffb5db1ba442ea5b6e45c016930ba0f2719cc112952a5571a9eac51
|
File details
Details for the file half_orm-1.0.0rc6-py3-none-any.whl.
File metadata
- Download URL: half_orm-1.0.0rc6-py3-none-any.whl
- Upload date:
- Size: 71.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72e3b6827fe1a862e4a3a5ec710416c5a3de3a0284d9867ec06ea332601d05cf
|
|
| MD5 |
09d9a48b74230722ef846e4c25548cde
|
|
| BLAKE2b-256 |
ffad9d34b4d53d91843a87741f27fb6df0a1f21e43783b57a9667242052b6dfa
|