Models (ORM) — Aquilia Documentation
Comprehensive guide and documentation for Models (ORM) in the Aquilia framework. View API reference, examples, and implementation patterns.
Docs / Models Models (ORM) Pure Python, async-first ORM. Subclass Model and declare fields. A metaclass collects descriptors, assigns PKs, parses Meta , registers globally, and attaches Manager . Architecture Metaclass-driven. All database access methods return an awaitable. A global ModelRegistry maps tables and dependencies. Quick Start from aquilia.models import Model from aquilia.models.fields_module import CharField, EmailField, BooleanField, DateTimeField class User(Model): table = "users" name = CharField(max_length=150) email = EmailField(unique=True) active = BooleanField(default=True) created_at = DateTimeField(auto_now_add=True) class Meta: ordering = ["-created_at"] CRUD Operations Mutations use instance methods. Queries are issued through the QuerySet attached to the objects manager. # CREATE user = User(name="Alice", email="alice@co.com") await user.save(db) # INSERT — calls save() # Eager objects manager creation user = await User.objects.create(db, name="Bob", email="bob@co.com") # READ users = await User.objects.filter(active=True).all() user = await User.objects.get(id=1) # strict one or raise # UPDATE user.name = "Alice Smith" await user.save(db, update_fields=["name"]) # UPDATE with update_fields # DELETE await user.delete_instance(db) # calls delete_instance() Identity Map and Unit of Work Aquilia deliberately does not implement an identity map or a deferred-flush unit of work, unlike session-oriented ORMs such as SQLAlchemy (Session), Hibernate (Persistence Context), or Entity Framework Core (DbContext). No identity map: fetching the same row twice returns two distinct Python objects with independent state. user_a = await User.get(id=1) user_b = await User.get(id=1) assert user_a is not user_b # Mutating user_a has no effect on user_b until saved and re-fetched. No unit of work: each .save() persists immediately — there is no deferred change batching or cross-entity flush planning. await user.save() await profile.save() await settings.save() # each of the above is a separate, immediate write # atomic() gives transactional consistency, not Session.flush()-style batching async with atomic(): await user.save() await profile.save() This is a deliberate tradeoff, not a missing feature: a session-scoped identity map and unit of work would require task-affinity tracking, session lifecycle management, and cross-request state — all at odds with an async-first framework where request handling routinely spans concurrent tasks. Explicit, immediate persistence keeps behavior predictable regardless of how your async code is scheduled. Instance Methods Method Description ))} Meta Options Configure table properties in Meta : Option Type Description ))} Model Registry & Thread Safety The metaclass auto-registers models in ModelRegistry for topology and dependency mapping. In v1.3.7, ModelRegistry is fully thread-safe (guarded by threading.RLock) and automatically invalidates reverse relation metadata caches across models on registration or reset. from aquilia.models.registry import ModelRegistry # Thread-safe model lookup (guarded by RLock) UserModel = ModelRegistry.get_model("User") # Create all tables (respects FK topology order across worker threads) await ModelRegistry.create_tables(db) # BaseManager descriptor isolation on model subclasses # SubModel.objects returns a thread-isolated bound copy (copy.copy) items = await ConcreteItem.objects.all() Fields )
Go to Homepage