Pony Object-Relational Mapper for Python with Pythonic query syntax using generator expressions
—
Attribute types for defining entity properties, primary keys, and relationships between entities. These classes define the schema structure, constraints, and relational mappings that form the foundation of the ORM.
Basic attribute types for defining entity properties with various constraints and database column configurations.
class Required:
def __init__(self, py_type, *args, **kwargs):
"""Define required (non-nullable) attribute.
Args:
py_type: Python type (str, int, float, datetime, etc.)
*args: Additional constraints or default value
**kwargs: Attribute options
max_len: Maximum length for strings
min: Minimum value for numbers
max: Maximum value for numbers
unique: Unique constraint
index: Create database index
default: Default value or callable
sql_type: Override SQL column type
column: Custom database column name
"""
class Optional:
def __init__(self, py_type, *args, **kwargs):
"""Define optional (nullable) attribute.
Args:
py_type: Python type (str, int, float, datetime, etc.)
*args: Additional constraints or default value
**kwargs: Same options as Required
"""
class PrimaryKey:
def __init__(self, py_type, *args, **kwargs):
"""Define primary key attribute.
Args:
py_type: Python type (usually int)
*args: Additional constraints
**kwargs: Attribute options
auto: Auto-increment for integer keys (default True)
size: Size for integer keys (32 or 64 bit)
"""
class Discriminator:
def __init__(self, py_type, *args, **kwargs):
"""Define discriminator column for entity inheritance.
Args:
py_type: Python type (usually str or int)
*args: Additional constraints
**kwargs: Attribute options
"""Relationship types for defining connections between entities, supporting one-to-one, one-to-many, and many-to-many relationships.
class Set:
def __init__(self, py_type, *args, **kwargs):
"""Define collection relationship (one-to-many or many-to-many).
Args:
py_type: Related entity class or string name
*args: Additional relationship constraints
**kwargs: Relationship options
reverse: Name of reverse relationship attribute
cascade_delete: Delete related objects when this is deleted
lazy: Lazy loading behavior
table: Join table name for many-to-many
column: Foreign key column name
reverse_column: Reverse foreign key column name
"""
def add(self, item):
"""Add item to collection."""
def remove(self, item):
"""Remove item from collection."""
def clear(self):
"""Remove all items from collection."""
def count(self):
"""Get count of items in collection."""
def is_empty(self):
"""Check if collection is empty."""
def select(self, lambda_expr=None):
"""Select items from collection matching criteria."""
def filter(self, lambda_expr):
"""Filter collection items."""
def order_by(self, *args):
"""Order collection items."""
def random(self, limit):
"""Get random items from collection."""
class Reference:
def __init__(self, py_type, *args, **kwargs):
"""Define reference to single related entity (one-to-one or many-to-one).
Args:
py_type: Related entity class or string name
*args: Additional constraints
**kwargs: Reference options
reverse: Name of reverse relationship attribute
cascade_delete: Delete behavior
lazy: Lazy loading behavior
column: Foreign key column name
"""Functions for defining composite primary keys and database indexes across multiple attributes.
def composite_key(*attrs):
"""Define composite primary key from multiple attributes.
Args:
*attrs: Attribute instances to include in composite key
Usage:
class Person(db.Entity):
first_name = Required(str)
last_name = Required(str)
birth_date = Required(date)
composite_key(first_name, last_name, birth_date)
"""
def composite_index(*attrs, **kwargs):
"""Define composite database index across multiple attributes.
Args:
*attrs: Attribute instances to include in index
**kwargs: Index options
unique: Create unique index
name: Custom index name
Usage:
class Person(db.Entity):
first_name = Required(str)
last_name = Required(str)
email = Required(str)
composite_index(first_name, last_name)
composite_index(email, unique=True)
"""from pony.orm import *
from datetime import datetime, date
db = Database()
class Person(db.Entity):
# Primary key (auto-increment by default)
id = PrimaryKey(int)
# Required attributes with constraints
name = Required(str, max_len=100)
email = Required(str, unique=True, max_len=255)
age = Required(int, min=0, max=150)
# Optional attributes
phone = Optional(str, max_len=20)
birth_date = Optional(date)
salary = Optional(float, min=0)
# Attribute with default value
created_at = Required(datetime, default=datetime.now)
is_active = Required(bool, default=True)
# Custom column name and SQL type
full_name = Optional(str, column='full_name_col', sql_type='VARCHAR(200)')
# Indexed attribute
department = Optional(str, index=True)class Company(db.Entity):
name = Required(str, unique=True)
founded = Optional(date)
employees = Set('Employee') # One-to-many
class Employee(db.Entity):
name = Required(str)
company = Required(Company) # Many-to-one (reverse of employees)
projects = Set('Project') # Many-to-many
manager = Optional('Employee') # Self-reference
subordinates = Set('Employee', reverse='manager') # Reverse self-reference
class Project(db.Entity):
name = Required(str)
employees = Set(Employee) # Many-to-many (reverse of projects)
deadline = Optional(date)class Author(db.Entity):
name = Required(str)
books = Set('Book', cascade_delete=True) # Delete books when author deleted
class Book(db.Entity):
title = Required(str)
isbn = Required(str, unique=True)
author = Required(Author)
tags = Set('Tag', table='book_tags',
column='book_id', reverse_column='tag_id') # Custom join table
class Tag(db.Entity):
name = Required(str, unique=True)
books = Set(Book)
# Entity inheritance with discriminator
class Vehicle(db.Entity):
make = Required(str)
model = Required(str)
year = Required(int)
vehicle_type = Discriminator(str) # Discriminator for inheritance
class Car(Vehicle):
doors = Required(int)
class Motorcycle(Vehicle):
engine_size = Required(int)class OrderItem(db.Entity):
order_id = Required(int)
product_id = Required(int)
quantity = Required(int)
price = Required(float)
# Composite primary key
composite_key(order_id, product_id)
class Person(db.Entity):
first_name = Required(str)
last_name = Required(str)
email = Required(str)
birth_date = Optional(date)
# Composite indexes
composite_index(first_name, last_name) # For name searches
composite_index(email, unique=True) # Unique email index
composite_index(birth_date, last_name) # For birthday querieswith db_session:
# Create entities with relationships
company = Company(name="Tech Corp", founded=date(2020, 1, 1))
# Add employees to company
alice = Employee(name="Alice", company=company)
bob = Employee(name="Bob", company=company)
# Working with Set collections
print(f"Company has {company.employees.count()} employees")
# Add to collection
company.employees.add(Employee(name="Charlie", company=company))
# Filter collection
senior_employees = company.employees.select(lambda e: e.salary > 80000)
# Order collection
ordered_employees = company.employees.order_by(Employee.name)
# Many-to-many relationships
project = Project(name="Website Redesign")
project.employees.add(alice)
project.employees.add(bob)
# Access reverse relationship
alice_projects = alice.projects # All projects Alice works on