0
# Entity Attributes and Relationships
1
2
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.
3
4
## Capabilities
5
6
### Core Attribute Types
7
8
Basic attribute types for defining entity properties with various constraints and database column configurations.
9
10
```python { .api }
11
class Required:
12
def __init__(self, py_type, *args, **kwargs):
13
"""Define required (non-nullable) attribute.
14
15
Args:
16
py_type: Python type (str, int, float, datetime, etc.)
17
*args: Additional constraints or default value
18
**kwargs: Attribute options
19
max_len: Maximum length for strings
20
min: Minimum value for numbers
21
max: Maximum value for numbers
22
unique: Unique constraint
23
index: Create database index
24
default: Default value or callable
25
sql_type: Override SQL column type
26
column: Custom database column name
27
"""
28
29
class Optional:
30
def __init__(self, py_type, *args, **kwargs):
31
"""Define optional (nullable) attribute.
32
33
Args:
34
py_type: Python type (str, int, float, datetime, etc.)
35
*args: Additional constraints or default value
36
**kwargs: Same options as Required
37
"""
38
39
class PrimaryKey:
40
def __init__(self, py_type, *args, **kwargs):
41
"""Define primary key attribute.
42
43
Args:
44
py_type: Python type (usually int)
45
*args: Additional constraints
46
**kwargs: Attribute options
47
auto: Auto-increment for integer keys (default True)
48
size: Size for integer keys (32 or 64 bit)
49
"""
50
51
class Discriminator:
52
def __init__(self, py_type, *args, **kwargs):
53
"""Define discriminator column for entity inheritance.
54
55
Args:
56
py_type: Python type (usually str or int)
57
*args: Additional constraints
58
**kwargs: Attribute options
59
"""
60
```
61
62
### Relationship Attributes
63
64
Relationship types for defining connections between entities, supporting one-to-one, one-to-many, and many-to-many relationships.
65
66
```python { .api }
67
class Set:
68
def __init__(self, py_type, *args, **kwargs):
69
"""Define collection relationship (one-to-many or many-to-many).
70
71
Args:
72
py_type: Related entity class or string name
73
*args: Additional relationship constraints
74
**kwargs: Relationship options
75
reverse: Name of reverse relationship attribute
76
cascade_delete: Delete related objects when this is deleted
77
lazy: Lazy loading behavior
78
table: Join table name for many-to-many
79
column: Foreign key column name
80
reverse_column: Reverse foreign key column name
81
"""
82
83
def add(self, item):
84
"""Add item to collection."""
85
86
def remove(self, item):
87
"""Remove item from collection."""
88
89
def clear(self):
90
"""Remove all items from collection."""
91
92
def count(self):
93
"""Get count of items in collection."""
94
95
def is_empty(self):
96
"""Check if collection is empty."""
97
98
def select(self, lambda_expr=None):
99
"""Select items from collection matching criteria."""
100
101
def filter(self, lambda_expr):
102
"""Filter collection items."""
103
104
def order_by(self, *args):
105
"""Order collection items."""
106
107
def random(self, limit):
108
"""Get random items from collection."""
109
110
class Reference:
111
def __init__(self, py_type, *args, **kwargs):
112
"""Define reference to single related entity (one-to-one or many-to-one).
113
114
Args:
115
py_type: Related entity class or string name
116
*args: Additional constraints
117
**kwargs: Reference options
118
reverse: Name of reverse relationship attribute
119
cascade_delete: Delete behavior
120
lazy: Lazy loading behavior
121
column: Foreign key column name
122
"""
123
```
124
125
### Composite Keys and Indexes
126
127
Functions for defining composite primary keys and database indexes across multiple attributes.
128
129
```python { .api }
130
def composite_key(*attrs):
131
"""Define composite primary key from multiple attributes.
132
133
Args:
134
*attrs: Attribute instances to include in composite key
135
136
Usage:
137
class Person(db.Entity):
138
first_name = Required(str)
139
last_name = Required(str)
140
birth_date = Required(date)
141
composite_key(first_name, last_name, birth_date)
142
"""
143
144
def composite_index(*attrs, **kwargs):
145
"""Define composite database index across multiple attributes.
146
147
Args:
148
*attrs: Attribute instances to include in index
149
**kwargs: Index options
150
unique: Create unique index
151
name: Custom index name
152
153
Usage:
154
class Person(db.Entity):
155
first_name = Required(str)
156
last_name = Required(str)
157
email = Required(str)
158
composite_index(first_name, last_name)
159
composite_index(email, unique=True)
160
"""
161
```
162
163
## Usage Examples
164
165
### Basic Attributes
166
167
```python
168
from pony.orm import *
169
from datetime import datetime, date
170
171
db = Database()
172
173
class Person(db.Entity):
174
# Primary key (auto-increment by default)
175
id = PrimaryKey(int)
176
177
# Required attributes with constraints
178
name = Required(str, max_len=100)
179
email = Required(str, unique=True, max_len=255)
180
age = Required(int, min=0, max=150)
181
182
# Optional attributes
183
phone = Optional(str, max_len=20)
184
birth_date = Optional(date)
185
salary = Optional(float, min=0)
186
187
# Attribute with default value
188
created_at = Required(datetime, default=datetime.now)
189
is_active = Required(bool, default=True)
190
191
# Custom column name and SQL type
192
full_name = Optional(str, column='full_name_col', sql_type='VARCHAR(200)')
193
194
# Indexed attribute
195
department = Optional(str, index=True)
196
```
197
198
### Relationships
199
200
```python
201
class Company(db.Entity):
202
name = Required(str, unique=True)
203
founded = Optional(date)
204
employees = Set('Employee') # One-to-many
205
206
class Employee(db.Entity):
207
name = Required(str)
208
company = Required(Company) # Many-to-one (reverse of employees)
209
projects = Set('Project') # Many-to-many
210
manager = Optional('Employee') # Self-reference
211
subordinates = Set('Employee', reverse='manager') # Reverse self-reference
212
213
class Project(db.Entity):
214
name = Required(str)
215
employees = Set(Employee) # Many-to-many (reverse of projects)
216
deadline = Optional(date)
217
```
218
219
### Advanced Relationship Configuration
220
221
```python
222
class Author(db.Entity):
223
name = Required(str)
224
books = Set('Book', cascade_delete=True) # Delete books when author deleted
225
226
class Book(db.Entity):
227
title = Required(str)
228
isbn = Required(str, unique=True)
229
author = Required(Author)
230
tags = Set('Tag', table='book_tags',
231
column='book_id', reverse_column='tag_id') # Custom join table
232
233
class Tag(db.Entity):
234
name = Required(str, unique=True)
235
books = Set(Book)
236
237
# Entity inheritance with discriminator
238
class Vehicle(db.Entity):
239
make = Required(str)
240
model = Required(str)
241
year = Required(int)
242
vehicle_type = Discriminator(str) # Discriminator for inheritance
243
244
class Car(Vehicle):
245
doors = Required(int)
246
247
class Motorcycle(Vehicle):
248
engine_size = Required(int)
249
```
250
251
### Composite Keys and Indexes
252
253
```python
254
class OrderItem(db.Entity):
255
order_id = Required(int)
256
product_id = Required(int)
257
quantity = Required(int)
258
price = Required(float)
259
260
# Composite primary key
261
composite_key(order_id, product_id)
262
263
class Person(db.Entity):
264
first_name = Required(str)
265
last_name = Required(str)
266
email = Required(str)
267
birth_date = Optional(date)
268
269
# Composite indexes
270
composite_index(first_name, last_name) # For name searches
271
composite_index(email, unique=True) # Unique email index
272
composite_index(birth_date, last_name) # For birthday queries
273
```
274
275
### Working with Collections
276
277
```python
278
with db_session:
279
# Create entities with relationships
280
company = Company(name="Tech Corp", founded=date(2020, 1, 1))
281
282
# Add employees to company
283
alice = Employee(name="Alice", company=company)
284
bob = Employee(name="Bob", company=company)
285
286
# Working with Set collections
287
print(f"Company has {company.employees.count()} employees")
288
289
# Add to collection
290
company.employees.add(Employee(name="Charlie", company=company))
291
292
# Filter collection
293
senior_employees = company.employees.select(lambda e: e.salary > 80000)
294
295
# Order collection
296
ordered_employees = company.employees.order_by(Employee.name)
297
298
# Many-to-many relationships
299
project = Project(name="Website Redesign")
300
project.employees.add(alice)
301
project.employees.add(bob)
302
303
# Access reverse relationship
304
alice_projects = alice.projects # All projects Alice works on
305
```