Ormar
Ormar is an async ORM for Python, designed with FastAPI and Pydantic validation in mind, supporting Postgres, MySQL, and SQLite. It provides a single model definition that acts as both an ORM model and a Pydantic model. Currently at version 0.23.1, it maintains an active development and release cadence, frequently pushing updates including vulnerability fixes and new features.
Warnings
- breaking A high severity vulnerability (CVE-2026-27953) in model initialization allowed injection of `__pk_only__` and `__excluded__` parameters through user-supplied `**kwargs`, bypassing Pydantic validation or nullifying fields.
- breaking A critical vulnerability (CVE-2026-26198) in aggregate functions allowed arbitrary SQL execution through user input due to improper SQL query generation.
- breaking Version 0.22.0 migrated from the `databases` library to native async SQLAlchemy. This requires changing database connection imports and potentially connection string formats.
- breaking Starting with version 0.20.0, model configuration transitioned from an inner `Meta` class to an instance of `ormar.OrmarConfig` assigned to the `ormar_config` attribute.
- breaking Ormar `0.20.0` introduced support for Pydantic v2. This includes changes to how `choices` are handled (now `ormar.Enum`) and deprecation of `pydantic_only` fields. This might require adjustments in model field definitions.
- breaking Support for Python 3.8 was dropped in `0.21.0`, and Python 3.9 was dropped in `0.23.0`. Additionally, SQLAlchemy 1.4 support was dropped in `0.21.0` in favor of SQLAlchemy 2.0.
Install
-
pip install ormar
Imports
- Model
from ormar import Model
- OrmarConfig
class Meta: ...
from ormar import OrmarConfig
- DatabaseConnection
import databases; database = databases.Database(...)
from ormar import DatabaseConnection
- Integer
from ormar import Integer
- String
from ormar import String
- Boolean
from ormar import Boolean
Quickstart
import asyncio
import sqlalchemy
import ormar
# 1. Define Database Connection and Metadata
DATABASE_URL = "sqlite+aiosqlite:///test.db"
# This assumes a base config for all models. For complex apps, use `base_ormar_config.copy()`
base_ormar_config = ormar.OrmarConfig(
metadata=sqlalchemy.MetaData(),
database=ormar.DatabaseConnection(DATABASE_URL),
)
# 2. Define an Ormar Model
class User(ormar.Model):
ormar_config = base_ormar_config.copy(tablename="users")
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
is_active: bool = ormar.Boolean(default=True)
async def main():
# 3. Connect to the database and create tables
if not base_ormar_config.database.is_connected:
await base_ormar_config.database.connect()
# Create tables (only once, usually in a migration or startup script)
# For a persistent DB, use alembic. For quickstart, create all.
print("Creating tables...")
engine = sqlalchemy.create_engine(DATABASE_URL.replace('+aiosqlite', ''))
base_ormar_config.metadata.create_all(engine)
print("Tables created.")
# 4. Create a new user
print("Creating user Jane Doe...")
jane = await User.objects.create(name="Jane Doe")
print(f"Created user: {jane.id} - {jane.name} (active: {jane.is_active})")
# 5. Retrieve all users
print("Retrieving all users...")
users = await User.objects.all()
for user in users:
print(f"Found user: {user.id} - {user.name} (active: {user.is_active})")
# 6. Disconnect from the database
print("Disconnecting from database...")
if base_ormar_config.database.is_connected:
await base_ormar_config.database.disconnect()
print("Disconnected.")
if __name__ == "__main__":
asyncio.run(main())