Massive performance update, dumping data to ids and not nested models and other
0.25.0
⚡ Performance
A broad performance pass across model construction, row hydration, relation
resolution, alias lookups, and result merging — combining per-class caching,
lazy initialization of relation machinery, and porting the hottest helpers to
Rust via the new required ormar-utils
dependency. End-to-end speedups vs 0.24.0 range from ~12 % on select_related,
through ~30 % on iterate and first, to ~60 - 80 % on initialization of models, and up to x2.5 speedup in getting all.
✨ Features
-
Add
flatten_fields()queryset method andmodel_dump(flatten_fields=...)/
model_dump(flatten_all=True)arguments to render related models as their
primary key value instead of nested dicts — see docs #1641cars = await Car.objects.flatten_fields("manufacturer").all() assert cars[0].model_dump() == {"id": 1, "name": "Corolla", "manufacturer": 1} # Note the id 1 and not the nested model car.model_dump(flatten_all=True) car.model_dump(flatten_fields={"manufacturer": ...})
-
Add proxy model inheritance (
OrmarConfig(proxy=True)) — child class
shares the parent's table and only adds methods / computed fields / a custom
queryset_class— thanks @SepehrBazyar — see docs #760class User(Human): ormar_config = base_ormar_config.copy(proxy=True) def full_name(self) -> str: return f"{self.first_name} {self.last_name}"
-
Add per-table
schema=support onOrmarConfigso models can live in
non-default database schemas (PostgreSQL full, MySQL with caveats, SQLite
not supported for cross-schema FKs) — thanks @hk3dva — see docs #1493 -
Add Python-style indexing and slicing on
QuerySet—Track.objects[:10],
Track.objects[-5:],Track.objects[5]— thanks @SepehrBazyar — see docs #765 -
Add
nulls_orderingargument to.asc()/.desc()(ormar.NullsOrdering.FIRST
/LAST) with MySQL emulation — thanks @SepehrBazyar — see docs #769 -
Allow filtering by a foreign-key column directly (
Book.objects.filter(Book.author == 5)
or with a model instance) without adding a JOIN — thanks @djalouehz — see docs #854 -
Add
through_relation_nullableandthrough_reverse_relation_nullableto
ormar.ManyToManyto enforceNOT NULLon the through table's FK columns —
thanks @evadev-eva — see docs #852 -
Add
last()/last_or_none()onQuerySetand exposefirst_or_none()/
last()/last_or_none()onQuerysetProxy— see docs #765 -
Forward unrecognized
**kwargsfromormar.ForeignKey/ormar.ManyToMany
toBaseField— fixescomment=(and otherBaseFieldkwargs) being
silently dropped on relation fields — thanks @booqoffsky #1239
🐛 Fixes
- Clearing a nullable
ForeignKeywithinstance.fk = Nonenow also clears the
in-memory relation, so subsequent reads returnNonewithout a reload —
originally @amit12297, rebased — see docs #1230 - Drop the unnecessary post-
INSERTpk reload insave(), and raise
ModelPersistenceErroron backends that cannot return a generated pk
(Oracle MySQL with non-AUTO_INCREMENTserver-default pk) instead of
silently assigning the row count toModel.pk— thanks @vnicolaichuk #919 SelectActionaggregate identifiers now go throughsqlalchemy.column()
instead of string concatenation #1637- Fix the
mkdocsdeployment workflow #1638