SQ L Alchemy
SQ L Alchemy
Release 1.0.12
Mike Bayer
1 Overview 3
1.1 Documentation Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Code Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Installation Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3.1 Supported Platforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3.2 Supported Installation Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3.3 Install via pip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.4 Installing using setup.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.5 Installing the C Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.6 Installing on Python 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.7 Installing a Database API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.8 Checking the Installed SQLAlchemy Version . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 0.9 to 1.0 Migration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2 SQLAlchemy ORM 7
2.1 Object Relational Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.1 Version Check . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.2 Connecting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.3 Declare a Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.4 Create a Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.5 Create an Instance of the Mapped Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.6 Creating a Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.7 Adding and Updating Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.1.8 Rolling Back . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.9 Querying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Common Filter Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Returning Lists and Scalars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Using Textual SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.1.10 Building a Relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.1.11 Working with Related Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.1.12 Querying with Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Using Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Using Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Selecting Entities from Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Using EXISTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Common Relationship Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.1.13 Eager Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
i
Subquery Load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Joined Load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Explicit Join + Eagerload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.14 Deleting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Configuring delete/delete-orphan Cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.1.15 Building a Many To Many Relationship . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.1.16 Further Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.2 Mapper Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.2.1 Types of Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Declarative Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Classical Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Runtime Introspection of Mappings, Objects . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.2.2 Mapping Columns and Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Mapping Table Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
SQL Expressions as Mapped Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Changing Attribute Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Composite Column Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2.3 Mapping Class Inheritance Hierarchies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Joined Table Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Single Table Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Concrete Table Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Using Relationships with Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Using Inheritance with Declarative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.2.4 Non-Traditional Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Mapping a Class against Multiple Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Mapping a Class against Arbitrary Selects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Multiple Mappers for One Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.2.5 Configuring a Version Counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Simple Version Counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Custom Version Counters / Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Server Side Version Counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Programmatic or Conditional Version Counters . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.2.6 Class Mapping API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
2.3 Relationship Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
2.3.1 Basic Relationship Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
One To Many . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Many To One . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
One To One . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Many To Many . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Association Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
2.3.2 Adjacency List Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Composite Adjacency Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Self-Referential Query Strategies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Configuring Self-Referential Eager Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
2.3.3 Linking Relationships with Backref . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Backref Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
One Way Backrefs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
2.3.4 Configuring how Relationship Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Handling Multiple Join Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Specifying Alternate Join Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Creating Custom Foreign Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Using custom operators in join conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Overlapping Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Non-relational Comparisons / Materialized Path . . . . . . . . . . . . . . . . . . . . . . . . . 113
ii
Self-Referential Many-to-Many Relationship . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Composite “Secondary” Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Relationship to Non Primary Mapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Building Query-Enabled Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
2.3.5 Collection Configuration and Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Working with Large Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Customizing Collection Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Custom Collection Implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Collection Internals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
2.3.6 Special Relationship Persistence Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Rows that point to themselves / Mutually Dependent Rows . . . . . . . . . . . . . . . . . . . 131
Mutable Primary Keys / Update Cascades . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
2.3.7 Relationships API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
2.4 Loading Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
2.4.1 Loading Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Deferred Column Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Column Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
2.4.2 Relationship Loading Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Using Loader Strategies: Lazy Loading, Eager Loading . . . . . . . . . . . . . . . . . . . . . 149
The Importance of Ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Loading Along Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Default Loading Strategies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Per-Entity Default Loading Strategies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
The Zen of Eager Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
What Kind of Loading to Use ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Routing Explicit Joins/Statements into Eagerly Loaded Collections . . . . . . . . . . . . . . 155
Creating Custom Load Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Relationship Loader API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
2.4.3 Constructors and Object Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.4.4 Query API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
The Query Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
ORM-Specific Query Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
2.5 Using the Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
2.5.1 Session Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
What does the Session do ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Getting a Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Session Frequently Asked Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Basics of Using a Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
2.5.2 State Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Quickie Intro to Object States . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Session Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Merging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Expunging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Refreshing / Expiring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
2.5.3 Cascades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
save-update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
delete-orphan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
merge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
refresh-expire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
expunge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Controlling Cascade on Backrefs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
2.5.4 Transactions and Connection Management . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Managing Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
iii
Joining a Session into an External Transaction (such as for test suites) . . . . . . . . . . . . . 223
2.5.5 Additional Persistence Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Embedding SQL Insert/Update Expressions into a Flush . . . . . . . . . . . . . . . . . . . . 224
Using SQL Expressions with Sessions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Partitioning Strategies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Bulk Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.5.6 Contextual/Thread-local Sessions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Implicit Method Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
Thread-Local Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Using Thread-Local Scope with Web Applications . . . . . . . . . . . . . . . . . . . . . . . 230
Using Custom Created Scopes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Contextual Session API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
2.5.7 Tracking Object and Session Changes with Events . . . . . . . . . . . . . . . . . . . . . . 233
Persistence Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Object Lifecycle Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Transaction Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Attribute Change Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
2.5.8 Session API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Session and sessionmaker() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Session Utilites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
Attribute and State Management Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
2.6 Events and Internals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
2.6.1 ORM Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Attribute Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Mapper Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Instance Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Session Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Query Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Instrumentation Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
2.6.2 ORM Internals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
2.6.3 ORM Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
2.6.4 Deprecated ORM Event Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
Mapper Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
Session Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
Attribute Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
2.7 ORM Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
2.7.1 Association Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Simplifying Scalar Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Creation of New Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Simplifying Association Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Proxying to Dictionary Based Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Composite Association Proxies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Querying with Association Proxies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
API Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
2.7.2 Automap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
Basic Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
Generating Mappings from an Existing MetaData . . . . . . . . . . . . . . . . . . . . . . . . 341
Specifying Classes Explicitly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Overriding Naming Schemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
Relationship Detection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Using Automap with Explicit Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
2.7.3 Baked Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
iv
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
Rationale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
Lazy Loading Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
API Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
2.7.4 Declarative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Basic Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Configuring Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
Table Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Inheritance Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
Mixin and Custom Base Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Declarative API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
2.7.5 Mutation Tracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
Establishing Mutability on Scalar Column Values . . . . . . . . . . . . . . . . . . . . . . . . 384
Establishing Mutability on Composites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
2.7.6 Ordering List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
2.7.7 Horizontal Sharding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
API Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
2.7.8 Hybrid Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
Defining Expression Behavior Distinct from Attribute Behavior . . . . . . . . . . . . . . . . 398
Defining Setters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
Working with Relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
Building Custom Comparators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
Hybrid Value Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
Building Transformers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
2.7.9 Alternate Class Instrumentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
2.8 ORM Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
2.8.1 Mapping Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Adjacency List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Directed Graphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Dynamic Relations as Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Generic Associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Large Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Materialized Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
Nested Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
Relationship Join Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
XML Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
Versioning Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Vertical Attribute Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
2.8.2 Inheritance Mapping Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Basic Inheritance Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
2.8.3 Special APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Attribute Instrumentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Horizontal Sharding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
2.8.4 Extending the ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Dogpile Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
PostGIS Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
v
3.1 SQL Expression Language Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
3.1.1 Version Check . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
3.1.2 Connecting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
3.1.3 Define and Create Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
3.1.4 Insert Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
3.1.5 Executing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
3.1.6 Executing Multiple Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
3.1.7 Selecting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
3.1.8 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Operator Customization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
3.1.9 Conjunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
3.1.10 Using Textual SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
Using More Specific Text with table(), literal_column(), and column() . . . . . 435
Ordering or Grouping by a Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
3.1.11 Using Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
3.1.12 Using Joins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
3.1.13 Everything Else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Bind Parameter Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
Window Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
Unions and Other Set Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
Scalar Selects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
Correlated Subqueries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
Ordering, Grouping, Limiting, Offset...ing... . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
3.1.14 Inserts, Updates and Deletes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
Correlated Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
Multiple Table Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
Parameter-Ordered Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Deletes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Matched Row Counts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
3.1.15 Further Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
3.2 SQL Statements and Expressions API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
3.2.1 Column Elements and Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
3.2.2 Selectables, Tables, FROM objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
3.2.3 Insert, Updates, Deletes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
3.2.4 SQL and Generic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588
3.2.5 Custom SQL Constructs and Compilation Extension . . . . . . . . . . . . . . . . . . . . . 595
Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
Dialect-specific compilation rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
Compiling sub-elements of a custom expression construct . . . . . . . . . . . . . . . . . . . 596
Enabling Autocommit on a Construct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
Changing the default compilation of existing constructs . . . . . . . . . . . . . . . . . . . . . 598
Changing Compilation of Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
Subclassing Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
Further Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599
3.2.6 Expression Serializer Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
3.3 Schema Definition Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
3.3.1 Describing Databases with MetaData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
Accessing Tables and Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
Creating and Dropping Database Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
Altering Schemas through Migrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
Specifying the Schema Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
Backend-Specific Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
Column, Table, MetaData API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607
vi
3.3.2 Reflecting Database Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632
Overriding Reflected Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
Reflecting Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
Reflecting All Tables at Once . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
Fine Grained Reflection with Inspector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
Limitations of Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
3.3.3 Column Insert/Update Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638
Scalar Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
Python-Executed Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
SQL Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
Server Side Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
Triggered Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
Defining Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
Default Objects API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
3.3.4 Defining Constraints and Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
Defining Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
UNIQUE Constraint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651
CHECK Constraint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
PRIMARY KEY Constraint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
Setting up Constraints when using the Declarative ORM Extension . . . . . . . . . . . . . . 653
Configuring Constraint Naming Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . 653
Constraints API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 657
Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
Index API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
3.3.5 Customizing DDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
Custom DDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
Controlling DDL Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
Using the built-in DDLElement Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681
DDL Expression Constructs API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683
3.4 Column and Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690
3.4.1 Column and Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690
Generic Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
SQL Standard Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
Vendor-Specific Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
3.4.2 Custom Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
Overriding Type Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
Augmenting Existing Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
TypeDecorator Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
Replacing the Bind/Result Processing of Existing Types . . . . . . . . . . . . . . . . . . . . 711
Applying SQL-level Bind/Result Processing . . . . . . . . . . . . . . . . . . . . . . . . . . 711
Redefining and Creating New Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
Creating New Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
3.4.3 Base Type API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
3.5 Engine and Connection Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
3.5.1 Engine Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
Supported Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721
Database Urls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721
Engine Creation API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723
Pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728
Custom DBAPI connect() arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728
Configuring Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728
3.5.2 Working with Engines and Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729
Basic Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729
Using Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731
vii
Understanding Autocommit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732
Connectionless Execution, Implicit Execution . . . . . . . . . . . . . . . . . . . . . . . . . . 732
Engine Disposal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
Using the Threadlocal Execution Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735
Working with Raw DBAPI Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
Registering New Dialects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737
Connection / Engine API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738
3.5.3 Connection Pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756
Connection Pool Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756
Switching Pool Implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
Using a Custom Connection Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
Constructing a Pool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
Pool Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
Dealing with Disconnects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
Using Connection Pools with Multiprocessing . . . . . . . . . . . . . . . . . . . . . . . . . 761
API Documentation - Available Pool Implementations . . . . . . . . . . . . . . . . . . . . . 762
Pooling Plain DB-API Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768
3.5.4 Core Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768
Connection Pool Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
SQL Execution and Connection Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772
Schema Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787
3.6 Core API Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
3.6.1 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
Event Registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
Named Argument Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 792
Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793
Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793
Event Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 793
API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794
3.6.2 Runtime Inspection API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
Available Inspection Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
3.6.3 Deprecated Event Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797
Execution, Connection and Cursor Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797
Connection Pool Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798
3.6.4 Core Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 799
3.6.5 Core Internals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802
4 Dialects 821
4.1 Included Dialects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
4.1.1 Firebird . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
Firebird Dialects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
Locking Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
RETURNING support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
fdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
kinterbasdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 823
4.1.2 Microsoft SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824
Auto Increment Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824
Rendering of SQL statements that include schema qualifiers . . . . . . . . . . . . . . . . . . 826
Collation Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 827
LIMIT/OFFSET Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 827
Nullability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
Date / Time Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
viii
Large Text/Binary Type Deprecation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
Clustered Index Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829
MSSQL-Specific Index Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829
Compatibility Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830
Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830
Rowcount Support / ORM Versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830
Enabling Snapshot Isolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
Known Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
SQL Server Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
PyODBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836
mxODBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
pymssql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
zxjdbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
AdoDBAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
4.1.3 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Supported Versions and Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Connection Timeouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
CREATE TABLE arguments including Storage Engines . . . . . . . . . . . . . . . . . . . . 840
Case Sensitivity and Table Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841
Transaction Isolation Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841
AUTO_INCREMENT Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 842
Unicode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 842
Ansi Quoting Style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
MySQL SQL Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
rowcount Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844
CAST Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844
MySQL Specific Index Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844
MySQL Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 845
MySQL Unique Constraints and Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . 846
TIMESTAMP Columns and NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846
MySQL Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 848
MySQL-Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
pymysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859
MySQL-Connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859
cymysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
OurSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
Google App Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861
pyodbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861
zxjdbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862
4.1.4 Oracle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862
Connect Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
Auto Increment Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
Identifier Casing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
LIMIT/OFFSET Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
RETURNING Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864
ON UPDATE CASCADE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864
Oracle 8 Compatibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865
Synonym/DBLINK Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865
DateTime Compatibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865
Oracle Table Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865
Oracle Specific Index Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866
Oracle Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866
ix
cx_Oracle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869
zxjdbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873
4.1.5 PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873
Sequences/SERIAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
Transaction Isolation Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
Remote-Schema Table Introspection and Postgresql search_path . . . . . . . . . . . . . . . . 875
INSERT/UPDATE...RETURNING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 877
Full Text Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 877
FROM ONLY ... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878
Postgresql-Specific Index Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 879
Postgresql Index Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
Special Reflection Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
PostgreSQL Table Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881
ENUM Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882
PostgreSQL Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 883
PostgreSQL Constraint Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
psycopg2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899
pg8000 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903
psycopg2cffi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904
py-postgresql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905
zxjdbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905
4.1.6 SQLite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
Date and Time Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
SQLite Auto Incrementing Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
Database Locking Behavior / Concurrency . . . . . . . . . . . . . . . . . . . . . . . . . . . 907
Transaction Isolation Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908
SAVEPOINT Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908
Transactional DDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
Foreign Key Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
Type Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 910
Partial Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 910
Dotted Column Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 910
SQLite Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912
Pysqlite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914
Pysqlcipher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918
4.1.7 Sybase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919
DBAPI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919
python-sybase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919
pyodbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 920
mxodbc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
4.2 External Dialects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
4.2.1 Production Ready . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
4.2.2 Experimental / Incomplete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
4.2.3 Attic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 922
x
I’m on MyISAM - how do I turn it off? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 924
I’m on SQL Server - how do I turn those ROLLBACKs into COMMITs? . . . . . . . . . . . 924
5.1.6 I am using multiple connections with a SQLite database (typically to test transaction opera-
tion), and my test program is not working! . . . . . . . . . . . . . . . . . . . . . . . . . . . 925
5.1.7 How do I get at the raw DBAPI connection when using an Engine? . . . . . . . . . . . . . . 925
5.1.8 How do I use engines / connections / sessions with Python multiprocessing, or os.fork()? . . 925
5.2 MetaData / Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 926
5.2.1 My program is hanging when I say table.drop() / metadata.drop_all() . . . . . 927
5.2.2 Does SQLAlchemy support ALTER TABLE, CREATE VIEW, CREATE TRIGGER,
Schema Upgrade Functionality? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 927
5.2.3 How can I sort Table objects in order of their dependency? . . . . . . . . . . . . . . . . . . 927
5.2.4 How can I get the CREATE TABLE/ DROP TABLE output as a string? . . . . . . . . . . . 928
5.2.5 How can I subclass Table/Column to provide certain behaviors/configurations? . . . . . . . 928
5.3 SQL Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928
5.3.1 How do I render SQL expressions as strings, possibly with bound parameters inlined? . . . . 928
5.3.2 Why does .col.in_([]) Produce col != col? Why not 1=0? . . . . . . . . . . . . 930
5.4 ORM Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931
5.4.1 How do I map a table that has no primary key? . . . . . . . . . . . . . . . . . . . . . . . . 931
5.4.2 How do I configure a Column that is a Python reserved word or similar? . . . . . . . . . . . 932
5.4.3 How do I get a list of all columns, relationships, mapped attributes, etc. given a mapped class? 932
5.4.4 I’m getting a warning or error about “Implicitly combining column X under attribute Y” . . 932
5.4.5 I’m using Declarative and setting primaryjoin/secondaryjoin using an and_() or or_(),
and I am getting an error message about foreign keys. . . . . . . . . . . . . . . . . . . . . . 934
5.4.6 Why is ORDER BY required with LIMIT (especially with subqueryload())? . . . . . . 934
5.5 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 936
5.5.1 How can I profile a SQLAlchemy powered application? . . . . . . . . . . . . . . . . . . . . 936
Query Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 936
Code Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937
Execution Slowness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 938
Result Fetching Slowness - Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 938
Result Fetching Slowness - ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
5.5.2 I’m inserting 400,000 rows with the ORM and it’s really slow! . . . . . . . . . . . . . . . . 940
5.6 Sessions / Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943
5.6.1 I’m re-loading data with my Session but it isn’t seeing changes that I committed elsewhere . 943
5.6.2 “This Session’s transaction has been rolled back due to a previous exception during flush.”
(or similar) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
But why does flush() insist on issuing a ROLLBACK? . . . . . . . . . . . . . . . . . . . . . 945
But why isn’t the one automatic call to ROLLBACK enough? Why must I ROLLBACK again? 946
5.6.3 How do I make a Query that always adds a certain filter to every query? . . . . . . . . . . . 947
5.6.4 I’ve created a mapping against an Outer Join, and while the query returns rows, no objects
are returned. Why not? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
5.6.5 I’m using joinedload() or lazy=False to create a JOIN/OUTER JOIN and
SQLAlchemy is not constructing the correct query when I try to add a WHERE, ORDER
BY, LIMIT, etc. (which relies upon the (OUTER) JOIN) . . . . . . . . . . . . . . . . . . . 947
5.6.6 Query has no __len__(), why not? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
5.6.7 How Do I use Textual SQL with ORM Queries? . . . . . . . . . . . . . . . . . . . . . . . . 948
5.6.8 I’m calling Session.delete(myobject) and it isn’t removed from the parent collection!948
5.6.9 why isn’t my __init__() called when I load objects? . . . . . . . . . . . . . . . . . . . 948
5.6.10 how do I use ON DELETE CASCADE with SA’s ORM? . . . . . . . . . . . . . . . . . . . 948
5.6.11 I set the “foo_id” attribute on my instance to “7”, but the “foo” attribute is still None -
shouldn’t it have loaded Foo with id #7? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948
5.6.12 How do I walk all objects that are related to a given object? . . . . . . . . . . . . . . . . . . 950
5.6.13 Is there a way to automagically have only unique keywords (or other kinds of objects) without
doing a query for the keyword and getting a reference to the row containing that keyword? . 951
xi
6 Changes and Migration 953
6.1 Current Migration Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
6.1.1 What’s New in SQLAlchemy 1.0? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
New Features and Improvements - ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
New Features and Improvements - Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 962
Key Behavioral Changes - ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 968
Key Behavioral Changes - Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 980
Dialect Improvements and Changes - Postgresql . . . . . . . . . . . . . . . . . . . . . . . . 986
Dialect Improvements and Changes - MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . 989
Dialect Improvements and Changes - SQLite . . . . . . . . . . . . . . . . . . . . . . . . . . 991
Dialect Improvements and Changes - SQL Server . . . . . . . . . . . . . . . . . . . . . . . . 991
Dialect Improvements and Changes - Oracle . . . . . . . . . . . . . . . . . . . . . . . . . . 992
6.2 Change logs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992
6.2.1 1.0 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992
1.0.13 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992
1.0.12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993
1.0.11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 995
1.0.10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 996
1.0.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 998
1.0.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 999
1.0.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000
1.0.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1001
1.0.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1002
1.0.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1004
1.0.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1005
1.0.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007
1.0.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007
1.0.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1009
1.0.0b5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1010
1.0.0b4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1011
1.0.0b3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1012
1.0.0b2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1012
1.0.0b1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013
6.2.2 0.9 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040
0.9.11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040
0.9.10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040
0.9.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1042
0.9.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045
0.9.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048
0.9.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051
0.9.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051
0.9.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055
0.9.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060
0.9.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1062
0.9.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1067
0.9.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068
0.9.0b1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1074
6.2.3 0.8 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1087
0.8.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1087
0.8.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1089
0.8.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1090
0.8.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1092
0.8.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1094
xii
0.8.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097
0.8.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1101
0.8.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1103
0.8.0b2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1107
0.8.0b1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1111
6.2.4 0.7 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1120
0.7.11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1120
0.7.10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121
0.7.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123
0.7.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1125
0.7.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126
0.7.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128
0.7.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1131
0.7.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133
0.7.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1137
0.7.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1141
0.7.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144
0.7.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145
0.7.0b4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1147
0.7.0b3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149
0.7.0b2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1151
0.7.0b1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152
6.2.5 0.6 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156
0.6.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156
0.6.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1158
0.6.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1159
0.6.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1162
0.6.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1164
0.6.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1168
0.6.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1171
0.6.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1172
0.6.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1175
0.6.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1177
0.6beta3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1179
0.6beta2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1181
0.6beta1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1186
6.2.6 0.5 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198
0.5.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198
0.5.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198
0.5.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1199
0.5.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1201
0.5.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1203
0.5.4p2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1204
0.5.4p1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1204
0.5.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1205
0.5.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1207
0.5.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1209
0.5.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1210
0.5.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1212
0.5.0rc4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1217
0.5.0rc3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1218
0.5.0rc2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220
0.5.0rc1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221
0.5.0beta3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224
xiii
0.5.0beta2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225
0.5.0beta1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227
6.2.7 0.4 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1229
0.4.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1229
0.4.7p1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1229
0.4.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1230
0.4.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231
0.4.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233
0.4.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1237
0.4.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1238
0.4.2p3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1242
0.4.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1243
0.4.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1247
0.4.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1250
0.4.0beta6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1252
0.4.0beta5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1253
0.4.0beta4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1253
0.4.0beta3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1254
0.4.0beta2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1255
0.4.0beta1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1255
6.2.8 0.3 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1260
0.3.11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1260
0.3.10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1262
0.3.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1262
0.3.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1265
0.3.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1267
0.3.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1269
0.3.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1272
0.3.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1275
0.3.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1277
0.3.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1277
0.3.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1278
0.3.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1279
6.2.9 0.2 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1283
0.2.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1283
0.2.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1284
0.2.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1285
0.2.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1286
0.2.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1286
0.2.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1287
0.2.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1288
0.2.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1288
0.2.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1289
6.2.10 0.1 Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1290
0.1.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1290
0.1.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1291
0.1.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1291
0.1.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1293
0.1.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1294
0.1.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1295
0.1.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1295
6.3 Older Migration Guides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296
6.3.1 What’s New in SQLAlchemy 0.9? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296
xiv
Platform Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296
Behavioral Changes - ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1297
Behavioral Changes - Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1302
New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1306
Behavioral Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1313
Dialect Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1323
6.3.2 What’s New in SQLAlchemy 0.8? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1323
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1323
Platform Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1324
New ORM Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1324
New Core Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1332
Behavioral Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1338
Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1344
6.3.3 What’s New in SQLAlchemy 0.7? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1345
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1345
New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1346
Behavioral Changes (Backwards Compatible) . . . . . . . . . . . . . . . . . . . . . . . . . . 1351
Behavioral Changes (Backwards Incompatible) . . . . . . . . . . . . . . . . . . . . . . . . . 1354
Deprecated API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1359
Backwards Incompatible API Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1360
Previously Deprecated, Now Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1361
6.3.4 What’s New in SQLAlchemy 0.6? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1362
Platform Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1362
New Dialect System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1362
Expression Language Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1363
C Extensions for Result Fetching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1365
New Schema Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1366
Logging opened up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1368
Reflection/Inspector API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1368
RETURNING Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1369
Type System Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1369
ORM Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1372
Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1376
6.3.5 What’s new in SQLAlchemy 0.5? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1376
Major Documentation Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1376
Deprecations Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1377
Requirements Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1377
Object Relational Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1377
Extending the ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1380
Schema/Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1380
Connection Pool no longer threadlocal by default . . . . . . . . . . . . . . . . . . . . . . . . 1382
*args Accepted, *args No Longer Accepted . . . . . . . . . . . . . . . . . . . . . . . . . . . 1382
Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1382
Renamed or Moved . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1384
Deprecated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1384
6.3.6 What’s new in SQLAlchemy 0.4? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1385
First Things First . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1385
Module Imports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1385
Object Relational Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1386
SQL Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1394
Schema and Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1395
SQL Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1395
xv
Python Module Index 1399
xvi
SQLAlchemy Documentation, Release 1.0.12
Full table of contents. For a high level overview of all documentation, see index_toplevel.
Contents 1
SQLAlchemy Documentation, Release 1.0.12
2 Contents
CHAPTER 1
Overview
The SQLAlchemy SQL Toolkit and Object Relational Mapper is a comprehensive set of tools for working with
databases and Python. It has several distinct areas of functionality which can be used individually or combined
together. Its major components are illustrated in below, with component dependencies organized into layers:
Above, the two most significant front-facing portions of SQLAlchemy are the Object Relational Mapper and the
SQL Expression Language. SQL Expressions can be used independently of the ORM. When using the ORM, the
SQL Expression language remains part of the public facing API as it is used within object-relational configurations
and queries.
3
SQLAlchemy Documentation, Release 1.0.12
The documentation is separated into three sections: SQLAlchemy ORM, SQLAlchemy Core, and Dialects.
In SQLAlchemy ORM, the Object Relational Mapper is introduced and fully described. New users should begin with
the Object Relational Tutorial. If you want to work with higher-level SQL which is constructed automatically for you,
as well as management of Python objects, proceed to this tutorial.
In SQLAlchemy Core, the breadth of SQLAlchemy’s SQL and database integration and description services are doc-
umented, the core of which is the SQL Expression language. The SQL Expression Language is a toolkit all its
own, independent of the ORM package, which can be used to construct manipulable SQL expressions which can be
programmatically constructed, modified, and executed, returning cursor-like result sets. In contrast to the ORM’s
domain-centric mode of usage, the expression language provides a schema-centric usage paradigm. New users should
begin here with SQL Expression Language Tutorial. SQLAlchemy engine, connection, and pooling services are also
described in SQLAlchemy Core.
In Dialects, reference documentation for all provided database and DBAPI backends is provided.
Working code examples, mostly regarding the ORM, are included in the SQLAlchemy distribution. A description of
all the included example applications is at ORM Examples.
There is also a wide variety of examples involving both core SQLAlchemy constructs as well as the ORM on the wiki.
See Theatrum Chemicum.
SQLAlchemy supports installation using standard Python “distutils” or “setuptools” methodologies. An overview of
potential setups is as follows:
• Plain Python Distutils - SQLAlchemy can be installed with a clean Python install using the services provided
via Python Distutils, using the setup.py script. The C extensions as well as Python 3 builds are supported.
• Setuptools or Distribute - When using setuptools, SQLAlchemy can be installed via setup.py or
easy_install, and the C extensions are supported.
4 Chapter 1. Overview
SQLAlchemy Documentation, Release 1.0.12
• pip - pip is an installer that rides on top of setuptools or distribute, replacing the usage of
easy_install. It is often preferred for its simpler mode of usage.
When pip is available, the distribution can be downloaded from Pypi and installed in one step:
pip install SQLAlchemy
This command will download the latest released version of SQLAlchemy from the Python Cheese Shop and install it
to your system.
In order to install the latest prerelease version, such as 1.0.0b1, pip requires that the --pre flag be used:
pip install --pre SQLAlchemy
Where above, if the most recent version is a prerelease, it will be installed instead of the latest released version.
Otherwise, you can install from the distribution using the setup.py script:
python setup.py install
SQLAlchemy includes C extensions which provide an extra speed boost for dealing with result sets. The extensions
are supported on both the 2.xx and 3.xx series of cPython.
Changed in version 0.9.0: The C extensions now compile on Python 3 as well as Python 2.
setup.py will automatically build the extensions if an appropriate platform is detected. If the build of the C exten-
sions fails, due to missing compiler or other issue, the setup process will output a warning message, and re-run the
build without the C extensions, upon completion reporting final status.
To run the build/install without even attempting to compile the C extensions, the DISABLE_SQLALCHEMY_CEXT
environment variable may be specified. The use case for this is either for special testing circumstances, or in the rare
case of compatibility/build issues not overcome by the usual “rebuild” mechanism:
# *** only in SQLAlchemy 0.9.4 / 0.8.6 or greater ***
export DISABLE_SQLALCHEMY_CEXT=1; python setup.py install
New in version 0.9.4,0.8.6: Support for disabling the build of C extensions using the
DISABLE_SQLALCHEMY_CEXT environment variable has been added. This allows control of C extension
building whether or not setuptools is available, and additionally works around the fact that setuptools will possibly be
removing support for command-line switches such as --without-extensions in a future release.
For versions of SQLAlchemy prior to 0.9.4 or 0.8.6, the --without-cextensions option may be used to disable
the attempt to build C extensions, provided setupools is in use, and provided the Feature construct is supported by
the installed version of setuptools:
python setup.py --without-cextensions install
Or with pip:
pip install --global-option='--without-cextensions' SQLAlchemy
SQLAlchemy runs directly on Python 2 or Python 3, and can be installed in either environment without any adjust-
ments or code conversion.
Changed in version 0.9.0: Python 3 is now supported in place with no 2to3 step required.
SQLAlchemy is designed to operate with a DBAPI implementation built for a particular database, and includes support
for the most popular databases. The individual database sections in Dialects enumerate the available DBAPIs for each
database, including external links.
This documentation covers SQLAlchemy version 1.0. If you’re working on a system that already has SQLAlchemy
installed, check the version from your Python prompt like this:
>>> import sqlalchemy
>>> sqlalchemy.__version__ # doctest: +SKIP
1.0.0
Notes on what’s changed from 0.9 to 1.0 is available here at What’s New in SQLAlchemy 1.0?.
6 Chapter 1. Overview
CHAPTER 2
SQLAlchemy ORM
Here, the Object Relational Mapper is introduced and fully described. If you want to work with higher-level SQL
which is constructed automatically for you, as well as automated persistence of Python objects, proceed first to the
tutorial.
The SQLAlchemy Object Relational Mapper presents a method of associating user-defined Python classes with
database tables, and instances of those classes (objects) with rows in their corresponding tables. It includes a sys-
tem that transparently synchronizes all changes in state between objects and their related rows, called a unit of work,
as well as a system for expressing database queries in terms of the user defined classes and their defined relationships
between each other.
The ORM is in contrast to the SQLAlchemy Expression Language, upon which the ORM is constructed. Whereas the
SQL Expression Language, introduced in SQL Expression Language Tutorial, presents a system of representing the
primitive constructs of the relational database directly without opinion, the ORM presents a high level and abstracted
pattern of usage, which itself is an example of applied usage of the Expression Language.
While there is overlap among the usage patterns of the ORM and the Expression Language, the similarities are more
superficial than they may at first appear. One approaches the structure and content of data from the perspective of
a user-defined domain model which is transparently persisted and refreshed from its underlying storage model. The
other approaches it from the perspective of literal schema and SQL expression representations which are explicitly
composed into messages consumed individually by the database.
A successful application may be constructed using the Object Relational Mapper exclusively. In advanced situations,
an application constructed with the ORM may make occasional usage of the Expression Language directly in certain
areas where specific database interactions are required.
The following tutorial is in doctest format, meaning each >>> line represents something you can type at a Python
command prompt, and the following text represents the expected return value.
7
SQLAlchemy Documentation, Release 1.0.12
2.1.2 Connecting
For this tutorial we will use an in-memory-only SQLite database. To connect we use create_engine():
>>> from sqlalchemy import create_engine
>>> engine = create_engine('sqlite:///:memory:', echo=True)
The echo flag is a shortcut to setting up SQLAlchemy logging, which is accomplished via Python’s standard
logging module. With it enabled, we’ll see all the generated SQL produced. If you are working through this
tutorial and want less output generated, set it to False. This tutorial will format the SQL behind a popup window so
it doesn’t get in our way; just click the “SQL” links to see what’s being generated.
The return value of create_engine() is an instance of Engine, and it represents the core interface to the
database, adapted through a dialect that handles the details of the database and DBAPI in use. In this case the SQLite
dialect will interpret instructions to the Python built-in sqlite3 module.
Lazy Connecting
The Engine, when first returned by create_engine(), has not actually tried to connect to the database
yet; that happens only the first time it is asked to perform a task against the database.
The first time a method like Engine.execute() or Engine.connect() is called, the Engine establishes a
real DBAPI connection to the database, which is then used to emit the SQL. When using the ORM, we typically don’t
use the Engine directly once created; instead, it’s used behind the scenes by the ORM as we’ll see shortly.
See also:
Database Urls - includes examples of create_engine() connecting to several kinds of databases with links to
more information.
When using the ORM, the configurational process starts by describing the database tables we’ll be dealing with, and
then by defining our own classes which will be mapped to those tables. In modern SQLAlchemy, these two tasks
are usually performed together, using a system known as Declarative, which allows us to create classes that include
directives to describe the actual database table they will be mapped to.
Classes mapped using the Declarative system are defined in terms of a base class which maintains a catalog of classes
and tables relative to that base - this is known as the declarative base class. Our application will usually have just one
instance of this base in a commonly imported module. We create the base class using the declarative_base()
function, as follows:
>>> from sqlalchemy.ext.declarative import declarative_base
Now that we have a “base”, we can define any number of mapped classes in terms of it. We will start with just a single
table called users, which will store records for the end-users using our application. A new class called User will
be the class to which we map this table. Within the class, we define details about the table to which we’ll be mapping,
primarily the table name, and names and datatypes of columns:
>>> from sqlalchemy import Column, Integer, String
>>> class User(Base):
... __tablename__ = 'users'
...
... id = Column(Integer, primary_key=True)
Tip
The User class defines a __repr__() method, but note that is optional; we only implement it in this tutorial
so that our examples show nicely formatted User objects.
A class using Declarative at a minimum needs a __tablename__ attribute, and at least one Column which is part of
a primary key 1 . SQLAlchemy never makes any assumptions by itself about the table to which a class refers, including
that it has no built-in conventions for names, datatypes, or constraints. But this doesn’t mean boilerplate is required;
instead, you’re encouraged to create your own automated conventions using helper functions and mixin classes, which
is described in detail at Mixin and Custom Base Classes.
When our class is constructed, Declarative replaces all the Column objects with special Python accessors known as
descriptors; this is a process known as instrumentation. The “instrumented” mapped class will provide us with the
means to refer to our table in a SQL context as well as to persist and load the values of columns from the database.
Outside of what the mapping process does to our class, the class remains otherwise mostly a normal Python class, to
which we can define any number of ordinary attributes and methods needed by our application.
With our User class constructed via the Declarative system, we have defined information about our table, known as
table metadata. The object used by SQLAlchemy to represent this information for a specific table is called the Table
object, and here Declarative has made one for us. We can see this object by inspecting the __table__ attribute:
>>> User.__table__
Table('users', MetaData(bind=None),
Column('id', Integer(), table=<users>, primary_key=True, nullable=False),
Column('name', String(), table=<users>),
Column('fullname', String(), table=<users>),
Column('password', String(), table=<users>), schema=None)
Classical Mappings
The Declarative system, though highly recommended, is not required in order to use SQLAlchemy’s ORM.
Outside of Declarative, any plain Python class can be mapped to any Table using the mapper() function
directly; this less common usage is described at Classical Mappings.
When we declared our class, Declarative used a Python metaclass in order to perform additional activities once the
class declaration was complete; within this phase, it then created a Table object according to our specifications, and
associated it with the class by constructing a Mapper object. This object is a behind-the-scenes object we normally
don’t need to deal with directly (though it can provide plenty of information about our mapping when we need it).
The Table object is a member of a larger collection known as MetaData. When using Declarative, this object is
available using the .metadata attribute of our declarative base class.
1 For information on why a primary key is required, see How do I map a table that has no primary key?.
The MetaData is a registry which includes the ability to emit a limited set of schema generation commands to
the database. As our SQLite database does not actually have a users table present, we can use MetaData
to issue CREATE TABLE statements to the database for all tables that don’t yet exist. Below, we call the
MetaData.create_all() method, passing in our Engine as a source of database connectivity. We will see
that special commands are first emitted to check for the presence of the users table, and following that the actual
CREATE TABLE statement:
>>> Base.metadata.create_all(engine)
SELECT ...
PRAGMA table_info("users")
()
CREATE TABLE users (
id INTEGER NOT NULL, name VARCHAR,
fullname VARCHAR,
password VARCHAR,
PRIMARY KEY (id)
)
()
COMMIT
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (
self.name, self.fullname, self.password)
We include this more verbose table definition separately to highlight the difference between a minimal construct
geared primarily towards in-Python usage only, versus one that will be used to emit CREATE TABLE statements
on a particular set of backends with more stringent requirements.
With mappings complete, let’s now create and inspect a User object:
Even though we didn’t specify it in the constructor, the id attribute still produces a value of None when we access
it (as opposed to Python’s usual behavior of raising AttributeError for an undefined attribute). SQLAlchemy’s
instrumentation normally produces this default value for column-mapped attributes when first accessed. For those
attributes where we’ve actually assigned a value, the instrumentation system is tracking those assignments for use
within an eventual INSERT statement to be emitted to the database.
We’re now ready to start talking to the database. The ORM’s “handle” to the database is the Session. When we first
set up the application, at the same level as our create_engine() statement, we define a Session class which
will serve as a factory for new Session objects:
>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=engine)
In the case where your application does not yet have an Engine when you define your module-level objects, just set
it up like this:
>>> Session = sessionmaker()
Later, when you create your engine with create_engine(), connect it to the Session using configure():
>>> Session.configure(bind=engine) # once engine is available
This custom-made Session class will create new Session objects which are bound to our database. Other trans-
actional characteristics may be defined when calling sessionmaker as well; these are described in a later chapter.
Then, whenever you need to have a conversation with the database, you instantiate a Session:
>>> session = Session()
The above Session is associated with our SQLite-enabled Engine, but it hasn’t opened any connections yet. When
it’s first used, it retrieves a connection from a pool of connections maintained by the Engine, and holds onto it until
we commit all changes and/or close the session object.
At this point, we say that the instance is pending; no SQL has yet been issued and the object is not yet represented by
a row in the database. The Session will issue the SQL to persist Ed Jones as soon as is needed, using a process
known as a flush. If we query the database for Ed Jones, all pending information will first be flushed, and the query
is issued immediately thereafter.
For example, below we create a new Query object which loads instances of User. We “filter by” the name attribute
of ed, and indicate that we’d like only the first result in the full list of rows. A User instance is returned which is
equivalent to that which we’ve added:
>>> our_user = session.query(User).filter_by(name='ed').first() # doctest:+NORMALIZE_WHITESPACE
BEGIN (implicit)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('ed', 'Ed Jones', 'edspassword')
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?
LIMIT ? OFFSET ?
('ed', 1, 0)
>>> our_user
<User(name='ed', fullname='Ed Jones', password='edspassword')>
In fact, the Session has identified that the row returned is the same row as one already represented within its internal
map of objects, so we actually got back the identical instance as that which we just added:
>>> ed_user is our_user
True
The ORM concept at work here is known as an identity map and ensures that all operations upon a particular row
within a Session operate upon the same set of data. Once an object with a particular primary key is present in the
Session, all SQL queries on that Session will always return the same Python object for that particular primary
key; it also will raise an error if an attempt is made to place a second, already-persisted object with the same primary
key within the session.
We can add more User objects at once using add_all():
>>> session.add_all([
... User(name='wendy', fullname='Wendy Williams', password='foobar'),
... User(name='mary', fullname='Mary Contrary', password='xxg527'),
... User(name='fred', fullname='Fred Flinstone', password='blah')])
Also, we’ve decided the password for Ed isn’t too secure, so lets change it:
>>> ed_user.password = 'f8s7ccs'
The Session is paying attention. It knows, for example, that Ed Jones has been modified:
>>> session.dirty
IdentitySet([<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>])
We tell the Session that we’d like to issue all remaining changes to the database and commit the transaction, which
has been in progress throughout. We do this via commit(). The Session emits the UPDATE statement for the
password change on “ed”, as well as INSERT statements for the three new User objects we’ve added:
>>> session.commit()
UPDATE users SET password=? WHERE users.id = ?
('f8s7ccs', 1)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('wendy', 'Wendy Williams', 'foobar')
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('mary', 'Mary Contrary', 'xxg527')
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('fred', 'Fred Flinstone', 'blah')
COMMIT
commit() flushes whatever remaining changes remain to the database, and commits the transaction. The connection
resources referenced by the session are now returned to the connection pool. Subsequent operations with this session
will occur in a new transaction, which will again re-acquire connection resources when first needed.
If we look at Ed’s id attribute, which earlier was None, it now has a value:
>>> ed_user.id # doctest: +NORMALIZE_WHITESPACE
BEGIN (implicit)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.id = ?
(1,)
1
After the Session inserts new rows in the database, all newly generated identifiers and database-generated defaults
become available on the instance, either immediately or via load-on-first-access. In this case, the entire row was re-
loaded on access because a new transaction was begun after we issued commit(). SQLAlchemy by default refreshes
data from a previous transaction the first time it’s accessed within a new transaction, so that the most recent state is
available. The level of reloading is configurable as is described in Using the Session.
Since the Session works within a transaction, we can roll back changes made too. Let’s make two changes that
we’ll revert; ed_user‘s user name gets set to Edwardo:
>>> ed_user.name = 'Edwardo'
Querying the session, we can see that they’re flushed into the current transaction:
>>> session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
UPDATE users SET name=? WHERE users.id = ?
('Edwardo', 1)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('fakeuser', 'Invalid', '12345')
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name IN (?, ?)
('Edwardo', 'fakeuser')
[<User(name='Edwardo', fullname='Ed Jones', password='f8s7ccs')>, <User(name='fakeuser', fullname='In
Rolling back, we can see that ed_user‘s name is back to ed, and fake_user has been kicked out of the session:
>>> session.rollback()
ROLLBACK
>>> ed_user.name
BEGIN (implicit)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.id = ?
(1,)
u'ed'
>>> fake_user in session
False
2.1.9 Querying
A Query object is created using the query() method on Session. This function takes a variable number of
arguments, which can be any combination of classes and class-instrumented descriptors. Below, we indicate a Query
which loads User instances. When evaluated in an iterative context, the list of User objects present is returned:
>>> for instance in session.query(User).order_by(User.id):
... print(instance.name, instance.fullname)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users ORDER BY users.id
()
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flinstone
The Query also accepts ORM-instrumented descriptors as arguments. Any time multiple class entities or column-
based entities are expressed as arguments to the query() function, the return result is expressed as tuples:
>>> for name, fullname in session.query(User.name, User.fullname):
... print(name, fullname)
SELECT users.name AS users_name,
users.fullname AS users_fullname
FROM users
()
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flinstone
The tuples returned by Query are named tuples, supplied by the KeyedTuple class, and can be treated much like
an ordinary Python object. The names are the same as the attribute’s name for an attribute, and the class name for a
class:
>>> for row in session.query(User, User.name).all():
... print(row.User, row.name)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
()
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')> ed
<User(name='wendy', fullname='Wendy Williams', password='foobar')> wendy
<User(name='mary', fullname='Mary Contrary', password='xxg527')> mary
<User(name='fred', fullname='Fred Flinstone', password='blah')> fred
You can control the names of individual column expressions using the label() construct, which is available from
any ColumnElement-derived object, as well as any class attribute which is mapped to one (such as User.name):
>>> for row in session.query(User.name.label('name_label')).all():
... print(row.name_label)
SELECT users.name AS name_label
FROM users
()
ed
wendy
mary
fred
The name given to a full entity such as User, assuming that multiple entities are present in the call to query(), can
be controlled using aliased() :
>>> from sqlalchemy.orm import aliased
>>> user_alias = aliased(User, name='user_alias')
Basic operations with Query include issuing LIMIT and OFFSET, most conveniently using Python array slices and
typically in conjunction with ORDER BY:
>>> for u in session.query(User).order_by(User.id)[1:3]:
... print(u)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users ORDER BY users.id
LIMIT ? OFFSET ?
(2, 1)
<User(name='wendy', fullname='Wendy Williams', password='foobar')>
<User(name='mary', fullname='Mary Contrary', password='xxg527')>
and filtering results, which is accomplished either with filter_by(), which uses keyword arguments:
>>> for name, in session.query(User.name).\
... filter_by(fullname='Ed Jones'):
... print(name)
SELECT users.name AS users_name FROM users
WHERE users.fullname = ?
('Ed Jones',)
ed
...or filter(), which uses more flexible SQL expression language constructs. These allow you to use regular
Python operators with the class-level attributes on your mapped class:
>>> for name, in session.query(User.name).\
... filter(User.fullname=='Ed Jones'):
... print(name)
SELECT users.name AS users_name FROM users
WHERE users.fullname = ?
('Ed Jones',)
ed
The Query object is fully generative, meaning that most method calls return a new Query object upon which
further criteria may be added. For example, to query for users named “ed” with a full name of “Ed Jones”, you can
call filter() twice, which joins criteria using AND:
>>> for user in session.query(User).\
... filter(User.name=='ed').\
... filter(User.fullname=='Ed Jones'):
... print(user)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ? AND users.fullname = ?
('ed', 'Ed Jones')
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
• not equals:
query.filter(User.name != 'ed')
• LIKE:
query.filter(User.name.like('%ed%'))
• IN :
query.filter(User.name.in_(['ed', 'wendy', 'jack']))
• NOT IN :
query.filter(~User.name.in_(['ed', 'wendy', 'jack']))
• IS NULL:
query.filter(User.name == None)
• IS NOT NULL:
query.filter(User.name != None)
• AND:
# use and_()
from sqlalchemy import and_
query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
Note: Make sure you use and_() and not the Python and operator!
• OR:
from sqlalchemy import or_
query.filter(or_(User.name == 'ed', User.name == 'wendy'))
Note: Make sure you use or_() and not the Python or operator!
• MATCH:
query.filter(User.name.match('wendy'))
Note: match() uses a database-specific MATCH or CONTAINS function; its behavior will vary by
backend and is not available on some backends such as SQLite.
A number of methods on Query immediately issue SQL and return a value containing loaded database results. Here’s
a brief tour:
• all() returns a list:
>>> query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
>>> query.all()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name LIKE ? ORDER BY users.id
('%ed',)
[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>,
<User(name='fred', fullname='Fred Flinstone', password='blah')>]
• first() applies a limit of one and returns the first result as a scalar:
>>> query.first()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
• one() fully fetches all rows, and if not exactly one object identity or composite row is present in the result,
raises an error. With multiple rows found:
>>> user = query.one()
Traceback (most recent call last):
...
MultipleResultsFound: Multiple rows were found for one()
The one() method is great for systems that expect to handle “no items found” versus “multiple items found”
differently; such as a RESTful web service, which may want to raise a “404 not found” when no results are
found, but raise an application error when multiple results are found.
• one_or_none() is like one(), except that if no results are found, it doesn’t raise an error; it just returns
None. Like one(), however, it does raise an error if multiple results are found.
• scalar() invokes the one() method, and upon success returns the first column of the row:
>>> query = session.query(User.id).filter(User.name == 'ed').\
... order_by(User.id)
>>> query.scalar()
SELECT users.id AS users_id
FROM users
WHERE users.name = ? ORDER BY users.id
('ed',)
1
Literal strings can be used flexibly with Query, by specifying their use with the text() construct, which is accepted
by most applicable methods. For example, filter() and order_by():
>>> from sqlalchemy import text
>>> for user in session.query(User).\
... filter(text("id<224")).\
... order_by(text("id")).all():
... print(user.name)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE id<224 ORDER BY id
()
ed
wendy
mary
fred
Bind parameters can be specified with string-based SQL, using a colon. To specify the values, use the params()
method:
>>> session.query(User).filter(text("id<:value and name=:name")).\
... params(value=224, name='fred').order_by(User.id).one()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE id<? and name=? ORDER BY users.id
(224, 'fred')
<User(name='fred', fullname='Fred Flinstone', password='blah')>
To use an entirely string-based statement, use from_statement(); just ensure that the columns clause of the
statement contains the column names normally used by the mapper (below illustrated using an asterisk):
>>> session.query(User).from_statement(
... text("SELECT * FROM users where name=:name")).\
... params(name='ed').all()
SELECT * FROM users where name=?
('ed',)
[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>]
See also:
Using Textual SQL - The text() construct explained from the perspective of Core-only queries.
Changed in version 1.0.0: The Query construct emits warnings when string SQL fragments are coerced to text(),
and text() should be used explicitly. See Warnings emitted when coercing full SQL fragments into text() for back-
ground.
Counting
Counting on count()
Query.count() used to be a very complicated method when it would try to guess whether or not a subquery
was needed around the existing query, and in some exotic cases it wouldn’t do the right thing. Now that it uses a
simple subquery every time, it’s only two lines long and always returns the right answer. Use func.count()
if a particular statement absolutely cannot tolerate the subquery being present.
The count() method is used to determine how many rows the SQL statement would return. Looking at the generated
SQL above, SQLAlchemy always places whatever it is we are querying into a subquery, then counts the rows from
that. In some cases this can be reduced to a simpler SELECT count(*) FROM table, however modern versions
of SQLAlchemy don’t try to guess when this is appropriate, as the exact SQL can be emitted using more explicit
means.
For situations where the “thing to be counted” needs to be indicated specifically, we can specify the “count” function
directly using the expression func.count(), available from the func construct. Below we use it to return the
count of each distinct user name:
>>> from sqlalchemy import func
>>> session.query(func.count(User.name), User.name).group_by(User.name).all()
SELECT count(users.name) AS count_1, users.name AS users_name
FROM users GROUP BY users.name
()
[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]
To achieve our simple SELECT count(*) FROM table, we can apply it as:
>>> session.query(func.count('*')).select_from(User).scalar()
SELECT count(?) AS count_1
FROM users
('*',)
4
The usage of select_from() can be removed if we express the count in terms of the User primary key directly:
>>> session.query(func.count(User.id)).scalar()
SELECT count(users.id) AS count_1
FROM users
()
4
Let’s consider how a second table, related to User, can be mapped and queried. Users in our system can store any
number of email addresses associated with their username. This implies a basic one to many association from the
users to a new table which stores email addresses, which we will call addresses. Using declarative, we define
this table along with its mapped class, Address:
>>> from sqlalchemy import ForeignKey
>>> from sqlalchemy.orm import relationship
The above class introduces the ForeignKey construct, which is a directive applied to Column that indicates that
values in this column should be constrained to be values present in the named remote column. This is a core feature
of relational databases, and is the “glue” that transforms an otherwise unconnected collection of tables to have rich
overlapping relationships. The ForeignKey above expresses that values in the addresses.user_id column
should be constrained to those values in the users.id column, i.e. its primary key.
A second directive, known as relationship(), tells the ORM that the Address class itself should be linked to
the User class, using the attribute Address.user. relationship() uses the foreign key relationships between
the two tables to determine the nature of this linkage, determining that Address.user will be many to one. An
additional relationship() directive is placed on the User mapped class under the attribute User.addresses.
In both relationship() directives, the parameter relationship.back_populates is assigned to refer to
the complementary attribute names; by doing so, each relationship() can make intelligent decision about the
same relationship as expressed in reverse; on one side, Address.user refers to a User instance, and on the other
side, User.addresses refers to a list of Address instances.
The reverse side of a many-to-one relationship is always one to many. A full catalog of available relationship()
configurations is at Basic Relationship Patterns.
The two complementing relationships Address.user and User.addresses are referred to as a bidirectional
relationship, and is a key feature of the SQLAlchemy ORM. The section Linking Relationships with Backref discusses
the “backref” feature in detail.
Arguments to relationship() which concern the remote class can be specified using strings, assuming the Declar-
ative system is in use. Once all mappings are complete, these strings are evaluated as Python expressions in order to
produce the actual argument, in the above case the User class. The names which are allowed during this evaluation
include, among other things, the names of all classes which have been created in terms of the declared base.
See the docstring for relationship() for more detail on argument style.
We’ll need to create the addresses table in the database, so we will issue another CREATE from our metadata,
which will skip over tables which have already been created:
>>> Base.metadata.create_all(engine)
PRAGMA...
CREATE TABLE addresses (
id INTEGER NOT NULL,
email_address VARCHAR NOT NULL,
user_id INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id)
)
()
COMMIT
Now when we create a User, a blank addresses collection will be present. Various collection types, such as sets
and dictionaries, are possible here (see Customizing Collection Access for details), but by default, the collection is a
Python list.
>>> jack = User(name='jack', fullname='Jack Bean', password='gjffdd')
>>> jack.addresses
[]
We are free to add Address objects on our User object. In this case we just assign a full list directly:
>>> jack.addresses = [
... Address(email_address='[email protected]'),
... Address(email_address='[email protected]')]
When using a bidirectional relationship, elements added in one direction automatically become visible in the other
direction. This behavior occurs based on attribute on-change events and is evaluated in Python, without using any
SQL:
>>> jack.addresses[1]
<Address(email_address='[email protected]')>
>>> jack.addresses[1].user
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
Let’s add and commit Jack Bean to the database. jack as well as the two Address members in the corresponding
addresses collection are both added to the session at once, using a process known as cascading:
>>> session.add(jack)
>>> session.commit()
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('jack', 'Jack Bean', 'gjffdd')
INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
('[email protected]', 5)
INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
('[email protected]', 5)
COMMIT
Querying for Jack, we get just Jack back. No SQL is yet issued for Jack’s addresses:
>>> jack = session.query(User).\
... filter_by(name='jack').one()
BEGIN (implicit)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?
('jack',)
>>> jack
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
When we accessed the addresses collection, SQL was suddenly issued. This is an example of a lazy loading
relationship. The addresses collection is now loaded and behaves just like an ordinary list. We’ll cover ways to
optimize the loading of this collection in a bit.
Now that we have two tables, we can show some more features of Query, specifically how to create queries that deal
with both tables at the same time. The Wikipedia page on SQL JOIN offers a good introduction to join techniques,
several of which we’ll illustrate here.
To construct a simple implicit join between User and Address, we can use Query.filter() to equate their
related columns together. Below we load the User and Address entities at once using this method:
>>> for u, a in session.query(User, Address).\
... filter(User.id==Address.user_id).\
... filter(Address.email_address=='[email protected]').\
... all():
... print(u)
... print(a)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password,
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM users, addresses
WHERE users.id = addresses.user_id
AND addresses.email_address = ?
('[email protected]',)
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
<Address(email_address='[email protected]')>
The actual SQL JOIN syntax, on the other hand, is most easily achieved using the Query.join() method:
>>> session.query(User).join(Address).\
... filter(Address.email_address=='[email protected]').\
... all()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
Query.join() knows how to join between User and Address because there’s only one foreign key between
them. If there were no foreign keys, or several, Query.join() works better when one of the following forms are
used:
query.join(Address, User.id==Address.user_id) # explicit condition
query.join(User.addresses) # specify relationship from left to right
query.join(Address, User.addresses) # same, with explicit target
query.join('addresses') # same, using a string
As you would expect, the same idea is used for “outer” joins, using the outerjoin() function:
query.outerjoin(User.addresses) # LEFT OUTER JOIN
The reference documentation for join() contains detailed information and examples of the calling styles accepted
by this method; join() is an important method at the center of usage for any SQL-fluent application.
Using Aliases
When querying across multiple tables, if the same table needs to be referenced more than once, SQL typically requires
that the table be aliased with another name, so that it can be distinguished against other occurrences of that table. The
Query supports this most explicitly using the aliased construct. Below we join to the Address entity twice, to
locate a user who has two distinct email addresses at the same time:
>>> from sqlalchemy.orm import aliased
>>> adalias1 = aliased(Address)
>>> adalias2 = aliased(Address)
>>> for username, email1, email2 in \
... session.query(User.name, adalias1.email_address, adalias2.email_address).\
... join(adalias1, User.addresses).\
... join(adalias2, User.addresses).\
... filter(adalias1.email_address=='[email protected]').\
... filter(adalias2.email_address=='[email protected]'):
... print(username, email1, email2)
SELECT users.name AS users_name,
addresses_1.email_address AS addresses_1_email_address,
addresses_2.email_address AS addresses_2_email_address
FROM users JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
JOIN addresses AS addresses_2
ON users.id = addresses_2.user_id
WHERE addresses_1.email_address = ?
AND addresses_2.email_address = ?
('[email protected]', '[email protected]')
jack [email protected] [email protected]
Using Subqueries
The Query is suitable for generating statements which can be used as subqueries. Suppose we wanted to load User
objects along with a count of how many Address records each user has. The best way to generate SQL like this is to
get the count of addresses grouped by user ids, and JOIN to the parent. In this case we use a LEFT OUTER JOIN so
that we get rows back for those users who don’t have any addresses, e.g.:
SELECT users.*, adr_count.address_count FROM users LEFT OUTER JOIN
(SELECT user_id, count(*) AS address_count
FROM addresses GROUP BY user_id) AS adr_count
ON users.id=adr_count.user_id
Using the Query, we build a statement like this from the inside out. The statement accessor returns a SQL
expression representing the statement generated by a particular Query - this is an instance of a select() construct,
which are described in SQL Expression Language Tutorial:
>>> from sqlalchemy.sql import func
>>> stmt = session.query(Address.user_id, func.count('*').\
... label('address_count')).\
... group_by(Address.user_id).subquery()
The func keyword generates SQL functions, and the subquery() method on Query produces a SQL
expression construct representing a SELECT statement embedded within an alias (it’s actually shorthand for
query.statement.alias()).
Once we have our statement, it behaves like a Table construct, such as the one we created for users at the start of
this tutorial. The columns on the statement are accessible through an attribute called c:
>>> for u, count in session.query(User, stmt.c.address_count).\
... outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id):
... print(u, count)
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password,
anon_1.address_count AS anon_1_address_count
FROM users LEFT OUTER JOIN
(SELECT addresses.user_id AS user_id, count(?) AS address_count
FROM addresses GROUP BY addresses.user_id) AS anon_1
ON users.id = anon_1.user_id
ORDER BY users.id
('*',)
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')> None
<User(name='wendy', fullname='Wendy Williams', password='foobar')> None
<User(name='mary', fullname='Mary Contrary', password='xxg527')> None
<User(name='fred', fullname='Fred Flinstone', password='blah')> None
<User(name='jack', fullname='Jack Bean', password='gjffdd')> 2
Above, we just selected a result that included a column from a subquery. What if we wanted our subquery to map to
an entity ? For this we use aliased() to associate an “alias” of a mapped class to a subquery:
Using EXISTS
The EXISTS keyword in SQL is a boolean operator which returns True if the given expression contains any rows. It
may be used in many scenarios in place of joins, and is also useful for locating rows which do not have a corresponding
row in a related table.
There is an explicit EXISTS construct, which looks like this:
>>> from sqlalchemy.sql import exists
>>> stmt = exists().where(Address.user_id==User.id)
>>> for name, in session.query(User.name).filter(stmt):
... print(name)
SELECT users.name AS users_name
FROM users
WHERE EXISTS (SELECT *
FROM addresses
WHERE addresses.user_id = users.id)
()
jack
The Query features several operators which make usage of EXISTS automatically. Above, the statement can be
expressed along the User.addresses relationship using any():
>>> for name, in session.query(User.name).\
... filter(User.addresses.any()):
... print(name)
SELECT users.name AS users_name
FROM users
WHERE EXISTS (SELECT 1
FROM addresses
WHERE users.id = addresses.user_id)
()
jack
has() is the same operator as any() for many-to-one relationships (note the ~ operator here too, which means
“NOT”):
>>> session.query(Address).\
... filter(~Address.user.has(User.name=='jack')).all()
SELECT addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE NOT (EXISTS (SELECT 1
FROM users
WHERE users.id = addresses.user_id AND users.name = ?))
('jack',)
[]
Here’s all the operators which build on relationships - each one is linked to its API documentation which includes full
details on usage and behavior:
• __eq__() (many-to-one “equals” comparison):
query.filter(Address.user == someuser)
Recall earlier that we illustrated a lazy loading operation, when we accessed the User.addresses collection of
a User and SQL was emitted. If you want to reduce the number of queries (dramatically, in many cases), we can
apply an eager load to the query operation. SQLAlchemy offers three types of eager loading, two of which are
automatic, and a third which involves custom criterion. All three are usually invoked via functions known as query
options which give additional instructions to the Query on how we would like various attributes to be loaded, via the
Query.options() method.
Subquery Load
In this case we’d like to indicate that User.addresses should load eagerly. A good choice for loading a set of
objects as well as their related collections is the orm.subqueryload() option, which emits a second SELECT
statement that fully loads the collections associated with the results just loaded. The name “subquery” originates from
the fact that the SELECT statement constructed directly via the Query is re-used, embedded as a subquery into a
SELECT against the related table. This is a little elaborate but very easy to use:
>>> from sqlalchemy.orm import subqueryload
>>> jack = session.query(User).\
... options(subqueryload(User.addresses)).\
... filter_by(name='jack').one()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?
('jack',)
SELECT addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id,
anon_1.users_id AS anon_1_users_id
FROM (SELECT users.id AS users_id
FROM users WHERE users.name = ?) AS anon_1
JOIN addresses ON anon_1.users_id = addresses.user_id
ORDER BY anon_1.users_id, addresses.id
('jack',)
>>> jack
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
>>> jack.addresses
[<Address(email_address='[email protected]')>, <Address(email_address='[email protected]')>]
Note: subqueryload() when used in conjunction with limiting such as Query.first(), Query.limit()
or Query.offset() should also include Query.order_by() on a unique column in order to ensure correct
results. See The Importance of Ordering.
Joined Load
The other automatic eager loading function is more well known and is called orm.joinedload(). This style
of loading emits a JOIN, by default a LEFT OUTER JOIN, so that the lead object as well as the related object or
collection is loaded in one step. We illustrate loading the same addresses collection in this way - note that even
though the User.addresses collection on jack is actually populated right now, the query will emit the extra join
regardless:
>>> from sqlalchemy.orm import joinedload
>>> jack
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
>>> jack.addresses
[<Address(email_address='[email protected]')>, <Address(email_address='[email protected]')>]
Note that even though the OUTER JOIN resulted in two rows, we still only got one instance of User back. This is
because Query applies a “uniquing” strategy, based on object identity, to the returned entities. This is specifically so
that joined eager loading can be applied without affecting the query results.
While joinedload() has been around for a long time, subqueryload() is a newer form of eager loading.
subqueryload() tends to be more appropriate for loading related collections while joinedload() tends to be
better suited for many-to-one relationships, due to the fact that only one row is loaded for both the lead and the related
object.
A third style of eager loading is when we are constructing a JOIN explicitly in order to locate the primary rows, and
would like to additionally apply the extra table to a related object or collection on the primary object. This feature is
supplied via the orm.contains_eager() function, and is most typically useful for pre-loading the many-to-one
object on a query that needs to filter on that same object. Below we illustrate loading an Address row as well as the
related User object, filtering on the User named “jack” and using orm.contains_eager() to apply the “user”
columns to the Address.user attribute:
>>> from sqlalchemy.orm import contains_eager
>>> jacks_addresses = session.query(Address).\
... join(Address.user).\
... filter(User.name=='jack').\
... options(contains_eager(Address.user)).\
... all()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password,
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses JOIN users ON users.id = addresses.user_id
WHERE users.name = ?
('jack',)
>>> jacks_addresses
[<Address(email_address='[email protected]')>, <Address(email_address='[email protected]')>]
>>> jacks_addresses[0].user
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
For more information on eager loading, including how to configure various forms of loading by default, see the section
Relationship Loading Techniques.
2.1.14 Deleting
Let’s try to delete jack and see how that goes. We’ll mark as deleted in the session, then we’ll issue a count query
to see that no rows remain:
>>> session.delete(jack)
>>> session.query(User).filter_by(name='jack').count()
UPDATE addresses SET user_id=? WHERE addresses.id = ?
((None, 1), (None, 2))
DELETE FROM users WHERE users.id = ?
(5,)
SELECT count(*) AS count_1
FROM (SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?) AS anon_1
('jack',)
0
addresses.user_id AS addresses_user_id
FROM addresses
WHERE addresses.email_address IN (?, ?)) AS anon_1
('[email protected]', '[email protected]')
2
Uh oh, they’re still there ! Analyzing the flush SQL, we can see that the user_id column of each address was set to
NULL, but the rows weren’t deleted. SQLAlchemy doesn’t assume that deletes cascade, you have to tell it to do so.
We will configure cascade options on the User.addresses relationship to change the behavior. While
SQLAlchemy allows you to add new attributes and relationships to mappings at any point in time, in this case the
existing relationship needs to be removed, so we need to tear down the mappings completely and start again - we’ll
close the Session:
>>> session.close()
ROLLBACK
Next we’ll declare the User class, adding in the addresses relationship including the cascade configuration (we’ll
leave the constructor out too):
>>> class User(Base):
... __tablename__ = 'users'
...
... id = Column(Integer, primary_key=True)
... name = Column(String)
... fullname = Column(String)
... password = Column(String)
...
... addresses = relationship("Address", back_populates='user',
... cascade="all, delete, delete-orphan")
...
... def __repr__(self):
... return "<User(name='%s', fullname='%s', password='%s')>" % (
... self.name, self.fullname, self.password)
Then we recreate Address, noting that in this case we’ve created the Address.user relationship via the User
class already:
>>> class Address(Base):
... __tablename__ = 'addresses'
... id = Column(Integer, primary_key=True)
... email_address = Column(String, nullable=False)
... user_id = Column(Integer, ForeignKey('users.id'))
... user = relationship("User", back_populates="addresses")
...
... def __repr__(self):
... return "<Address(email_address='%s')>" % self.email_address
Now when we load the user jack (below using get(), which loads by primary key), removing an address from the
corresponding addresses collection will result in that Address being deleted:
Deleting Jack will delete both Jack and the remaining Address associated with the user:
>>> session.delete(jack)
>>> session.query(User).filter_by(name='jack').count()
DELETE FROM addresses WHERE addresses.id = ?
(1,)
DELETE FROM users WHERE users.id = ?
(5,)
SELECT count(*) AS count_1
FROM (SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?) AS anon_1
('jack',)
0
>>> session.query(Address).filter(
... Address.email_address.in_(['[email protected]', '[email protected]'])
... ).count()
More on Cascades
Further detail on configuration of cascades is at Cascades. The cascade functionality can also integrate smoothly
with the ON DELETE CASCADE functionality of the relational database. See Using Passive Deletes for details.
We’re moving into the bonus round here, but lets show off a many-to-many relationship. We’ll sneak in some other
features too, just to take a tour. We’ll make our application a blog application, where users can write BlogPost
items, which have Keyword items associated with them.
For a plain many-to-many, we need to create an un-mapped Table construct to serve as the association table. This
looks like the following:
>>> from sqlalchemy import Table, Text
>>> # association table
>>> post_keywords = Table('post_keywords', Base.metadata,
... Column('post_id', ForeignKey('posts.id'), primary_key=True),
... Column('keyword_id', ForeignKey('keywords.id'), primary_key=True)
... )
Above, we can see declaring a Table directly is a little different than declaring a mapped class. Table is a con-
structor function, so each individual Column argument is separated by a comma. The Column object is also given
its name explicitly, rather than it being taken from an assigned attribute name.
Next we define BlogPost and Keyword, using complementary relationship() constructs, each referring to
the post_keywords table as an association table:
>>> class BlogPost(Base):
... __tablename__ = 'posts'
...
... id = Column(Integer, primary_key=True)
... user_id = Column(Integer, ForeignKey('users.id'))
... headline = Column(String(255), nullable=False)
... body = Column(Text)
...
... # many to many BlogPost<->Keyword
... keywords = relationship('Keyword',
... secondary=post_keywords,
... back_populates='posts')
...
... def __init__(self, headline, body, author):
... self.author = author
... self.headline = headline
... self.body = body
...
... def __repr__(self):
Note: The above class declarations illustrate explicit __init__() methods. Remember, when using Declarative,
it’s optional!
Above, the many-to-many relationship is BlogPost.keywords. The defining feature of a many-to-many rela-
tionship is the secondary keyword argument which references a Table object representing the association table.
This table only contains columns which reference the two sides of the relationship; if it has any other columns, such
as its own primary key, or foreign keys to other tables, SQLAlchemy requires a different usage pattern called the
“association object”, described at Association Object.
We would also like our BlogPost class to have an author field. We will add this as another bidirectional relation-
ship, except one issue we’ll have is that a single user might have lots of blog posts. When we access User.posts,
we’d like to be able to filter results further so as not to load the entire collection. For this we use a setting accepted by
relationship() called lazy=’dynamic’, which configures an alternate loader strategy on the attribute:
>>> BlogPost.author = relationship(User, back_populates="posts")
>>> User.posts = relationship(BlogPost, back_populates="author", lazy="dynamic")
Usage is not too different from what we’ve been doing. Let’s give Wendy some blog posts:
>>> wendy = session.query(User).\
... filter_by(name='wendy').\
... one()
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?
('wendy',)
We’re storing keywords uniquely in the database, but we know that we don’t have any yet, so we can just create them:
>>> post.keywords.append(Keyword('wendy'))
>>> post.keywords.append(Keyword('firstpost'))
We can now look up all blog posts with the keyword ‘firstpost’. We’ll use the any operator to locate “blog posts where
any of its keywords has the keyword string ‘firstpost”’:
>>> session.query(BlogPost).\
... filter(BlogPost.keywords.any(keyword='firstpost')).\
... all()
INSERT INTO keywords (keyword) VALUES (?)
('wendy',)
INSERT INTO keywords (keyword) VALUES (?)
('firstpost',)
INSERT INTO posts (user_id, headline, body) VALUES (?, ?, ?)
(2, "Wendy's Blog Post", 'This is a test')
INSERT INTO post_keywords (post_id, keyword_id) VALUES (?, ?)
(...)
SELECT posts.id AS posts_id,
posts.user_id AS posts_user_id,
posts.headline AS posts_headline,
posts.body AS posts_body
FROM posts
WHERE EXISTS (SELECT 1
FROM post_keywords, keywords
WHERE posts.id = post_keywords.post_id
AND keywords.id = post_keywords.keyword_id
AND keywords.keyword = ?)
('firstpost',)
[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', passw
If we want to look up posts owned by the user wendy, we can tell the query to narrow down to that User object as a
parent:
>>> session.query(BlogPost).\
... filter(BlogPost.author==wendy).\
... filter(BlogPost.keywords.any(keyword='firstpost')).\
... all()
SELECT posts.id AS posts_id,
posts.user_id AS posts_user_id,
posts.headline AS posts_headline,
posts.body AS posts_body
FROM posts
WHERE ? = posts.user_id AND (EXISTS (SELECT 1
FROM post_keywords, keywords
WHERE posts.id = post_keywords.post_id
AND keywords.id = post_keywords.keyword_id
AND keywords.keyword = ?))
(2, 'firstpost')
[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', passw
Or we can use Wendy’s own posts relationship, which is a “dynamic” relationship, to query straight from there:
>>> wendy.posts.\
... filter(BlogPost.keywords.any(keyword='firstpost')).\
... all()
SELECT posts.id AS posts_id,
posts.user_id AS posts_user_id,
posts.headline AS posts_headline,
posts.body AS posts_body
FROM posts
WHERE ? = posts.user_id AND (EXISTS (SELECT 1
FROM post_keywords, keywords
WHERE posts.id = post_keywords.post_id
AND keywords.id = post_keywords.keyword_id
AND keywords.keyword = ?))
(2, 'firstpost')
[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', passw
This section describes a variety of configurational patterns that are usable with mappers. It assumes you’ve worked
through Object Relational Tutorial and know how to construct and use rudimentary mappers and relationships.
Modern SQLAlchemy features two distinct styles of mapper configuration. The “Classical” style is SQLAlchemy’s
original mapping API, whereas “Declarative” is the richer and more succinct system that builds on top of “Classical”.
Both styles may be used interchangeably, as the end result of each is exactly the same - a user-defined class mapped
by the mapper() function onto a selectable unit, typically a Table.
Declarative Mapping
The Declarative Mapping is the typical way that mappings are constructed in modern SQLAlchemy. Making use of
the Declarative system, the components of the user-defined class as well as the Table metadata to which the class is
mapped are defined at once:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
password = Column(String)
Above, a basic single-table mapping with four columns. Additional attributes, such as relationships to other mapped
classes, are also declared inline within the class definition:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
password = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
user_id = Column(ForeignKey('user.id'))
email_address = Column(String)
The declarative mapping system is introduced in the Object Relational Tutorial. For additional details on how this
system works, see Declarative.
Classical Mappings
A Classical Mapping refers to the configuration of a mapped class using the mapper() function, without using the
Declarative system. This is SQLAlchemy’s original class mapping API, and is still the base mapping system provided
by the ORM.
In “classical” form, the table metadata is created separately with the Table construct, then associated with the User
class via the mapper() function:
from sqlalchemy import Table, MetaData, Column, Integer, String, ForeignKey
from sqlalchemy.orm import mapper
metadata = MetaData()
class User(object):
def __init__(self, name, fullname, password):
self.name = name
self.fullname = fullname
self.password = password
mapper(User, user)
Information about mapped attributes, such as relationships to other classes, are provided via the properties dictio-
nary. The example below illustrates a second Table object, mapped to a class called Address, then linked to User
via relationship():
address = Table('address', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey('user.id')),
Column('email_address', String(50))
)
mapper(Address, address)
When using classical mappings, classes must be provided directly without the benefit of the “string lookup” system
provided by Declarative. SQL expressions are typically specified in terms of the Table objects, i.e. address.c.id
above for the Address relationship, and not Address.id, as Address may not yet be linked to table metadata,
nor can we specify a string here.
Some examples in the documentation still use the classical approach, but note that the classical as well as Declarative
approaches are fully interchangeable. Both systems ultimately create the same configuration, consisting of a Table,
user-defined class, linked together with a mapper(). When we talk about “the behavior of mapper()”, this includes
when using the Declarative system as well - it’s still used, just behind the scenes.
The Mapper object is available from any mapped class, regardless of method, using the Runtime Inspection API
system. Using the inspect() function, one can acquire the Mapper from a mapped class:
>>> from sqlalchemy import inspect
>>> insp = inspect(User)
This is a namespace that can be viewed in a list format or via individual names:
>>> list(insp.columns)
[Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('name', String(lengt
>>> insp.columns.name
Column('name', String(length=50), table=<user>)
Other namespaces include Mapper.all_orm_descriptors, which includes all mapped attributes as well as
hybrids, association proxies:
>>> insp.all_orm_descriptors
<sqlalchemy.util._collections.ImmutableProperties object at 0x1040e2c68>
>>> insp.all_orm_descriptors.keys()
['fullname', 'password', 'name', 'id']
As well as Mapper.column_attrs:
>>> list(insp.column_attrs)
[<ColumnProperty at 0x10403fde0; id>, <ColumnProperty at 0x10403fce8; name>, <ColumnProperty at 0x104
>>> insp.column_attrs.name
<ColumnProperty at 0x10403fce8; name>
>>> insp.column_attrs.name.expression
Column('name', String(length=50), table=<user>)
See also:
Runtime Inspection API
Mapper
InstanceState
The following sections discuss how table columns and SQL expressions are mapped to individual object attributes.
The default behavior of mapper() is to assemble all the columns in the mapped Table into mapped object attributes,
each of which are named according to the name of the column itself (specifically, the key attribute of Column). This
behavior can be modified in several ways.
A mapping by default shares the same name for a Column as that of the mapped attribute - specifically it matches the
Column.key attribute on Column, which by default is the same as the Column.name.
The name assigned to the Python attribute which maps to Column can be different from either Column.name or
Column.key just by assigning it that way, as we illustrate here in a Declarative mapping:
class User(Base):
__tablename__ = 'user'
id = Column('user_id', Integer, primary_key=True)
name = Column('user_name', String(50))
Where above User.id resolves to a column named user_id and User.name resolves to a column named
user_name.
When mapping to an existing table, the Column object can be referenced directly:
class User(Base):
__table__ = user_table
id = user_table.c.user_id
name = user_table.c.user_name
Or in a classical mapping, placed in the properties dictionary with the desired key:
mapper(User, user_table, properties={
'id': user_table.c.user_id,
'name': user_table.c.user_name,
})
In the next section we’ll examine the usage of .key more closely.
In the previous section Naming Columns Distinctly from Attribute Names, we showed how a Column explicitly
mapped to a class can have a different attribute name than the column. But what if we aren’t listing out Column
objects explicitly, and instead are automating the production of Table objects using reflection (e.g. as described in
Reflecting Database Objects)? In this case we can make use of the DDLEvents.column_reflect() event to
intercept the production of Column objects and provide them with the Column.key of our choice:
@event.listens_for(Table, "column_reflect")
def column_reflect(inspector, table, column_info):
# set column.key = "attr_<lower_case_name>"
column_info['key'] = "attr_%s" % column_info['name'].lower()
With the above event, the reflection of Column objects will be intercepted with our event that adds a new ”.key”
element, such as in a mapping as below:
class MyClass(Base):
__table__ = Table("some_table", Base.metadata,
autoload=True, autoload_with=some_engine)
If we want to qualify our event to only react for the specific MetaData object above, we can check for it in our event:
@event.listens_for(Table, "column_reflect")
def column_reflect(inspector, table, column_info):
if table.metadata is Base.metadata:
# set column.key = "attr_<lower_case_name>"
column_info['key'] = "attr_%s" % column_info['name'].lower()
A quick approach to prefix column names, typically when mapping to an existing Table object, is to use
column_prefix:
class User(Base):
__table__ = user_table
__mapper_args__ = {'column_prefix':'_'}
The above will place attribute names such as _user_id, _user_name, _password etc. on the mapped User
class.
This approach is uncommon in modern usage. For dealing with reflected tables, a more flexible approach is to use that
described in Automating Column Naming Schemes from Reflected Tables.
Options can be specified when mapping a Column using the column_property() function. This function explic-
itly creates the ColumnProperty used by the mapper() to keep track of the Column; normally, the mapper()
creates this automatically. Using column_property(), we can pass additional arguments about how we’d like the
Column to be mapped. Below, we pass an option active_history, which specifies that a change to this column’s
value should result in the former value being loaded first:
from sqlalchemy.orm import column_property
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = column_property(Column(String(50)), active_history=True)
column_property() is also used to map a single attribute to multiple columns. This use case arises when mapping
to a join() which has attributes which are equated to each other:
class User(Base):
__table__ = user.join(address)
For more examples featuring this usage, see Mapping a Class against Multiple Tables.
Another place where column_property() is needed is to specify SQL expressions as mapped attributes, such as
below where we create an attribute fullname that is the string concatenation of the firstname and lastname
columns:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
firstname = Column(String(50))
lastname = Column(String(50))
fullname = column_property(firstname + " " + lastname)
Sometimes, a Table object was made available using the reflection process described at Reflecting Database Objects
to load the table’s structure from the database. For such a table that has lots of columns that don’t need to be referenced
in the application, the include_properties or exclude_properties arguments can specify that only a
subset of columns should be mapped. For example:
class User(Base):
__table__ = user_table
__mapper_args__ = {
'include_properties' :['user_id', 'user_name']
}
...will map the User class to the user_table table, only including the user_id and user_name columns - the
rest are not referenced. Similarly:
class Address(Base):
__table__ = address_table
__mapper_args__ = {
'exclude_properties' : ['street', 'city', 'state', 'zip']
}
...will map the Address class to the address_table table, including all columns present except street, city,
state, and zip.
When this mapping is used, the columns that are not included will not be referenced in any SELECT statements emitted
by Query, nor will there be any mapped attribute on the mapped class which represents the column; assigning an
attribute of that name will have no effect beyond that of a normal Python attribute assignment.
In some cases, multiple columns may have the same name, such as when mapping to a join of two or more tables that
share some column name. include_properties and exclude_properties can also accommodate Column
objects to more accurately describe which columns should be included or excluded:
class UserAddress(Base):
__table__ = user_table.join(addresses_table)
__mapper_args__ = {
'exclude_properties' :[address_table.c.id],
'primary_key' : [user_table.c.id]
}
Note: insert and update defaults configured on individual Column objects, i.e. those described at Col-
umn Insert/Update Defaults including those configured by the default, update, server_default and
server_onupdate arguments, will continue to function normally even if those Column objects are not mapped.
This is because in the case of default and update, the Column object is still present on the underlying Table,
thus allowing the default functions to take place when the ORM emits an INSERT or UPDATE, and in the case of
server_default and server_onupdate, the relational database itself maintains these functions.
Attributes on a mapped class can be linked to SQL expressions, which can be used in queries.
Using a Hybrid
The easiest and most flexible way to link relatively simple SQL expressions to a class is to use a so-called “hybrid
attribute”, described in the section Hybrid Attributes. The hybrid provides for an expression that works at both the
Python level as well as at the SQL expression level. For example, below we map a class User, containing attributes
firstname and lastname, and include a hybrid that will provide for us the fullname, which is the string
concatenation of the two:
from sqlalchemy.ext.hybrid import hybrid_property
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
firstname = Column(String(50))
lastname = Column(String(50))
@hybrid_property
def fullname(self):
return self.firstname + " " + self.lastname
Above, the fullname attribute is interpreted at both the instance and class level, so that it is available from an
instance:
some_user = session.query(User).first()
print some_user.fullname
The string concatenation example is a simple one, where the Python expression can be dual purposed at the instance
and class level. Often, the SQL expression must be distinguished from the Python expression, which can be achieved
using hybrid_property.expression(). Below we illustrate the case where a conditional needs to be present
inside the hybrid, using the if statement in Python and the sql.expression.case() construct for SQL expres-
sions:
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.sql import case
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
firstname = Column(String(50))
lastname = Column(String(50))
@hybrid_property
def fullname(self):
if self.firstname is not None:
return self.firstname + " " + self.lastname
else:
return self.lastname
@fullname.expression
def fullname(cls):
return case([
(cls.firstname != None, cls.firstname + " " + cls.lastname),
], else_ = cls.lastname)
Using column_property
The orm.column_property() function can be used to map a SQL expression in a manner similar to a regularly
mapped Column. With this technique, the attribute is loaded along with all other column-mapped attributes at load
time. This is in some cases an advantage over the usage of hybrids, as the value can be loaded up front at the same
time as the parent row of the object, particularly if the expression is one which links to other tables (typically as a
correlated subquery) to access data that wouldn’t normally be available on an already loaded object.
Disadvantages to using orm.column_property() for SQL expressions include that the expression must be com-
patible with the SELECT statement emitted for the class as a whole, and there are also some configurational quirks
which can occur when using orm.column_property() from declarative mixins.
Our “fullname” example can be expressed using orm.column_property() as follows:
from sqlalchemy.orm import column_property
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
firstname = Column(String(50))
lastname = Column(String(50))
fullname = column_property(firstname + " " + lastname)
Correlated subqueries may be used as well. Below we use the select() construct to create a SELECT that links
together the count of Address objects available for a particular User:
Base = declarative_base()
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user.id'))
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
address_count = column_property(
select([func.count(Address.id)]).\
where(Address.user_id==id).\
correlate_except(Address)
)
The meaning of the above statement is, select the count of Address.id rows where the Address.user_id
column is equated to id, which in the context of the User class is the Column named id (note that id is also the
name of a Python built in function, which is not what we want to use here - if we were outside of the User class
definition, we’d use User.id).
The select.correlate_except() directive indicates that each element in the FROM clause of this select()
may be omitted from the FROM list (that is, correlated to the enclosing SELECT statement against User) except for
the one corresponding to Address. This isn’t strictly necessary, but prevents Address from being inadvertently
omitted from the FROM list in the case of a long string of joins between User and Address tables where SELECT
statements against Address are nested.
If import issues prevent the column_property() from being defined inline with the class, it can be assigned to
the class after both are configured. In Declarative this has the effect of calling Mapper.add_property() to add
an additional property after the fact:
User.address_count = column_property(
select([func.count(Address.id)]).\
where(Address.user_id==User.id)
)
For many-to-many relationships, use and_() to join the fields of the association table to both tables in a relation,
illustrated here with a classical mapping:
from sqlalchemy import and_
)))
})
In cases where a SQL query more elaborate than what orm.column_property() or hybrid_property can
provide must be emitted, a regular Python function accessed as an attribute can be used, assuming the expression only
needs to be available on an already-loaded instance. The function is decorated with Python’s own @property deco-
rator to mark it as a read-only attribute. Within the function, object_session() is used to locate the Session
corresponding to the current object, which is then used to emit a query:
from sqlalchemy.orm import object_session
from sqlalchemy import select, func
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
firstname = Column(String(50))
lastname = Column(String(50))
@property
def address_count(self):
return object_session(self).\
scalar(
select([func.count(Address.id)]).\
where(Address.user_id==self.id)
)
The plain descriptor approach is useful as a last resort, but is less performant in the usual case than both the hybrid
and column property approaches, in that it needs to emit a SQL query upon each access.
Simple Validators
A quick way to add a “validation” routine to an attribute is to use the validates() decorator. An attribute validator
can raise an exception, halting the process of mutating the attribute’s value, or can change the given value into some-
thing different. Validators, like all attribute extensions, are only called by normal userland code; they are not issued
when the ORM is populating the object:
from sqlalchemy.orm import validates
class EmailAddress(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
@validates('email')
def validate_email(self, key, address):
assert '@' in address
return address
Changed in version 1.0.0: - validators are no longer triggered within the flush process when the newly fetched values
for primary key columns as well as some python- or server-side defaults are fetched. Prior to 1.0, validators may be
class User(Base):
# ...
addresses = relationship("Address")
@validates('addresses')
def validate_address(self, key, address):
assert '@' in address.email
return address
The validation function by default does not get emitted for collection remove events, as the typical expectation is that
a value being discarded doesn’t require validation. However, validates() supports reception of these events by
specifying include_removes=True to the decorator. When this flag is set, the validation function must receive
an additional boolean argument which if True indicates that the operation is a removal:
from sqlalchemy.orm import validates
class User(Base):
# ...
addresses = relationship("Address")
@validates('addresses', include_removes=True)
def validate_address(self, key, address, is_remove):
if is_remove:
raise ValueError(
"not allowed to remove items from the collection")
else:
assert '@' in address.email
return address
The case where mutually dependent validators are linked via a backref can also be tailored, using the
include_backrefs=False option; this option, when set to False, prevents a validation function from emitting
if the event occurs as a result of a backref:
from sqlalchemy.orm import validates
class User(Base):
# ...
@validates('addresses', include_backrefs=False)
def validate_address(self, key, address):
assert '@' in address.email
return address
sqlalchemy.orm.validates(*names, **kw)
Decorate a method as a ‘validator’ for one or more named properties.
Designates a method as a validator, a method which receives the name of the attribute as well as a value to
be assigned, or in the case of a collection, the value to be added to the collection. The function can then
raise validation exceptions to halt the process from continuing (where Python’s built-in ValueError and
AssertionError exceptions are reasonable choices), or can modify or replace the value before proceeding.
The function should otherwise return the given value.
Note that a validator for a collection cannot issue a load of that collection within the validation routine - this
usage raises an assertion to avoid recursion overflows. This is a reentrant condition which is not supported.
Parameters
• *names – list of attribute names to be validated.
• include_removes – if True, “remove” events will be sent as well - the validation func-
tion must accept an additional argument “is_remove” which will be a boolean.
New in version 0.7.7.
• include_backrefs – defaults to True; if False, the validation function will not emit
if the originator is an attribute event related via a backref. This can be used for bi-directional
validates() usage where only one validator should emit per attribute operation.
New in version 0.9.0.
See also:
Simple Validators - usage examples for validates()
A more comprehensive way to produce modified behavior for an attribute is to use descriptors. These are commonly
used in Python using the property() function. The standard SQLAlchemy technique for descriptors is to create
a plain descriptor, and to have it read/write from a mapped attribute with a different name. Below we illustrate this
using Python 2.6-style properties:
class EmailAddress(Base):
__tablename__ = 'email_address'
id = Column(Integer, primary_key=True)
@email.setter
def email(self, email):
self._email = email
The approach above will work, but there’s more we can add. While our EmailAddress object will shuttle the value
through the email descriptor and into the _email mapped attribute, the class level EmailAddress.email
attribute does not have the usual expression semantics usable with Query. To provide these, we instead use the
hybrid extension as follows:
from sqlalchemy.ext.hybrid import hybrid_property
class EmailAddress(Base):
__tablename__ = 'email_address'
id = Column(Integer, primary_key=True)
@hybrid_property
def email(self):
return self._email
@email.setter
def email(self, email):
self._email = email
The .email attribute, in addition to providing getter/setter behavior when we have an instance of EmailAddress,
also provides a SQL expression when used at the class level, that is, from the EmailAddress class directly:
from sqlalchemy.orm import Session
session = Session()
address = session.query(EmailAddress).\
filter(EmailAddress.email == '[email protected]').\
one()
SELECT address.email AS address_email, address.id AS address_id
FROM address
WHERE address.email = ?
('[email protected]',)
address.email = '[email protected]'
session.commit()
UPDATE address SET email=? WHERE address.id = ?
('[email protected]', 1)
COMMIT
The hybrid_property also allows us to change the behavior of the attribute, including defining separate
behaviors when the attribute is accessed at the instance level versus at the class/expression level, using the
hybrid_property.expression() modifier. Such as, if we wanted to add a host name automatically, we
might define two sets of string manipulation logic:
class EmailAddress(Base):
__tablename__ = 'email_address'
id = Column(Integer, primary_key=True)
@hybrid_property
def email(self):
"""Return the value of _email up until the last twelve
characters."""
return self._email[:-12]
@email.setter
def email(self, email):
"""Set the value of _email, tacking on the twelve character
value @example.com."""
@email.expression
def email(cls):
"""Produce a SQL expression that represents the value
of the _email column, minus the last twelve characters."""
Above, accessing the email property of an instance of EmailAddress will return the value of the _email at-
tribute, removing or adding the hostname @example.com from the value. When we query against the email
attribute, a SQL function is rendered which produces the same effect:
address = session.query(EmailAddress).filter(EmailAddress.email == 'address').one()
SELECT address.email AS address_email, address.id AS address_id
FROM address
WHERE substr(address.email, ?, length(address.email) - ?) = ?
(0, 12, 'address')
Synonyms
Synonyms are a mapper-level construct that allow any attribute on a class to “mirror” another attribute that is mapped.
In the most basic sense, the synonym is an easy way to make a certain attribute available by an additional name:
class MyClass(Base):
__tablename__ = 'my_table'
id = Column(Integer, primary_key=True)
job_status = Column(String(50))
status = synonym("job_status")
The above class MyClass has two attributes, .job_status and .status that will behave as one attribute, both
at the expression level:
>>> print MyClass.job_status == 'some_status'
my_table.job_status = :job_status_1
The synonym() can be used for any kind of mapped attribute that subclasses MapperProperty, including
mapped columns and relationships, as well as synonyms themselves.
Beyond a simple mirror, synonym() can also be made to reference a user-defined descriptor. We can supply our
status synonym with a @property:
class MyClass(Base):
__tablename__ = 'my_table'
id = Column(Integer, primary_key=True)
status = Column(String(50))
@property
def job_status(self):
return "Status: " + self.status
When using Declarative, the above pattern can be expressed more succinctly using the synonym_for() decorator:
from sqlalchemy.ext.declarative import synonym_for
class MyClass(Base):
__tablename__ = 'my_table'
id = Column(Integer, primary_key=True)
status = Column(String(50))
@synonym_for("status")
@property
def job_status(self):
return "Status: " + self.status
While the synonym() is useful for simple mirroring, the use case of augmenting attribute behavior with descriptors is
better handled in modern usage using the hybrid attribute feature, which is more oriented towards Python descriptors.
Technically, a synonym() can do everything that a hybrid_property can do, as it also supports injection of
custom SQL capabilities, but the hybrid is more straightforward to use in more complex situations.
sqlalchemy.orm.synonym(name, map_column=None, descriptor=None, comparator_factory=None,
doc=None, info=None)
Denote an attribute name as a synonym to a mapped property, in that the attribute will mirror the value and
expression behavior of another attribute.
Parameters
• name – the name of the existing mapped property. This can refer to the string name of
any MapperProperty configured on the class, including column-bound attributes and
relationships.
• descriptor – a Python descriptor that will be used as a getter (and potentially a setter)
when this attribute is accessed at the instance level.
• map_column – if True, the synonym() construct will locate the existing named
MapperProperty based on the attribute name of this synonym(), and assign it to a
new attribute linked to the name of this synonym(). That is, given a mapping like:
class MyClass(Base):
__tablename__ = 'my_table'
id = Column(Integer, primary_key=True)
job_status = Column(String(50))
The above class MyClass will now have the job_status Column object mapped to
the attribute named _job_status, and the attribute named job_status will refer to
the synonym itself. This feature is typically used in conjunction with the descriptor
argument in order to link a user-defined descriptor as a “wrapper” for an existing column.
• info – Optional data dictionary which will be populated into the
InspectionAttr.info attribute of this object.
New in version 1.0.0.
• comparator_factory – A subclass of PropComparator that will provide custom
comparison behavior at the SQL expression level.
Note: For the use case of providing an attribute which redefines both Python-level and
SQL-expression level behavior of an attribute, please refer to the Hybrid attribute introduced
at Using Descriptors and Hybrids for a more effective technique.
See also:
Synonyms - examples of functionality.
Using Descriptors and Hybrids - Hybrids provide a better approach for more complicated attribute-wrapping
schemes than synonyms.
Operator Customization
The “operators” used by the SQLAlchemy ORM and Core expression language are fully customizable. For exam-
ple, the comparison expression User.name == ’ed’ makes usage of an operator built into Python itself called
operator.eq - the actual SQL construct which SQLAlchemy associates with such an operator can be modified.
New operations can be associated with column expressions as well. The operators which take place for column ex-
pressions are most directly redefined at the type level - see the section Redefining and Creating New Operators for a
description.
ORM level functions like column_property(), relationship(), and composite() also provide for op-
erator redefinition at the ORM level, by passing a PropComparator subclass to the comparator_factory
argument of each function. Customization of operators at this level is a rare use case. See the documentation at
PropComparator for an overview.
Sets of columns can be associated with a single user-defined datatype. The ORM provides a single attribute which
represents the group of columns using the class you provide.
Changed in version 0.7: Composites have been simplified such that they no longer “conceal” the underlying column
based attributes. Additionally, in-place mutation is no longer automatic; see the section below on enabling mutability
to support tracking of in-place changes.
Changed in version 0.9: Composites will return their object-form, rather than as individual columns, when used in a
column-oriented Query construct. See Composite attributes are now returned as their object form when queried on
a per-attribute basis.
A simple example represents pairs of columns as a Point object. Point represents such a pair as .x and .y:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __composite_values__(self):
return self.x, self.y
def __repr__(self):
return "Point(x=%r, y=%r)" % (self.x, self.y)
The requirements for the custom datatype class are that it have a constructor which accepts positional arguments
corresponding to its column format, and also provides a method __composite_values__() which returns the
state of the object as a list or tuple, in order of its column-based attributes. It also should supply adequate __eq__()
and __ne__() methods which test the equality of two instances.
We will create a mapping to a table vertice, which represents two points as x1/y1 and x2/y2. These are created
normally as Column objects. Then, the composite() function is used to assign new attributes that will represent
sets of columns via the Point class:
from sqlalchemy import Column, Integer
from sqlalchemy.orm import composite
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Vertex(Base):
__tablename__ = 'vertice'
id = Column(Integer, primary_key=True)
x1 = Column(Integer)
y1 = Column(Integer)
x2 = Column(Integer)
y2 = Column(Integer)
A classical mapping above would define each composite() against the existing table:
mapper(Vertex, vertice_table, properties={
'start':composite(Point, vertice_table.c.x1, vertice_table.c.y1),
'end':composite(Point, vertice_table.c.x2, vertice_table.c.y2),
})
We can now persist and use Vertex instances, as well as query for them, using the .start and .end attributes
In-place changes to an existing composite value are not tracked automatically. Instead, the composite class needs to
provide events to its parent object explicitly. This task is largely automated via the usage of the MutableComposite
mixin, which uses events to associate each user-defined composite object with all parent associations. Please see the
example in Establishing Mutability on Composites.
Changed in version 0.7: In-place changes to an existing composite value are no longer tracked automatically; the
functionality is superseded by the MutableComposite class.
The “equals” comparison operation by default produces an AND of all corresponding columns equated to one another.
This can be changed using the comparator_factory argument to composite(), where we specify a custom
CompositeProperty.Comparator class to define existing or new operations. Below we illustrate the “greater
than” operator, implementing the same expression that the base “greater than” does:
from sqlalchemy.orm.properties import CompositeProperty
from sqlalchemy import sql
class PointComparator(CompositeProperty.Comparator):
def __gt__(self, other):
"""redefine the 'greater than' operation"""
class Vertex(Base):
___tablename__ = 'vertice'
id = Column(Integer, primary_key=True)
x1 = Column(Integer)
y1 = Column(Integer)
x2 = Column(Integer)
y2 = Column(Integer)
SQLAlchemy supports three forms of inheritance: single table inheritance, where several types of classes are repre-
sented by a single table, concrete table inheritance, where each type of class is represented by independent tables,
and joined table inheritance, where the class hierarchy is broken up among dependent tables, each class represented
by its own table that only includes those attributes local to that class.
The most common forms of inheritance are single and joined table, while concrete inheritance presents more configu-
rational challenges.
When mappers are configured in an inheritance relationship, SQLAlchemy has the ability to load elements polymor-
phically, meaning that a single query can return objects of multiple types.
In joined table inheritance, each class along a particular classes’ list of parents is represented by a unique table. The
total set of attributes for a particular instance is represented as a join along all tables in its inheritance path. Here, we
first define the Employee class. This table will contain a primary key column (or columns), and a column for each
attribute that’s represented by Employee. In this case it’s just name:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type
}
The mapped table also has a column called type. The purpose of this column is to act as the discriminator, and
stores a value which indicates the type of object represented within the row. The column may be of any datatype,
though string and integer are the most common.
Warning: Currently, only one discriminator column may be set, typically on the base-most class in the hierar-
chy. “Cascading” polymorphic columns are not yet supported.
The discriminator column is only needed if polymorphic loading is desired, as is usually the case. It is not strictly
necessary that it be present directly on the base mapped table, and can instead be defined on a derived select statement
that’s used when the class is queried; however, this is a much more sophisticated configuration scenario.
The mapping receives additional arguments via the __mapper_args__ dictionary. Here the type column is ex-
plicitly stated as the discriminator column, and the polymorphic identity of employee is also given; this is the value
that will be stored in the polymorphic discriminator column for instances of this class.
We next define Engineer and Manager subclasses of Employee. Each contains columns that represent the
attributes unique to the subclass they represent. Each table also must contain a primary key column (or columns), and
in most cases a foreign key reference to the parent table:
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
engineer_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'engineer',
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'manager',
}
It is standard practice that the same column is used for both the role of primary key as well as foreign key to the parent
table, and that the column is also named the same as that of the parent table. However, both of these practices are
optional. Separate columns may be used for primary key and parent-relationship, the column may be named differently
than that of the parent, and even a custom join condition can be specified between parent and child tables instead of
using a foreign key.
With the joined inheritance mapping complete, querying against Employee will return a combination of Employee,
Engineer and Manager objects. Newly saved Engineer, Manager, and Employee objects will automatically
populate the employee.type column with engineer, manager, or employee, as appropriate.
The orm.with_polymorphic() function and the with_polymorphic() method of Query affects the spe-
cific tables which the Query selects from. Normally, a query such as this:
session.query(Employee).all()
...selects only from the employee table. When loading fresh from the database, our joined-table setup will query
from the parent table only, using SQL such as this:
As attributes are requested from those Employee objects which are represented in either the engineer or
manager child tables, a second load is issued for the columns in that related row, if the data was not already loaded.
So above, after accessing the objects you’d see further SQL issued along the lines of:
This behavior works well when issuing searches for small numbers of items, such as when using Query.get(),
since the full range of joined tables are not pulled in to the SQL statement unnecessarily. But when querying a larger
span of rows which are known to be of many types, you may want to actively join to some or all of the joined tables.
The with_polymorphic feature provides this.
Telling our query to polymorphically load Engineer and Manager objects, we can use the
orm.with_polymorphic() function to create a new aliased class which represents a select of the base
table combined with outer joins to each of the inheriting tables:
query = session.query(eng_plus_manager)
The above produces a query which joins the employee table to both the engineer and manager tables like the
following:
query.all()
orm.with_polymorphic() accepts a single class or mapper, a list of classes/mappers, or the string ’*’ to
indicate all subclasses:
# join to the engineer table
entity = with_polymorphic(Employee, Engineer)
It also accepts a third argument selectable which replaces the automatic join creation and instead selects directly
from the selectable given. This feature is normally used with “concrete” inheritance, described later, but can be used
with any kind of inheritance setup in the case that specialized SQL should be used to load polymorphically:
# custom selectable
employee = Employee.__table__
manager = Manager.__table__
engineer = Engineer.__table__
entity = with_polymorphic(
Employee,
[Engineer, Manager],
employee.outerjoin(manager).outerjoin(engineer)
)
Note that if you only need to load a single subtype, such as just the Engineer objects,
orm.with_polymorphic() is not needed since you would query against the Engineer class directly.
Query.with_polymorphic() has the same purpose as orm.with_polymorphic(), except is not as flexible
in its usage patterns in that it only applies to the first full mapping, which then impacts all occurrences of that class or
the target subclasses within the Query. For simple cases it might be considered to be more succinct:
session.query(Employee).with_polymorphic([Engineer, Manager]).\
filter(or_(Engineer.engineer_info=='w', Manager.manager_data=='q'))
__mapper_args__ = {
'polymorphic_on':type,
'polymorphic_identity':'employee',
'with_polymorphic':'*'
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity':'engineer'}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity':'manager'}
The above mapping will produce a query similar to that of with_polymorphic(’*’) for every query of
Employee objects.
Using orm.with_polymorphic() or Query.with_polymorphic() will override the mapper-level
with_polymorphic setting.
sqlalchemy.orm.with_polymorphic(base, classes, selectable=False, flat=False, poly-
morphic_on=None, aliased=False, innerjoin=False,
_use_mapper_path=False, _existing_alias=None)
Produce an AliasedClass construct which specifies columns for descendant mappers of the given base.
New in version 0.8: orm.with_polymorphic() is in addition to the existing Query method
Query.with_polymorphic(), which has the same purpose but is not as flexible in its usage.
Using this method will ensure that each descendant mapper’s tables are included in the FROM clause, and will
allow filter() criterion to be used against those tables. The resulting instances will also have those columns
already loaded so that no “post fetch” of those columns will be required.
See the examples at Basic Control of Which Tables are Queried.
Parameters
• base – Base class to be aliased.
• classes – a single class or mapper, or list of class/mappers, which inherit from the base
class. Alternatively, it may also be the string ’*’, in which case all descending mapped
classes will be added to the FROM clause.
• aliased – when True, the selectable will be wrapped in an alias, that is (SELECT
* FROM <fromclauses>) AS anon_1. This can be important when using the
with_polymorphic() to create the target of a JOIN on a backend that does not support paren-
thesized joins, such as SQLite and older versions of MySQL.
• flat –
Boolean, will be passed through to the FromClause.alias() call so that aliases of
Join objects don’t include an enclosing SELECT. This can lead to more efficient queries
in many circumstances. A JOIN against a nested JOIN will be rewritten as a JOIN against
an aliased SELECT subquery on backends that don’t support this syntax.
Setting flat to True implies the aliased flag is also True.
New in version 0.9.0.
See also:
Join.alias()
• selectable – a table or select() statement that will be used in place of the generated
FROM clause. This argument is required if any of the desired classes use concrete table
inheritance, since SQLAlchemy currently cannot generate UNIONs among tables automati-
cally. If used, the selectable argument must represent the full set of tables and columns
mapped by every mapped class. Otherwise, the unaccounted mapped columns will result in
their table being appended directly to the FROM clause which will usually lead to incorrect
results.
• polymorphic_on – a column to be used as the “discriminator” column for the given
selectable. If not given, the polymorphic_on attribute of the base classes’ mapper will be
used, if any. This is useful for mappings that don’t have polymorphic loading behavior by
default.
• innerjoin – if True, an INNER JOIN will be used. This should only be specified if
querying for one specific subtype only
The with_polymorphic functions work fine for simplistic scenarios. However, direct control of table rendering is
called for, such as the case when one wants to render to only the subclass table and not the parent table.
This use case can be achieved by using the mapped Table objects directly. For example, to query the name of
employees with particular criterion:
engineer = Engineer.__table__
manager = Manager.__table__
session.query(Employee.name).\
outerjoin((engineer, engineer.c.employee_id==Employee.employee_id)).\
outerjoin((manager, manager.c.employee_id==Employee.employee_id)).\
filter(or_(Engineer.engineer_info=='w', Manager.manager_data=='q'))
The base table, in this case the “employees” table, isn’t always necessary. A SQL query is always more efficient
with fewer joins. Here, if we wanted to just load information specific to manager or engineer, we can instruct
Query to use only those tables. The FROM clause is determined by what’s specified in the Session.query(),
Query.filter(), or Query.select_from() methods:
session.query(Manager.manager_data).select_from(manager)
session.query(engineer.c.id).\
filter(engineer.c.engineer_info==manager.c.manager_data)
The of_type() method is a helper which allows the construction of joins along relationship() paths while
narrowing the criterion to specific subclasses. Suppose the employees table represents a collection of employees
which are associated with a Company object. We’ll add a company_id column to the employees table and a new
table companies:
class Company(Base):
__tablename__ = 'company'
id = Column(Integer, primary_key=True)
name = Column(String(50))
employees = relationship("Employee",
backref='company',
cascade='all, delete-orphan')
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
type = Column(String(20))
company_id = Column(Integer, ForeignKey('company.id'))
__mapper_args__ = {
'polymorphic_on':type,
'polymorphic_identity':'employee',
'with_polymorphic':'*'
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
engineer_info = Column(String(50))
__mapper_args__ = {'polymorphic_identity':'engineer'}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_data = Column(String(50))
__mapper_args__ = {'polymorphic_identity':'manager'}
When querying from Company onto the Employee relationship, the join() method as well as the any() and
has() operators will create a join from company to employee, without including engineer or manager in the
mix. If we wish to have criterion which is specifically against the Engineer class, we can tell those methods to join
or subquery against the joined table representing the subclass using the of_type() operator:
session.query(Company).\
join(Company.employees.of_type(Engineer)).\
filter(Engineer.engineer_info=='someinfo')
A longhand version of this would involve spelling out the full target selectable within a 2-tuple:
employee = Employee.__table__
engineer = Engineer.__table__
session.query(Company).\
join((employee.join(engineer), Company.employees)).\
filter(Engineer.engineer_info=='someinfo')
of_type() accepts a single class argument. More flexibility can be achieved either by joining to an explicit join as
above, or by using the orm.with_polymorphic() function to create a polymorphic selectable:
manager_and_engineer = with_polymorphic(
Employee, [Manager, Engineer],
aliased=True)
session.query(Company).\
join(manager_and_engineer, Company.employees).\
filter(
or_(manager_and_engineer.Engineer.engineer_info=='someinfo',
manager_and_engineer.Manager.manager_data=='somedata')
)
Above, we use the aliased=True argument with orm.with_polymorhpic() so that the right hand side of
the join between Company and manager_and_engineer is converted into an aliased subquery. Some backends,
such as SQLite and older versions of MySQL can’t handle a FROM clause of the following form:
FROM x JOIN (y JOIN z ON <onclause>) ON <onclause>
The above join can also be expressed more succinctly by combining of_type() with the polymorphic construct:
manager_and_engineer = with_polymorphic(
Employee, [Manager, Engineer],
aliased=True)
session.query(Company).\
join(Company.employees.of_type(manager_and_engineer)).\
filter(
or_(manager_and_engineer.Engineer.engineer_info=='someinfo',
manager_and_engineer.Manager.manager_data=='somedata')
)
The any() and has() operators also can be used with of_type() when the embedded criterion is in terms of a
subclass:
session.query(Company).\
filter(
Company.employees.of_type(Engineer).
any(Engineer.engineer_info=='someinfo')
).all()
Note that the any() and has() are both shorthand for a correlated EXISTS query. To build one by hand looks like:
session.query(Company).filter(
exists([1],
and_(Engineer.engineer_info=='someinfo',
employees.c.company_id==companies.c.company_id),
from_obj=employees.join(engineers)
)
).all()
The EXISTS subquery above selects from the join of employees to engineers, and also specifies criterion which
correlates the EXISTS subselect back to the parent companies table.
New in version 0.8: of_type() accepts orm.aliased() and orm.with_polymorphic() constructs in con-
junction with Query.join(), any() and has().
The joinedload(), subqueryload(), contains_eager() and other loading-related options also support
paths which make use of of_type(). Below we load Company rows while eagerly loading related Engineer
objects, querying the employee and engineer tables simultaneously:
session.query(Company).\
options(
subqueryload(Company.employees.of_type(Engineer)).
subqueryload("machines")
)
)
As is the case with Query.join(), of_type() also can be used with eager loading and
orm.with_polymorphic() at the same time, so that all sub-attributes of all referenced subtypes can be
loaded:
manager_and_engineer = with_polymorphic(
Employee, [Manager, Engineer],
aliased=True)
session.query(Company).\
options(
joinedload(Company.employees.of_type(manager_and_engineer))
)
)
)
)
New in version 1.0: Eager loaders such as joinedload() will create a polymorphic entity when multiple overlap-
ping of_type() directives are encountered.
Single table inheritance is where the attributes of the base class as well as all subclasses are represented within a single
table. A column is present in the table for every attribute mapped to the base class and all subclasses; the columns
which correspond to a single subclass are nullable. This configuration looks much like joined-table inheritance except
there’s only one table. In this case, a type column is required, as there would be no other way to discriminate between
classes. The table is specified in the base mapper only; for the inheriting classes, leave their table parameter blank:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(50))
engineer_info = Column(String(50))
type = Column(String(20))
__mapper_args__ = {
'polymorphic_on':type,
'polymorphic_identity':'employee'
}
class Manager(Employee):
__mapper_args__ = {
'polymorphic_identity':'manager'
}
class Engineer(Employee):
__mapper_args__ = {
'polymorphic_identity':'engineer'
}
Note that the mappers for the derived classes Manager and Engineer omit the __tablename__, indicating they do
not have a mapped table of their own.
This form of inheritance maps each class to a distinct table. As concrete inheritance has a bit more conceptual
overhead, first we’ll illustrate what these tables look like as Core table metadata:
employees_table = Table(
'employee', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50)),
)
managers_table = Table(
'manager', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50)),
Column('manager_data', String(50)),
engineers_table = Table(
'engineer', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50)),
Column('engineer_info', String(50)),
)
Notice in this case there is no type column; for polymorphic loading, additional steps will be needed in order to
“manufacture” this information during a query.
Using classical mapping, we can map our three classes independently without any relationship between them; the fact
that Engineer and Manager inherit from Employee does not have any impact on a classical mapping:
class Employee(object):
pass
class Manager(Employee):
pass
class Engineer(Employee):
pass
mapper(Employee, employees_table)
mapper(Manager, managers_table)
mapper(Engineer, engineers_table)
However when using Declarative, Declarative assumes an inheritance mapping between the classes because they
are already in an inheritance relationship. So to map our three classes declaratively, we must include the
orm.mapper.concrete parameter within the __mapper_args__:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(50))
__mapper_args__ = {
'concrete': True
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(50))
__mapper_args__ = {
'concrete': True
}
pjoin = polymorphic_union({
'employee': employees_table,
'manager': managers_table,
'engineer': engineers_table
}, 'type', 'pjoin')
SELECT
pjoin.id AS pjoin_id,
pjoin.name AS pjoin_name,
pjoin.type AS pjoin_type,
pjoin.manager_data AS pjoin_manager_data,
pjoin.engineer_info AS pjoin_engineer_info
FROM (
SELECT
employee.id AS id,
employee.name AS name,
CAST(NULL AS VARCHAR(50)) AS manager_data,
CAST(NULL AS VARCHAR(50)) AS engineer_info,
'employee' AS type
FROM employee
UNION ALL
SELECT
manager.id AS id,
manager.name AS name,
manager.manager_data AS manager_data,
CAST(NULL AS VARCHAR(50)) AS engineer_info,
'manager' AS type
FROM manager
UNION ALL
SELECT
engineer.id AS id,
engineer.name AS name,
CAST(NULL AS VARCHAR(50)) AS manager_data,
engineer.engineer_info AS engineer_info,
'engineer' AS type
FROM engineer
) AS pjoin
The above UNION query needs to manufacture “NULL” columns for each subtable in order to accommodate for those
columns that aren’t part of the mapping.
In order to map with concrete inheritance and polymorphic loading using Declarative, the challenge is to have the
polymorphic union ready to go when the mappings are created. One way to achieve this is to continue to define the
table metadata before the actual mapped classes, and specify them to each class using __table__:
class Employee(Base):
__table__ = employee_table
__mapper_args__ = {
'polymorphic_on':pjoin.c.type,
'with_polymorphic': ('*', pjoin),
'polymorphic_identity':'employee'
}
class Engineer(Employee):
__table__ = engineer_table
__mapper_args__ = {'polymorphic_identity':'engineer', 'concrete':True}
class Manager(Employee):
__table__ = manager_table
__mapper_args__ = {'polymorphic_identity':'manager', 'concrete':True}
Another way is to use a special helper class that takes on the fairly complicated task of deferring the production of
Mapper objects until all table metadata has been collected, and the polymorphic union to which the mappers will be
associated will be available. This is available via the AbstractConcreteBase and ConcreteBase classes. For
our example here, we’re using a “concrete” base, e.g. an Employee row can exist by itself that is not an Engineer
or a Manager. The mapping would look like:
from sqlalchemy.ext.declarative import ConcreteBase
__mapper_args__ = {
'polymorphic_identity':'employee',
'concrete':True
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
'polymorphic_identity':'manager',
'concrete':True
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
__mapper_args__ = {
'polymorphic_identity':'engineer',
'concrete':True
}
There is also the option to use a so-called “abstract” base; where we wont actually have an employee table at all,
and instead will only have manager and engineer tables. The Employee class will never be instantiated directly.
The change here is that the base mapper is mapped directly to the “polymorphic union” selectable, which no longer
includes the employee table. In classical mapping, this is:
from sqlalchemy.orm import polymorphic_union
pjoin = polymorphic_union({
'manager': managers_table,
'engineer': engineers_table
}, 'type', 'pjoin')
Using the Declarative helpers, the AbstractConcreteBase helper can produce this; the mapping would be:
from sqlalchemy.ext.declarative import AbstractConcreteBase
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
'polymorphic_identity':'manager',
'concrete':True
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
__mapper_args__ = {
'polymorphic_identity':'engineer',
'concrete':True
}
See also:
Concrete Table Inheritance - in the Declarative reference documentation
Both joined-table and single table inheritance scenarios produce mappings which are usable in relationship()
functions; that is, it’s possible to map a parent object to a child object which is polymorphic. Similarly, inheriting
mappers can have relationship() objects of their own at any level, which are inherited to each child class.
The only requirement for relationships is that there is a table relationship between parent and child. An example is
the following modification to the joined table inheritance example, which sets a bi-directional relationship between
Employee and Company:
employees_table = Table('employees', metadata,
Column('employee_id', Integer, primary_key=True),
Column('name', String(50)),
Column('company_id', Integer, ForeignKey('companies.company_id'))
)
class Company(object):
pass
In a concrete inheritance scenario, mapping relationships is more challenging since the distinct classes do not share
a table. In this case, you can establish a relationship from parent to child if a join condition can be constructed from
parent to child, if each child table contains a foreign key to the parent:
mapper(Employee, employees_table,
with_polymorphic=('*', pjoin),
polymorphic_on=pjoin.c.type,
polymorphic_identity='employee')
mapper(Manager, managers_table,
inherits=employee_mapper,
concrete=True,
polymorphic_identity='manager')
mapper(Engineer, engineers_table,
inherits=employee_mapper,
concrete=True,
polymorphic_identity='engineer')
The big limitation with concrete table inheritance is that relationship() objects placed on each concrete mapper
do not propagate to child mappers. If you want to have the same relationship() objects set up on all con-
crete mappers, they must be configured manually on each. To configure back references in such a configuration the
back_populates keyword may be used instead of backref, such as below where both A(object) and B(A)
bidirectionally reference C:
ajoin = polymorphic_union({
'a':a_table,
'b':b_table
}, 'type', 'ajoin')
})
mapper(B, b_table,inherits=A, concrete=True,
polymorphic_identity='b',
properties={
'some_c':relationship(C, back_populates='many_a')
})
mapper(C, c_table, properties={
'many_a':relationship(A, collection_class=set,
back_populates='some_c'),
})
Declarative makes inheritance configuration more intuitive. See the docs at Inheritance Configuration.
Mappers can be constructed against arbitrary relational units (called selectables) in addition to plain tables. For
example, the join() function creates a selectable unit comprised of multiple tables, complete with its own composite
primary key, which can be mapped in the same way as a Table:
from sqlalchemy import Table, Column, Integer, \
String, MetaData, join, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import column_property
metadata = MetaData()
Base = declarative_base()
# map to it
class AddressUser(Base):
__table__ = user_address_join
id = column_property(user_table.c.id, address_table.c.user_id)
address_id = address_table.c.id
In the example above, the join expresses columns for both the user and the address table. The user.id and
address.user_id columns are equated by foreign key, so in the mapping they are defined as one attribute,
AddressUser.id, using column_property() to indicate a specialized column mapping. Based on this part
of the configuration, the mapping will copy new primary key values from user.id into the address.user_id
column when a flush occurs.
Additionally, the address.id column is mapped explicitly to an attribute named address_id. This is to disam-
biguate the mapping of the address.id column from the same-named AddressUser.id attribute, which here
has been assigned to refer to the user table combined with the address.user_id foreign key.
The natural primary key of the above mapping is the composite of (user.id, address.id), as these are the
primary key columns of the user and address table combined together. The identity of an AddressUser object
will be in terms of these two values, and is represented from an AddressUser object as (AddressUser.id,
AddressUser.address_id).
Similar to mapping against a join, a plain select() object can be used with a mapper as well. The example fragment
below illustrates mapping a class called Customer to a select() which includes a join to a subquery:
from sqlalchemy import select, func
subq = select([
func.count(orders.c.id).label('order_count'),
func.max(orders.c.price).label('highest_order'),
orders.c.customer_id
]).group_by(orders.c.customer_id).alias()
class Customer(Base):
__table__ = customer_select
Above, the full row represented by customer_select will be all the columns of the customers table, in
addition to those columns exposed by the subq subquery, which are order_count, highest_order, and
customer_id. Mapping the Customer class to this selectable then creates a class which will contain those at-
tributes.
When the ORM persists new instances of Customer, only the customers table will actually receive an INSERT.
This is because the primary key of the orders table is not represented in the mapping; the ORM will only emit an
INSERT into a table for which it has mapped the primary key.
Note: The practice of mapping to arbitrary SELECT statements, especially complex ones as above, is almost never
needed; it necessarily tends to produce complex queries which are often less efficient than that which would be
produced by direct query construction. The practice is to some degree based on the very early history of SQLAlchemy
where the mapper() construct was meant to represent the primary querying interface; in modern usage, the Query
object can be used to construct virtually any SELECT statement, including complex composites, and should be favored
over the “map-to-selectable” approach.
In modern SQLAlchemy, a particular class is mapped by only one so-called primary mapper at a time. This mapper
is involved in three main areas of functionality: querying, persistence, and instrumentation of the mapped class. The
rationale of the primary mapper relates to the fact that the mapper() modifies the class itself, not only persisting it
towards a particular Table, but also instrumenting attributes upon the class which are structured specifically according
to the table metadata. It’s not possible for more than one mapper to be associated with a class in equal measure, since
only one mapper can actually instrument the class.
However, there is a class of mapper known as the non primary mapper with allows additional mappers to be associated
with a class, but with a limited scope of use. This scope typically applies to being able to load rows from an alternate
table or selectable unit, but still producing classes which are ultimately persisted using the primary mapping. The non-
primary mapper is created using the classical style of mapping against a class that is already mapped with a primary
mapper, and involves the use of the non_primary flag.
The non primary mapper is of very limited use in modern SQLAlchemy, as the task of being able to load classes from
subqueries or other compound statements can be now accomplished using the Query object directly.
There is really only one use case for the non-primary mapper, which is that we wish to build a relationship()
to such a mapper; this is useful in the rare and advanced case that our relationship is attempting to join two classes
together using many tables and/or joins in between. An example of this pattern is at Relationship to Non Primary
Mapper.
As far as the use case of a class that can actually be fully persisted to different tables under different scenarios, very
early versions of SQLAlchemy offered a feature for this adapted from Hibernate, known as the “entity name” feature.
However, this use case became infeasable within SQLAlchemy once the mapped class itself became the source of SQL
expression construction; that is, the class’ attributes themselves link directly to mapped table columns. The feature
was removed and replaced with a simple recipe-oriented approach to accomplishing this task without any ambiguity
of instrumentation - to create new subclasses, each mapped individually. This pattern is now available as a recipe at
Entity Name.
The Mapper supports management of a version id column, which is a single table column that increments or otherwise
updates its value each time an UPDATE to the mapped table occurs. This value is checked each time the ORM emits
an UPDATE or DELETE against the row to ensure that the value held in memory matches the database value.
Warning: Because the versioning feature relies upon comparison of the in memory record of an object, the
feature only applies to the Session.flush() process, where the ORM flushes individual in-memory rows to
the database. It does not take effect when performing a multirow UPDATE or DELETE using Query.update()
or Query.delete() methods, as these methods only emit an UPDATE or DELETE statement but otherwise do
not have direct access to the contents of those rows being affected.
The purpose of this feature is to detect when two concurrent transactions are modifying the same row at roughly the
same time, or alternatively to provide a guard against the usage of a “stale” row in a system that might be re-using data
from a previous transaction without refreshing (e.g. if one sets expire_on_commit=False with a Session, it
is possible to re-use the data from a previous transaction).
The most straightforward way to track versions is to add an integer column to the mapped table, then establish it as
the version_id_col within the mapper options:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
version_id = Column(Integer, nullable=False)
name = Column(String(50), nullable=False)
__mapper_args__ = {
"version_id_col": version_id
}
Above, the User mapping tracks integer versions using the column version_id. When an object of type User
is first flushed, the version_id column will be given a value of “1”. Then, an UPDATE of the table later on will
always be emitted in a manner similar to the following:
UPDATE user SET version_id=:version_id, name=:name
WHERE user.id = :user_id AND user.version_id = :user_version_id
{"name": "new name", "version_id": 2, "user_id": 1, "user_version_id": 1}
The above UPDATE statement is updating the row that not only matches user.id = 1, it also is requiring that
user.version_id = 1, where “1” is the last version identifier we’ve been known to use on this object. If a
transaction elsewhere has modified the row independently, this version id will no longer match, and the UPDATE
statement will report that no rows matched; this is the condition that SQLAlchemy tests, that exactly one row matched
our UPDATE (or DELETE) statement. If zero rows match, that indicates our version of the data is stale, and a
StaleDataError is raised.
Other kinds of values or counters can be used for versioning. Common types include dates and GUIDs.
When using an alternate type or counter scheme, SQLAlchemy provides a hook for this scheme using the
version_id_generator argument, which accepts a version generation callable. This callable is passed the value
of the current known version, and is expected to return the subsequent version.
For example, if we wanted to track the versioning of our User class using a randomly generated GUID, we could do
this (note that some backends support a native GUID type, but we illustrate here using a simple string):
import uuid
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
version_uuid = Column(String(32))
name = Column(String(50), nullable=False)
__mapper_args__ = {
'version_id_col':version_uuid,
'version_id_generator':lambda version: uuid.uuid4().hex
}
The persistence engine will call upon uuid.uuid4() each time a User object is subject to an INSERT or an UP-
DATE. In this case, our version generation function can disregard the incoming value of version, as the uuid4()
function generates identifiers without any prerequisite value. If we were using a sequential versioning scheme such
as numeric or a special character system, we could make use of the given version in order to help determine the
subsequent value.
See also:
Backend-agnostic GUID Type
The version_id_generator can also be configured to rely upon a value that is generated by the database. In
this case, the database would need some means of generating new identifiers when a row is subject to an INSERT as
well as with an UPDATE. For the UPDATE case, typically an update trigger is needed, unless the database in question
supports some other native version identifier. The Postgresql database in particular supports a system column called
xmin which provides UPDATE versioning. We can make use of the Postgresql xmin column to version our User
class as follows:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
xmin = Column("xmin", Integer, system=True)
__mapper_args__ = {
'version_id_col': xmin,
'version_id_generator': False
}
With the above mapping, the ORM will rely upon the xmin column for automatically providing the new value of the
version id counter.
The ORM typically does not actively fetch the values of database-generated values when it emits an INSERT or
UPDATE, instead leaving these columns as “expired” and to be fetched when they are next accessed, unless the
eager_defaults mapper() flag is set. However, when a server side version column is used, the ORM needs to
actively fetch the newly generated value. This is so that the version counter is set up before any concurrent transaction
may update it again. This fetching is also best done simultaneously within the INSERT or UPDATE statement using
RETURNING, otherwise if emitting a SELECT statement afterwards, there is still a potential race condition where
the version counter may change before it can be fetched.
When the target database supports RETURNING, an INSERT statement for our User class will look like this:
INSERT INTO "user" (name) VALUES (%(name)s) RETURNING "user".id, "user".xmin
{'name': 'ed'}
Where above, the ORM can acquire any newly generated primary key values along with server-generated version
identifiers in one statement. When the backend does not support RETURNING, an additional SELECT must be
emitted for every INSERT and UPDATE, which is much less efficient, and also introduces the possibility of missed
version counters:
INSERT INTO "user" (name) VALUES (%(name)s)
{'name': 'ed'}
It is strongly recommended that server side version counters only be used when absolutely necessary and only on
backends that support RETURNING, e.g. Postgresql, Oracle, SQL Server (though SQL Server has major caveats
when triggers are used), Firebird.
New in version 0.9.0: Support for server side version identifier tracking.
When version_id_generator is set to False, we can also programmatically (and conditionally) set the version
identifier on our object in the same way we assign any other mapped attribute. Such as if we used our UUID example,
but set version_id_generator to False, we can set the version identifier at our choosing:
import uuid
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
version_uuid = Column(String(32))
name = Column(String(50), nullable=False)
__mapper_args__ = {
'version_id_col':version_uuid,
'version_id_generator': False
}
u1 = User(name='u1', version_uuid=uuid.uuid4())
session.add(u1)
session.commit()
u1.name = 'u2'
u1.version_uuid = uuid.uuid4()
session.commit()
We can update our User object without incrementing the version counter as well; the value of the counter will remain
unchanged, and the UPDATE statement will still check against the previous value. This may be useful for schemes
where only certain classes of UPDATE are sensitive to concurrency issues:
# will leave version_uuid unchanged
u1.name = 'u3'
session.commit()
New in version 0.9.0: Support for programmatic and conditional version identifier tracking.
__mapper_args__ = {
'polymorphic_on' : type
}
Explicit use of mapper() is often referred to as classical mapping. The above declarative example is equivalent
in classical form to:
my_table = Table("my_table", metadata,
Column('id', Integer, primary_key=True),
Column('type', String(50)),
Column("some_alt", Integer)
)
class MyClass(object):
pass
mapper(MyClass, my_table,
polymorphic_on=my_table.c.type,
properties={
'alt':my_table.c.some_alt
})
See also:
Parameters
• class_ – The class to be mapped. When using Declarative, this argument is automatically
passed as the declared class itself.
• local_table – The Table or other selectable to which the class is mapped. May be
None if this mapper inherits from another mapper using single-table inheritance. When
using Declarative, this argument is automatically passed by the extension, based on what
is configured via the __table__ argument or via the Table produced as a result of the
__tablename__ and Column arguments present.
• always_refresh – If True, all query operations for this mapped class will overwrite all
data within object instances that already exist within the session, erasing any in-memory
changes with whatever information was loaded from the database. Usage of this flag is
highly discouraged; as an alternative, see the method Query.populate_existing().
• allow_partial_pks – Defaults to True. Indicates that a composite primary key with
some NULL values should be considered as possibly existing within the database. This
affects whether a mapper will assign an incoming row to an existing identity, as well as if
Session.merge() will check the database first for a particular primary key value. A
“partial primary key” can occur if one has mapped to an OUTER JOIN, for example.
• batch – Defaults to True, indicating that save operations of multiple entities can be
batched together for efficiency. Setting to False indicates that an instance will be fully
saved before saving the next instance. This is used in the extremely rare case that a
MapperEvents listener requires being called in between individual row persistence oper-
ations.
• column_prefix – A string which will be prepended to the mapped attribute name when
Column objects are automatically assigned as attributes to the mapped class. Does not
affect explicitly specified column-based properties.
See the section Naming All Columns with a Prefix for an example.
• concrete – If True, indicates this mapper should use concrete table inheritance with its
parent mapper.
See the section Concrete Table Inheritance for an example.
• confirm_deleted_rows – defaults to True; when a DELETE occurs of one more rows
based on specific primary keys, a warning is emitted when the number of rows matched does
not equal the number of rows expected. This parameter may be set to False to handle the
case where database ON DELETE CASCADE rules may be deleting some of those rows
automatically. The warning may be changed to an exception in a future release.
New in version 0.9.4: - added mapper.confirm_deleted_rows as well as condi-
tional matched row checking on delete.
• eager_defaults – if True, the ORM will immediately fetch the value of server-
generated default values after an INSERT or UPDATE, rather than leaving them as expired
to be fetched on next access. This can be used for event schemes where the server-generated
values are needed immediately before the flush completes. By default, this scheme will emit
an individual SELECT statement per row inserted or updated, which note can add significant
performance overhead. However, if the target database supports RETURNING, the default
values will be returned inline with the INSERT or UPDATE statement, which can greatly
enhance performance for an application that needs frequent access to just-generated server
defaults.
Changed in version 0.9.0: The eager_defaults option can now make use of RETURN-
ING for backends which support it.
• exclude_properties – A list or set of string column names to be excluded from map-
ping.
See Mapping a Subset of Table Columns for an example.
• extension – A MapperExtension instance or list of MapperExtension in-
stances which will be applied to all operations by this Mapper. Deprecated. Please see
MapperEvents.
• include_properties – An inclusive list or set of string column names to map.
See Mapping a Subset of Table Columns for an example.
• inherits – A mapped class or the corresponding Mapper of one indicating a superclass
to which this Mapper should inherit from. The mapped class here must be a subclass of
the other mapper’s class. When using Declarative, this argument is passed automatically as
a result of the natural class hierarchy of the declared classes.
See also:
Mapping Class Inheritance Hierarchies
• inherit_condition – For joined table inheritance, a SQL expression which will define
how the two tables are joined; defaults to a natural join between the two tables.
• inherit_foreign_keys – When inherit_condition is used and the columns
present are missing a ForeignKey configuration, this parameter can be used to specify
which columns are “foreign”. In most cases can be left as None.
• legacy_is_orphan – Boolean, defaults to False. When True, specifies that “legacy”
orphan consideration is to be applied to objects mapped by this mapper, which means that
a pending (that is, not persistent) object is auto-expunged from an owning Session only
when it is de-associated from all parents that specify a delete-orphan cascade towards
this mapper. The new default behavior is that the object is auto-expunged when it is de-
associated with any of its parents that specify delete-orphan cascade. This behavior is
more consistent with that of a persistent object, and allows behavior to be consistent in more
scenarios independently of whether or not an orphanable object has been flushed yet or not.
See the change note and example at The consideration of a “pending” object as an “or-
phan” has been made more aggressive for more detail on this change.
New in version 0.8: - the consideration of a pending object as an “orphan” has been mod-
ified to more closely match the behavior as that of persistent objects, which is that the
object is expunged from the Session as soon as it is de-associated from any of its orphan-
enabled parents. Previously, the pending object would be expunged only if de-associated
from all of its orphan-enabled parents. The new flag legacy_is_orphan is added to
orm.mapper() which re-establishes the legacy behavior.
• non_primary – Specify that this Mapper is in addition to the “primary” mapper, that is,
the one used for persistence. The Mapper created here may be used for ad-hoc mapping of
the class to an alternate selectable, for loading only.
Mapper.non_primary is not an often used option, but is useful in some specific
relationship() cases.
See also:
Relationship to Non Primary Mapper
• order_by – A single Column or list of Column objects for which selection operations
should use as the default ordering for entities. By default mappers have no pre-defined
ordering.
• passive_updates – Indicates UPDATE behavior of foreign key columns when a pri-
mary key column changes on a joined-table inheritance mapping. Defaults to True.
When True, it is assumed that ON UPDATE CASCADE is configured on the foreign key in
the database, and that the database will handle propagation of an UPDATE from a source
column to dependent columns on joined-table rows.
When False, it is assumed that the database does not enforce referential integrity and will
not be issuing its own CASCADE operation for an update. The unit of work process will
emit an UPDATE statement for the dependent columns during a primary key change.
See also:
Mutable Primary Keys / Update Cascades - description of a similar feature as used with
relationship()
• polymorphic_on – Specifies the column, attribute, or SQL expression used to determine
the target class for an incoming row, when inheriting classes are present.
This value is commonly a Column object that’s present in the mapped Table:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
discriminator = Column(String(50))
__mapper_args__ = {
"polymorphic_on":discriminator,
"polymorphic_identity":"employee"
}
It may also be specified as a SQL expression, as in this example where we use the case()
construct to provide a conditional approach:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
discriminator = Column(String(50))
__mapper_args__ = {
"polymorphic_on":case([
(discriminator == "EN", "engineer"),
(discriminator == "MA", "manager"),
], else_="employee"),
"polymorphic_identity":"employee"
}
It may also refer to any attribute configured with column_property(), or to the string
name of one:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
discriminator = Column(String(50))
employee_type = column_property(
case([
(discriminator == "EN", "engineer"),
(discriminator == "MA", "manager"),
], else_="employee")
)
__mapper_args__ = {
"polymorphic_on":employee_type,
"polymorphic_identity":"employee"
}
Where above, we assign the value of polymorphic_identity for the mapped class to
the discriminator attribute, thus persisting the value to the discriminator column
in the database.
Warning: Currently, only one discriminator column may be set, typically on the
base-most class in the hierarchy. “Cascading” polymorphic columns are not yet sup-
ported.
See also:
Mapping Class Inheritance Hierarchies
• polymorphic_identity – Specifies the value which identifies this particular class as
returned by the column expression referred to by the polymorphic_on setting. As rows
are received, the value corresponding to the polymorphic_on column expression is com-
pared to this value, indicating which subclass should be used for the newly reconstructed
object.
• properties – A dictionary mapping the string names of object attributes to
MapperProperty instances, which define the persistence behavior of that attribute.
Note that Column objects present in the mapped Table are automatically placed into
ColumnProperty instances upon mapping, unless overridden. When using Declarative,
this argument is passed automatically, based on all those MapperProperty instances
declared in the declared class body.
• primary_key – A list of Column objects which define the primary key to be used
against this mapper’s selectable unit. This is normally simply the primary key of the
def generate_version(version):
return next_version
sqlalchemy.orm.object_mapper(instance)
Given an object, return the primary Mapper associated with the object instance.
Raises sqlalchemy.orm.exc.UnmappedInstanceError if no mapping is configured.
This function is available via the inspection system as:
inspect(instance).mapper
Using the inspection system will raise sqlalchemy.exc.NoInspectionAvailable if the class is not
mapped.
sqlalchemy.orm.configure_mappers()
Initialize the inter-mapper relationships of all mappers that have been constructed thus far.
This function can be called any number of times, but in most cases is invoked automatically, the first time
mappings are used, as well as whenever mappings are used and additional not-yet-configured mappers have
been constructed.
Points at which this occur include when a mapped class is instantiated into an instance, as well as when the
Session.query() method is used.
The configure_mappers() function provides several event hooks that can be used to augment its func-
tionality. These methods include:
•MapperEvents.before_configured() - called once before configure_mappers() does
any work; this can be used to establish additional options, properties, or related mappings before the
operation proceeds.
•MapperEvents.mapper_configured() - called as each indivudal Mapper is configured within
the process; will include all mapper state except for backrefs set up by other mappers that are still to be
configured.
•MapperEvents.after_configured() - called once after configure_mappers() is com-
plete; at this stage, all Mapper objects that are known to SQLAlchemy will be fully configured. Note
that the calling application may still have other mappings that haven’t been produced yet, such as if they
are in modules as yet unimported.
sqlalchemy.orm.clear_mappers()
Remove all mappers from all classes.
This function removes all instrumentation from classes and disposes of their associated mappers. Once called,
the classes are unmapped and can be later re-mapped with new mappers.
clear_mappers() is not for normal use, as there is literally no valid usage for it outside of very specific test-
ing scenarios. Normally, mappers are permanent structural components of user-defined classes, and are never
discarded independently of their class. If a mapped class itself is garbage collected, its mapper is automati-
cally disposed of as well. As such, clear_mappers() is only for usage in test suites that re-use the same
classes with different mappings, which is itself an extremely rare use case - the only such use case is in fact
SQLAlchemy’s own test suite, and possibly the test suites of other ORM extension libraries which intend to test
various combinations of mapper construction upon a fixed set of classes.
sqlalchemy.orm.util.identity_key(*args, **kwargs)
Generate “identity key” tuples, as are used as keys in the Session.identity_map dictionary.
This function has several call styles:
•identity_key(class, ident)
This form receives a mapped class and a primary key scalar or tuple as an argument.
E.g.:
>>> identity_key(MyClass, (1, 2))
(<class '__main__.MyClass'>, (1, 2))
•identity_key(instance=instance)
This form will produce the identity key for a given instance. The instance need not be persistent, only that
its primary key attributes are populated (else the key will contain None for those missing values).
E.g.:
>>> instance = MyClass(1, 2)
>>> identity_key(instance=instance)
(<class '__main__.MyClass'>, (1, 2))
mapper = inspect(MyClass)
A class which was mapped by the sqlalchemy.ext.declarative extension will also have its mapper
available via the __mapper__ attribute.
__init__(class_, local_table=None, properties=None, primary_key=None, non_primary=False,
inherits=None, inherit_condition=None, inherit_foreign_keys=None, exten-
sion=None, order_by=False, always_refresh=False, version_id_col=None, ver-
sion_id_generator=None, polymorphic_on=None, _polymorphic_map=None, polymor-
phic_identity=None, concrete=False, with_polymorphic=None, allow_partial_pks=True,
batch=True, column_prefix=None, include_properties=None, exclude_properties=None,
passive_updates=True, confirm_deleted_rows=True, eager_defaults=False,
legacy_is_orphan=False, _compiled_cache_size=100)
Construct a new Mapper object.
This constructor is mirrored as a public API function; see mapper() for a full usage and argument
description.
add_properties(dict_of_properties)
Add the given dictionary of properties to this mapper, using add_property.
add_property(key, prop)
Add an individual MapperProperty to this mapper.
If the mapper has not been configured yet, just adds the property to the initial properties dictionary sent to
the constructor. If this Mapper has already been configured, then the given MapperProperty is configured
immediately.
all_orm_descriptors
A namespace of all InspectionAttr attributes associated with the mapped class.
These attributes are in all cases Python descriptors associated with the mapped class or its superclasses.
This namespace includes attributes that are mapped to the class as well as attributes declared by extension
modules. It includes any Python descriptor type that inherits from InspectionAttr. This includes
QueryableAttribute, as well as extension types such as hybrid_property, hybrid_method
and AssociationProxy.
To distinguish between mapped attributes and extension attributes, the attribute
InspectionAttr.extension_type will refer to a constant that distinguishes between dif-
ferent extension types.
When dealing with a QueryableAttribute, the QueryableAttribute.property attribute
refers to the MapperProperty property, which is what you get when referring to the collection of
mapped properties via Mapper.attrs.
See also:
Mapper.all_orm_descriptors
base_mapper = None
The base-most Mapper in an inheritance chain.
In a non-inheriting scenario, this attribute will always be this Mapper. In an inheritance scenario, it
references the Mapper which is parent to all other Mapper objects in the inheritance chain.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
c = None
A synonym for columns.
Note: the "all" cascade is not accepted here. For a generic object traversal function,
see How do I walk all objects that are related to a given object?.
• state – The lead InstanceState. child items will be processed per the relationships de-
fined for this object’s mapper.
Returns the method yields individual object instances.
See also:
Cascades
How do I walk all objects that are related to a given object? - illustrates a generic function to traverse all
objects without relying on cascades.
class_ = None
The Python class which this Mapper maps.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
class_manager = None
The ClassManager which maintains event listeners and class-bound descriptors for this Mapper.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
column_attrs
Return a namespace of all ColumnProperty properties maintained by this Mapper.
See also:
Mapper.attrs - namespace of all MapperProperty objects.
columns = None
A collection of Column or other scalar expression objects maintained by this Mapper.
The collection behaves the same as that of the c attribute on any Table object, except that only those
columns included in this mapping are present, and are keyed based on the attribute name defined in the
mapping, not necessarily the key attribute of the Column itself. Additionally, scalar expressions mapped
by column_property() are also present here.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
common_parent(other)
Return true if the given mapper shares a common inherited parent as this mapper.
composites
Return a namespace of all CompositeProperty properties maintained by this Mapper.
See also:
Mapper.attrs - namespace of all MapperProperty objects.
concrete = None
Represent True if this Mapper is a concrete inheritance mapper.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
configured = None
Represent True if this Mapper has been configured.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
See also:
configure_mappers().
entity
Part of the inspection API.
Returns self.class_.
get_property(key, _configure_mappers=True)
return a MapperProperty associated with the given key.
get_property_by_column(column)
Given a Column object, return the MapperProperty which maps this column.
identity_key_from_instance(instance)
Return the identity key for the given instance, based on its primary key attributes.
If the instance’s state is expired, calling this method will result in a database check to see if the object has
been deleted. If the row no longer exists, ObjectDeletedError is raised.
This value is typically also found on the instance state under the attribute name key.
identity_key_from_primary_key(primary_key)
Return an identity-map key for use in storing/retrieving an item from an identity map.
Parameters primary_key – A list of values indicating the identifier.
identity_key_from_row(row, adapter=None)
Return an identity-map key for use in storing/retrieving an item from the identity map.
Parameters row – A RowProxy instance. The columns which are mapped by this
Mapper should be locatable in the row, preferably via the Column object directly (as
is the case when a select() construct is executed), or via string names of the form
<tablename>_<colname>.
inherits = None
References the Mapper which this Mapper inherits from, if any.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
is_mapper = True
Part of the inspection API.
isa(other)
Return True if the this mapper inherits from the given mapper.
iterate_properties
return an iterator of all MapperProperty objects.
local_table = None
The Selectable which this Mapper manages.
Typically is an instance of Table or Alias. May also be None.
The “local” table is the selectable that the Mapper is directly responsible for managing from an attribute
access and flush perspective. For non-inheriting mappers, the local table is the same as the “mapped” table.
For joined-table inheritance mappers, local_table will be the particular sub-table of the overall “join” which
this Mapper represents. If this mapper is a single-table inheriting mapper, local_table will be None.
See also:
mapped_table.
mapped_table = None
The Selectable to which this Mapper is mapped.
Typically an instance of Table, Join, or Alias.
The “mapped” table is the selectable that the mapper selects from during queries. For non-inheriting map-
pers, the mapped table is the same as the “local” table. For joined-table inheritance mappers, mapped_table
references the full Join representing full rows for this particular subclass. For single-table inheritance
mappers, mapped_table references the base table.
See also:
local_table.
mapper
Part of the inspection API.
Returns self.
non_primary = None
Represent True if this Mapper is a “non-primary” mapper, e.g. a mapper that is used only to selet rows
but not for persistence management.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
polymorphic_identity = None
Represent an identifier which is matched against the polymorphic_on column during result row load-
ing.
Used only with inheritance, this object can be of any type which is comparable to the type of column
represented by polymorphic_on.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
polymorphic_iterator()
Iterate through the collection including this mapper and all descendant mappers.
This includes not just the immediately inheriting mappers but all their inheriting mappers as well.
To iterate through an entire hierarchy, use mapper.base_mapper.polymorphic_iterator().
polymorphic_map = None
A mapping of “polymorphic identity” identifiers mapped to Mapper instances, within an inheritance
scenario.
The identifiers can be of any type which is comparable to the type of column represented by
polymorphic_on.
An inheritance chain of mappers will all reference the same polymorphic map object. The object is used
to correlate incoming result rows to target mappers.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
polymorphic_on = None
The Column or SQL expression specified as the polymorphic_on argument for this Mapper, within
an inheritance scenario.
This attribute is normally a Column instance but may also be an expression, such as one derived from
cast().
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
primary_key = None
An iterable containing the collection of Column objects which comprise the ‘primary key’ of the mapped
table, from the perspective of this Mapper.
This list is against the selectable in mapped_table. In the case of inheriting mappers, some columns
may be managed by a superclass mapper. For example, in the case of a Join, the primary key is deter-
mined by all of the primary key columns across all tables referenced by the Join.
The list is also not necessarily the same as the primary key column collection associated with the un-
derlying tables; the Mapper features a primary_key argument that can override what the Mapper
considers as primary key columns.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
primary_key_from_instance(instance)
Return the list of primary key values for the given instance.
If the instance’s state is expired, calling this method will result in a database check to see if the object has
been deleted. If the row no longer exists, ObjectDeletedError is raised.
primary_mapper()
Return the primary mapper corresponding to this mapper’s class key (class).
relationships
Return a namespace of all RelationshipProperty properties maintained by this Mapper.
See also:
Mapper.attrs - namespace of all MapperProperty objects.
selectable
The select() construct this Mapper selects from by default.
Normally, this is equivalent to mapped_table, unless the with_polymorphic feature is in use, in
which case the full “polymorphic” selectable is returned.
self_and_descendants
The collection including this mapper and all descendant mappers.
This includes not just the immediately inheriting mappers but all their inheriting mappers as well.
single = None
Represent True if this Mapper is a single table inheritance mapper.
local_table will be None if this flag is set.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
synonyms
Return a namespace of all SynonymProperty properties maintained by this Mapper.
See also:
Mapper.attrs - namespace of all MapperProperty objects.
tables = None
An iterable containing the collection of Table objects which this Mapper is aware of.
If the mapper is mapped to a Join, or an Alias representing a Select, the individual Table objects
that comprise the full construct will be represented here.
This is a read only attribute determined during mapper construction. Behavior is undefined if directly
modified.
validators = None
An immutable dictionary of attributes which have been decorated using the validates() decorator.
The dictionary contains string attribute names as keys mapped to the actual validation method.
with_polymorphic_mappers
The list of Mapper objects included in the default “polymorphic” query.
This section describes the relationship() function and in depth discussion of its usage. For an introduction to
relationships, start with the Object Relational Tutorial and head into Building a Relationship.
Base = declarative_base()
One To Many
A one to many relationship places a foreign key on the child table referencing the parent. relationship() is then
specified on the parent, as referencing a collection of items represented by the child:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
To establish a bidirectional relationship in one-to-many, where the “reverse” side is a many to one, specify an additional
relationship() and connect the two using the relationship.back_populates parameter:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent", back_populates="children")
Many To One
Many to one places a foreign key in the parent table referencing the child. relationship() is declared on the
parent, where a new scalar-holding attribute will be created:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parents = relationship("Parent", back_populates="child")
Alternatively, the backref parameter may be applied to a single relationship(), such as Parent.child:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref="parents")
One To One
One To One is essentially a bidirectional relationship with a scalar attribute on both sides. To achieve this, the
uselist flag indicates the placement of a scalar attribute instead of a collection on the “many” side of the rela-
tionship. To convert one-to-many into one-to-one:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child = relationship("Child", uselist=False, back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent", back_populates="child")
Or for many-to-one:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent = relationship("Parent", back_populates="child", uselist=False)
As always, the relationship.backref and backref() functions may be used in lieu of the
relationship.back_populates approach; to specify uselist on a backref, use the backref() function:
from sqlalchemy.orm import backref
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref=backref("parent", uselist=False))
Many To Many
Many to Many adds an association table between two classes. The association table is indicated by the secondary
argument to relationship(). Usually, the Table uses the MetaData object associated with the declarative
base class, so that the ForeignKey directives can locate the remote tables with which to link:
association_table = Table('association', Base.metadata,
Column('left_id', Integer, ForeignKey('left.id')),
Column('right_id', Integer, ForeignKey('right.id'))
)
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Child",
secondary=association_table)
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
For a bidirectional relationship, both sides of the relationship contain a collection. Specify using
relationship.back_populates, and for each relationship() specify the common association table:
association_table = Table('association', Base.metadata,
Column('left_id', Integer, ForeignKey('left.id')),
Column('right_id', Integer, ForeignKey('right.id'))
)
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship(
"Child",
secondary=association_table,
back_populates="parents")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
parents = relationship(
"Parent",
secondary=association_table,
back_populates="children")
When using the backref parameter instead of relationship.back_populates, the backref will automati-
cally use the same secondary argument for the reverse relationship:
association_table = Table('association', Base.metadata,
Column('left_id', Integer, ForeignKey('left.id')),
Column('right_id', Integer, ForeignKey('right.id'))
)
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Child",
secondary=association_table,
backref="parents")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
The secondary argument of relationship() also accepts a callable that returns the ultimate argument, which
is evaluated only when mappers are first used. Using this, we can define the association_table at a later point,
as long as it’s available to the callable after all module initialization is complete:
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Child",
secondary=lambda: association_table,
backref="parents")
With the declarative extension in use, the traditional “string name of the table” is accepted as well, matching the name
of the table as stored in Base.metadata.tables:
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Child",
secondary="association",
backref="parents")
A behavior which is unique to the secondary argument to relationship() is that the Table which is specified
here is automatically subject to INSERT and DELETE statements, as objects are added or removed from the collection.
There is no need to delete from this table manually. The act of removing a record from the collection will have the
effect of the row being deleted on flush:
# row will be deleted from the "secondary" table
# automatically
myparent.children.remove(somechild)
A question which often arises is how the row in the “secondary” table can be deleted when the child object is handed
directly to Session.delete():
session.delete(somechild)
to forego actively loading in the Child.parents collection in this case using the passive_deletes
directive on relationship(); see Using Passive Deletes for more details on this.
Note again, these behaviors are only relevant to the secondary option used with relationship(). If deal-
ing with association tables that are mapped explicitly and are not present in the secondary option of a relevant
relationship(), cascade rules can be used instead to automatically delete entities in reaction to a related entity
being deleted - see Cascades for information on this feature.
Association Object
The association object pattern is a variant on many-to-many: it’s used when your association table contains additional
columns beyond those which are foreign keys to the left and right tables. Instead of using the secondary argument,
you map a new class directly to the association table. The left side of the relationship references the association object
via one-to-many, and the association class references the right side via many-to-one. Below we illustrate an association
table mapped to the Association class which includes a column called extra_data, which is a string value that
is stored along with each association between Parent and Child:
class Association(Base):
__tablename__ = 'association'
left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
extra_data = Column(String(50))
child = relationship("Child")
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Association")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Association", back_populates="parent")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
parents = relationship("Association", back_populates="child")
Working with the association pattern in its direct form requires that child objects are associated with an association
instance before being appended to the parent; similarly, access from parent to child goes through the association object:
To enhance the association object pattern such that direct access to the Association object is optional,
SQLAlchemy provides the Association Proxy extension. This extension allows the configuration of attributes which
will access two “hops” with a single access, one “hop” to the associated object, and a second to a target attribute.
Warning: The association object pattern does not coordinate changes with a separate relationship that maps
the association table as “secondary”.
Below, changes made to Parent.children will not be coordinated with changes made to
Parent.child_associations or Child.parent_associations in Python; while all of these
relationships will continue to function normally by themselves, changes on one will not show up in another until
the Session is expired, which normally occurs automatically after Session.commit():
class Association(Base):
__tablename__ = 'association'
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
Additionally, just as changes to one relationship aren’t reflected in the others automatically, writing the same data
to both relationships will cause conflicting INSERT or DELETE statements as well, such as below where we
establish the same relationship between a Parent and Child object twice:
p1 = Parent()
c1 = Child()
p1.children.append(c1)
It’s fine to use a mapping like the above if you know what you’re doing, though it may be a good idea to apply
the viewonly=True parameter to the “secondary” relationship to avoid the issue of redundant changes being
logged. However, to get a foolproof pattern that allows a simple two-object Parent->Child relationship while
still using the association object pattern, use the association proxy extension as documented at Association Proxy.
The adjacency list pattern is a common relational pattern whereby a table contains a foreign key reference to itself.
This is the most common way to represent hierarchical data in flat tables. Other methods include nested sets, some-
times called “modified preorder”, as well as materialized path. Despite the appeal that modified preorder has when
evaluated for its fluency within SQL queries, the adjacency list model is probably the most appropriate pattern for
the large majority of hierarchical storage needs, for reasons of concurrency, reduced complexity, and that modified
preorder has little advantage over an application which can fully load subtrees into the application space.
In this example, we’ll work with a single mapped class called Node, representing a tree structure:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('node.id'))
data = Column(String(50))
children = relationship("Node")
The relationship() configuration here works in the same way as a “normal” one-to-many relationship, with the
exception that the “direction”, i.e. whether the relationship is one-to-many or many-to-one, is assumed by default to
be one-to-many. To establish the relationship as many-to-one, an extra directive is added known as remote_side,
which is a Column or collection of Column objects that indicate those which should be considered to be “remote”:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('node.id'))
data = Column(String(50))
parent = relationship("Node", remote_side=[id])
Where above, the id column is applied as the remote_side of the parent relationship(), thus establishing
parent_id as the “local” side, and the relationship then behaves as a many-to-one.
As always, both directions can be combined into a bidirectional relationship using the backref() function:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('node.id'))
data = Column(String(50))
children = relationship("Node",
backref=backref('parent', remote_side=[id])
)
There are several examples included with SQLAlchemy illustrating self-referential strategies; these include Adjacency
List and XML Persistence.
A sub-category of the adjacency list relationship is the rare case where a particular column is present on both the
“local” and “remote” side of the join condition. An example is the Folder class below; using a composite primary
key, the account_id column refers to itself, to indicate sub folders which are within the same account as that of the
parent; while folder_id refers to a specific folder within that account:
class Folder(Base):
__tablename__ = 'folder'
__table_args__ = (
ForeignKeyConstraint(
['account_id', 'parent_id'],
['folder.account_id', 'folder.folder_id']),
)
parent_folder = relationship("Folder",
backref="child_folders",
remote_side=[account_id, folder_id]
)
Above, we pass account_id into the remote_side list. relationship() recognizes that the account_id
column here is on both sides, and aligns the “remote” column along with the folder_id column, which it recognizes
as uniquely present on the “remote” side.
New in version 0.8: Support for self-referential composite keys in relationship() where a column points to
itself.
However extra care is needed when attempting to join along the foreign key from one level of the tree to the next.
In SQL, a join from a table to itself requires that at least one side of the expression be “aliased” so that it can be
unambiguously referred to.
Recall from Using Aliases in the ORM tutorial that the orm.aliased() construct is normally used to provide an
“alias” of an ORM entity. Joining from Node to itself using this technique looks like:
from sqlalchemy.orm import aliased
nodealias = aliased(Node)
session.query(Node).filter(Node.data=='subchild1').\
join(nodealias, Node.parent).\
filter(nodealias.data=="child2").\
all()
SELECT node.id AS node_id,
node.parent_id AS node_parent_id,
node.data AS node_data
FROM node JOIN node AS node_1
ON node.parent_id = node_1.id
WHERE node.data = ?
AND node_1.data = ?
['subchild1', 'child2']
Query.join() also includes a feature known as Query.join.aliased that can shorten the verbosity self-
referential joins, at the expense of query flexibility. This feature performs a similar “aliasing” step to that above,
without the need for an explicit entity. Calls to Query.filter() and similar subsequent to the aliased join will
adapt the Node entity to be that of the alias:
session.query(Node).filter(Node.data=='subchild1').\
join(Node.parent, aliased=True).\
filter(Node.data=='child2').\
all()
SELECT node.id AS node_id,
node.parent_id AS node_parent_id,
node.data AS node_data
FROM node
JOIN node AS node_1 ON node_1.id = node.parent_id
WHERE node.data = ? AND node_1.data = ?
['subchild1', 'child2']
To add criterion to multiple points along a longer join, add Query.join.from_joinpoint to the additional
join() calls:
# get all nodes named 'subchild1' with a
# parent named 'child2' and a grandparent 'root'
session.query(Node).\
filter(Node.data=='subchild1').\
join(Node.parent, aliased=True).\
filter(Node.data=='child2').\
join(Node.parent, aliased=True, from_joinpoint=True).\
filter(Node.data=='root').\
all()
SELECT node.id AS node_id,
node.parent_id AS node_parent_id,
node.data AS node_data
FROM node
JOIN node AS node_1 ON node_1.id = node.parent_id
JOIN node AS node_2 ON node_2.id = node_1.parent_id
WHERE node.data = ?
AND node_1.data = ?
AND node_2.data = ?
['subchild1', 'child2', 'root']
For an example of using Query.join.aliased to arbitrarily join along a chain of self-referential nodes, see XML
Persistence.
Eager loading of relationships occurs using joins or outerjoins from parent to child table during a normal query oper-
ation, such that the parent and its immediate child collection or reference can be populated from a single SQL state-
ment, or a second statement for all immediate child collections. SQLAlchemy’s joined and subquery eager loading use
aliased tables in all cases when joining to related items, so are compatible with self-referential joining. However, to use
eager loading with a self-referential relationship, SQLAlchemy needs to be told how many levels deep it should join
and/or query; otherwise the eager load will not take place at all. This depth setting is configured via join_depth:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('node.id'))
data = Column(String(50))
children = relationship("Node",
lazy="joined",
join_depth=2)
session.query(Node).all()
SELECT node_1.id AS node_1_id,
node_1.parent_id AS node_1_parent_id,
node_1.data AS node_1_data,
node_2.id AS node_2_id,
node_2.parent_id AS node_2_parent_id,
node_2.data AS node_2_data,
node.id AS node_id,
node.parent_id AS node_parent_id,
node.data AS node_data
FROM node
LEFT OUTER JOIN node AS node_2
ON node.id = node_2.parent_id
LEFT OUTER JOIN node AS node_1
ON node_2.id = node_1.parent_id
[]
The backref keyword argument was first introduced in Object Relational Tutorial, and has been mentioned through-
out many of the examples here. What does it actually do ? Let’s start with the canonical User and Address scenario:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))
The above configuration establishes a collection of Address objects on User called User.addresses. It also
establishes a .user attribute on Address which will refer to the parent User object.
In fact, the backref keyword is only a common shortcut for placing a second relationship() onto the
Address mapping, including the establishment of an event listener on both sides which will mirror attribute op-
erations in both directions. The above configuration is equivalent to:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))
Above, we add a .user relationship to Address explicitly. On both relationships, the back_populates directive
tells each relationship about the other one, indicating that they should establish “bidirectional” behavior between each
other. The primary effect of this configuration is that the relationship adds event handlers to both attributes which
have the behavior of “when an append or set event occurs here, set ourselves onto the incoming attribute using this
particular attribute name”. The behavior is illustrated as follows. Start with a User and an Address instance. The
.addresses collection is empty, and the .user attribute is None:
>>> u1 = User()
>>> a1 = Address()
>>> u1.addresses
[]
>>> print a1.user
None
However, once the Address is appended to the u1.addresses collection, both the collection and the scalar
attribute have been populated:
>>> u1.addresses.append(a1)
>>> u1.addresses
[<__main__.Address object at 0x12a6ed0>]
>>> a1.user
<__main__.User object at 0x12a6590>
This behavior of course works in reverse for removal operations as well, as well as for equivalent operations on both
sides. Such as when .user is set again to None, the Address object is removed from the reverse collection:
>>> a1.user = None
>>> u1.addresses
[]
The manipulation of the .addresses collection and the .user attribute occurs entirely in Python without any
interaction with the SQL database. Without this behavior, the proper state would be apparent on both sides once
the data has been flushed to the database, and later reloaded after a commit or expiration operation occurs. The
backref/back_populates behavior has the advantage that common bidirectional operations can reflect the cor-
rect state without requiring a database round trip.
Remember, when the backref keyword is used on a single relationship, it’s exactly the same as if the above two
relationships were created individually using back_populates on each.
Backref Arguments
We’ve established that the backref keyword is merely a shortcut for building two individual relationship()
constructs that refer to each other. Part of the behavior of this shortcut is that certain configurational arguments
applied to the relationship() will also be applied to the other direction - namely those arguments that describe
the relationship at a schema level, and are unlikely to be different in the reverse direction. The usual case here is a
many-to-many relationship() that has a secondary argument, or a one-to-many or many-to-one which has a
primaryjoin argument (the primaryjoin argument is discussed in Specifying Alternate Join Conditions). Such
as if we limited the list of Address objects to those which start with “tony”:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address",
primaryjoin="and_(User.id==Address.user_id, "
"Address.email.startswith('tony'))",
backref="user")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))
We can observe, by inspecting the resulting property, that both sides of the relationship have this join condition applied:
>>> print User.addresses.property.primaryjoin
"user".id = address.user_id AND address.email LIKE :email_1 || '%%'
>>>
>>> print Address.user.property.primaryjoin
"user".id = address.user_id AND address.email LIKE :email_1 || '%%'
>>>
This reuse of arguments should pretty much do the “right thing” - it uses only arguments that are applicable, and in the
case of a many-to- many relationship, will reverse the usage of primaryjoin and secondaryjoin to correspond
to the other direction (see the example in Self-Referential Many-to-Many Relationship for this).
It’s very often the case however that we’d like to specify arguments that are specific to just the side where we happened
to place the “backref”. This includes relationship() arguments like lazy, remote_side, cascade and
cascade_backrefs. For this case we use the backref() function in place of a string:
# <other imports>
from sqlalchemy.orm import backref
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address",
backref=backref("user", lazy="joined"))
Where above, we placed a lazy="joined" directive only on the Address.user side, indicating that when a
query against Address is made, a join to the User entity should be made automatically which will populate the
.user attribute of each returned Address. The backref() function formatted the arguments we gave it into
a form that is interpreted by the receiving relationship() as additional arguments to be applied to the new
relationship it creates.
An unusual case is that of the “one way backref”. This is where the “back-populating” behavior of the backref is only
desirable in one direction. An example of this is a collection which contains a filtering primaryjoin condition.
We’d like to append items to this collection as needed, and have them populate the “parent” object on the incoming
object. However, we’d also like to have items that are not part of the collection, but still have the same “parent”
association - these items should never be in the collection.
Taking our previous example, where we established a primaryjoin that limited the collection only to Address
objects whose email address started with the word tony, the usual backref behavior is that all items populate in both
directions. We wouldn’t want this behavior for a case like the following:
>>> u1 = User()
>>> a1 = Address(email='mary')
>>> a1.user = u1
>>> u1.addresses
[<__main__.Address object at 0x1411910>]
Above, the Address object that doesn’t match the criterion of “starts with ‘tony”’ is present in the addresses
collection of u1. After these objects are flushed, the transaction committed and their attributes expired for a re-load,
the addresses collection will hit the database on next access and no longer have this Address object present, due
to the filtering condition. But we can do away with this unwanted side of the “backref” behavior on the Python side
by using two separate relationship() constructs, placing back_populates only on one side:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address",
primaryjoin="and_(User.id==Address.user_id, "
"Address.email.startswith('tony'))",
back_populates="user")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship("User")
With the above scenario, appending an Address object to the .addresses collection of a User will always
establish the .user attribute on that Address:
>>> u1 = User()
>>> a1 = Address(email='tony')
>>> u1.addresses.append(a1)
>>> a1.user
<__main__.User object at 0x1411850>
However, applying a User to the .user attribute of an Address, will not append the Address object to the
collection:
>>> a2 = Address(email='mary')
>>> a2.user = u1
>>> a2 in u1.addresses
False
Of course, we’ve disabled some of the usefulness of backref here, in that when we do append an Address that
corresponds to the criteria of email.startswith(’tony’), it won’t show up in the User.addresses col-
lection until the session is flushed, and the attributes reloaded after a commit or expire operation. While we could
consider an attribute event that checks this criterion in Python, this starts to cross the line of duplicating too much SQL
behavior in Python. The backref behavior itself is only a slight transgression of this philosophy - SQLAlchemy tries
to keep these to a minimum overall.
relationship() will normally create a join between two tables by examining the foreign key relationship between
the two tables to determine which columns should be compared. There are a variety of situations where this behavior
needs to be customized.
One of the most common situations to deal with is when there are more than one foreign key path between two tables.
Consider a Customer class that contains two foreign keys to an Address class:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String)
billing_address = relationship("Address")
shipping_address = relationship("Address")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
street = Column(String)
city = Column(String)
state = Column(String)
zip = Column(String)
The above mapping, when we attempt to use it, will produce the error:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
condition between parent/child tables on relationship
Customer.billing_address - there are multiple foreign key
paths linking the tables. Specify the 'foreign_keys' argument,
providing a list of those columns which should be
counted as containing a foreign key reference to the parent table.
The above message is pretty long. There are many potential messages that relationship() can return, which
have been carefully tailored to detect a variety of common configurational issues; most will suggest the additional
configuration that’s needed to resolve the ambiguity or other missing information.
In this case, the message wants us to qualify each relationship() by instructing for each one which foreign key
column should be considered, and the appropriate form is as follows:
class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String)
Above, we specify the foreign_keys argument, which is a Column or list of Column objects which indi-
cate those columns to be considered “foreign”, or in other words, the columns that contain a value referring to
a parent table. Loading the Customer.billing_address relationship from a Customer object will use
the value present in billing_address_id in order to identify the row in Address to be loaded; similarly,
shipping_address_id is used for the shipping_address relationship. The linkage of the two columns also
plays a role during persistence; the newly generated primary key of a just-inserted Address object will be copied
into the appropriate foreign key column of an associated Customer object during a flush.
When specifying foreign_keys with Declarative, we can also use string names to specify, however it is important
that if using a list, the list is part of the string:
billing_address = relationship("Address", foreign_keys="[Customer.billing_address_id]")
In this specific example, the list is not necessary in any case as there’s only one Column we need:
billing_address = relationship("Address", foreign_keys="Customer.billing_address_id")
Changed in version 0.8: relationship() can resolve ambiguity between foreign key targets on the basis of the
foreign_keys argument alone; the primaryjoin argument is no longer needed in this situation.
The default behavior of relationship() when constructing a join is that it equates the value of primary key
columns on one side to that of foreign-key-referring columns on the other. We can change this criterion to be any-
thing we’d like using the primaryjoin argument, as well as the secondaryjoin argument in the case when a
“secondary” table is used.
In the example below, using the User class as well as an Address class which stores a street address, we create a
relationship boston_addresses which will only load those Address objects which specify a city of “Boston”:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
boston_addresses = relationship("Address",
primaryjoin="and_(User.id==Address.user_id, "
"Address.city=='Boston')")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user.id'))
street = Column(String)
city = Column(String)
state = Column(String)
zip = Column(String)
Within this string SQL expression, we made use of the and_() conjunction construct to establish two distinct pred-
icates for the join condition - joining both the User.id and Address.user_id columns to each other, as well
as limiting rows in Address to just city=’Boston’. When using Declarative, rudimentary SQL functions like
and_() are automatically available in the evaluated namespace of a string relationship() argument.
The custom criteria we use in a primaryjoin is generally only significant when SQLAlchemy is rendering SQL in
order to load or represent this relationship. That is, it’s used in the SQL statement that’s emitted in order to perform
a per-attribute lazy load, or when a join is constructed at query time, such as via Query.join(), or via the eager
“joined” or “subquery” styles of loading. When in-memory objects are being manipulated, we can place any Address
object we’d like into the boston_addresses collection, regardless of what the value of the .city attribute is.
The objects will remain present in the collection until the attribute is expired and re-loaded from the database where the
criterion is applied. When a flush occurs, the objects inside of boston_addresses will be flushed unconditionally,
assigning value of the primary key user.id column onto the foreign-key-holding address.user_id column for
each row. The city criteria has no effect here, as the flush process only cares about synchronizing primary key values
into referencing foreign key values.
Another element of the primary join condition is how those columns considered “foreign” are determined. Usually,
some subset of Column objects will specify ForeignKey, or otherwise be part of a ForeignKeyConstraint
that’s relevant to the join condition. relationship() looks to this foreign key status as it decides how it
should load and persist data for this relationship. However, the primaryjoin argument can be used to create a
join condition that doesn’t involve any “schema” level foreign keys. We can combine primaryjoin along with
foreign_keys and remote_side explicitly in order to establish such a join.
Below, a class HostEntry joins to itself, equating the string content column to the ip_address column, which
is a Postgresql type called INET. We need to use cast() in order to cast one side of the join to the type of the other:
from sqlalchemy import cast, String, Column, Integer
from sqlalchemy.orm import relationship
Base = declarative_base()
class HostEntry(Base):
__tablename__ = 'host_entry'
id = Column(Integer, primary_key=True)
ip_address = Column(INET)
content = Column(String(50))
An alternative syntax to the above is to use the foreign() and remote() annotations, inline within the
primaryjoin expression. This syntax represents the annotations that relationship() normally applies by
itself to the join condition given the foreign_keys and remote_side arguments. These functions may be more
succinct when an explicit join condition is present, and additionally serve to mark exactly the column that is “foreign”
or “remote” independent of whether that column is stated multiple times or within complex SQL expressions:
from sqlalchemy.orm import foreign, remote
class HostEntry(Base):
__tablename__ = 'host_entry'
id = Column(Integer, primary_key=True)
ip_address = Column(INET)
content = Column(String(50))
Another use case for relationships is the use of custom operators, such as Postgresql’s “is contained within” <<
operator when joining with types such as postgresql.INET and postgresql.CIDR. For custom operators we
use the Operators.op() function:
inet_column.op("<<")(cidr_column)
However, if we construct a primaryjoin using this operator, relationship() will still need more information.
This is because when it examines our primaryjoin condition, it specifically looks for operators used for comparisons,
and this is typically a fixed list containing known comparison operators such as ==, <, etc. So for our custom operator
to participate in this system, we need it to register as a comparison operator using the is_comparison parameter:
inet_column.op("<<", is_comparison=True)(cidr_column)
A complete example:
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin="IPA.v4address.op('<<', is_comparison=True)"
"(foreign(Network.v4representation))",
viewonly=True
)
class Network(Base):
__tablename__ = 'network'
id = Column(Integer, primary_key=True)
v4representation = Column(CIDR)
New in version 0.9.2: - Added the Operators.op.is_comparison flag to assist in the creation of
relationship() constructs using custom operators.
A rare scenario can arise when composite foreign keys are used, such that a single column may be the subject of more
than one column referred to via foreign key constraint.
Consider an (admittedly complex) mapping such as the Magazine object, referred to both by the Writer object
and the Article object using a composite primary key scheme that includes magazine_id for both; then to
make Article refer to Writer as well, Article.magazine_id is involved in two separate relationships;
Article.magazine and Article.writer:
class Magazine(Base):
__tablename__ = 'magazine'
id = Column(Integer, primary_key=True)
class Article(Base):
__tablename__ = 'article'
article_id = Column(Integer)
magazine_id = Column(ForeignKey('magazine.id'))
writer_id = Column()
magazine = relationship("Magazine")
writer = relationship("Writer")
__table_args__ = (
PrimaryKeyConstraint('article_id', 'magazine_id'),
ForeignKeyConstraint(
['writer_id', 'magazine_id'],
['writer.id', 'writer.magazine_id']
),
)
class Writer(Base):
__tablename__ = 'writer'
id = Column(Integer, primary_key=True)
magazine_id = Column(ForeignKey('magazine.id'), primary_key=True)
magazine = relationship("Magazine")
When the above mapping is configured, we will see this warning emitted:
SAWarning: relationship 'Article.writer' will copy column
writer.magazine_id to column article.magazine_id,
which conflicts with relationship(s): 'Article.magazine'
(copies magazine.id to article.magazine_id). Consider applying
viewonly=True to read-only relationships, or provide a primaryjoin
condition marking writable columns with the foreign() annotation.
What this refers to originates from the fact that Article.magazine_id is the subject of two different foreign
key constraints; it refers to Magazine.id directly as a source column, but also refers to Writer.magazine_id
as a source column in the context of the composite key to Writer. If we associate an Article with a particular
Magazine, but then associate the Article with a Writer that’s associated with a different Magazine, the ORM
will overwrite Article.magazine_id non-deterministically, silently changing which magazine we refer towards;
it may also attempt to place NULL into this columnn if we de-associate a Writer from an Article. The warning
lets us know this is the case.
To solve this, we need to break out the behavior of Article to include all three of the following features:
1. Article first and foremost writes to Article.magazine_id based on data persisted in the
Article.magazine relationship only, that is a value copied from Magazine.id.
2. Article can write to Article.writer_id on behalf of data persisted in the Article.writer rela-
tionship, but only the Writer.id column; the Writer.magazine_id column should not be written into
Article.magazine_id as it ultimately is sourced from Magazine.id.
3. Article takes Article.magazine_id into account when loading Article.writer, even though it
doesn’t write to it on behalf of this relationship.
To get just #1 and #2, we could specify only Article.writer_id as the “foreign keys” for Article.writer:
class Article(Base):
# ...
However, this has the effect of Article.writer not taking Article.magazine_id into account when query-
ing against Writer:
Therefore, to get at all of #1, #2, and #3, we express the join condition as well as which columns to be written by
combining primaryjoin fully, along with either the foreign_keys argument, or more succinctly by annotating
with foreign():
class Article(Base):
# ...
writer = relationship(
"Writer",
primaryjoin="and_(Writer.id == foreign(Article.writer_id), "
"Writer.magazine_id == Article.magazine_id)")
Changed in version 1.0.0: the ORM will attempt to warn when a column is used as the synchronization target from
more than one relationship simultaneously.
Using custom expressions means we can produce unorthodox join conditions that don’t obey the usual primary/foreign
key model. One such example is the materialized path pattern, where we compare strings for overlapping path tokens
in order to produce a tree structure.
Through careful use of foreign() and remote(), we can build a relationship that effectively produces a rudimen-
tary materialized path system. Essentially, when foreign() and remote() are on the same side of the comparison
expression, the relationship is considered to be “one to many”; when they are on different sides, the relationship is
considered to be “many to one”. For the comparison we’ll use here, we’ll be dealing with collections so we keep
things configured as “one to many”:
class Element(Base):
__tablename__ = 'element'
descendants = relationship('Element',
primaryjoin=
remote(foreign(path)).like(
path.concat('/%')),
viewonly=True,
order_by=path)
Above, if given an Element object with a path attribute of "/foo/bar2", we seek for a load of
Element.descendants to look like:
SELECT element.path AS element_path
FROM element
WHERE element.path LIKE ('/foo/bar2' || '/%') ORDER BY element.path
New in version 0.9.5: Support has been added to allow a single-column comparison to itself within a primaryjoin
condition, as well as for primaryjoin conditions that use ColumnOperators.like() as the comparison operator.
Many to many relationships can be customized by one or both of primaryjoin and secondaryjoin - the latter
is significant for a relationship that specifies a many-to-many reference using the secondary argument. A common
situation which involves the usage of primaryjoin and secondaryjoin is when establishing a many-to-many
relationship from a class to itself, as shown below:
from sqlalchemy import Integer, ForeignKey, String, Column, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
label = Column(String)
right_nodes = relationship("Node",
secondary=node_to_node,
primaryjoin=id==node_to_node.c.left_node_id,
secondaryjoin=id==node_to_node.c.right_node_id,
backref="left_nodes"
)
Where above, SQLAlchemy can’t know automatically which columns should connect to which for the right_nodes
and left_nodes relationships. The primaryjoin and secondaryjoin arguments establish how we’d like to
join to the association table. In the Declarative form above, as we are declaring these conditions within the Python
block that corresponds to the Node class, the id variable is available directly as the Column object we wish to join
with.
Alternatively, we can define the primaryjoin and secondaryjoin arguments using strings, which is suitable in
the case that our configuration does not have either the Node.id column object available yet or the node_to_node
table perhaps isn’t yet available. When referring to a plain Table object in a declarative string, we use the string name
of the table as it is present in the MetaData:
class Node(Base):
__tablename__ = 'node'
id = Column(Integer, primary_key=True)
label = Column(String)
right_nodes = relationship("Node",
secondary="node_to_node",
primaryjoin="Node.id==node_to_node.c.left_node_id",
secondaryjoin="Node.id==node_to_node.c.right_node_id",
backref="left_nodes"
)
A classical mapping situation here is similar, where node_to_node can be joined to node.c.id:
from sqlalchemy import Integer, ForeignKey, String, Column, Table, MetaData
from sqlalchemy.orm import relationship, mapper
metadata = MetaData()
Note that in both examples, the backref keyword specifies a left_nodes backref - when relationship()
creates the second relationship in the reverse direction, it’s smart enough to reverse the primaryjoin and
secondaryjoin arguments.
Note: This section features some new and experimental features of SQLAlchemy.
Sometimes, when one seeks to build a relationship() between two tables there is a need for more than just two
or three tables to be involved in order to join them. This is an area of relationship() where one seeks to push the
boundaries of what’s possible, and often the ultimate solution to many of these exotic use cases needs to be hammered
out on the SQLAlchemy mailing list.
In more recent versions of SQLAlchemy, the secondary parameter can be used in some of these cases in order
to provide a composite target consisting of multiple tables. Below is an example of such a join condition (requires
version 0.9.2 at least to function as is):
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey('b.id'))
d = relationship("D",
secondary="join(B, D, B.d_id == D.id)."
"join(C, C.d_id == D.id)",
primaryjoin="and_(A.b_id == B.id, A.id == C.a_id)",
secondaryjoin="D.id == B.d_id",
uselist=False
)
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
d_id = Column(ForeignKey('d.id'))
class C(Base):
__tablename__ = 'c'
id = Column(Integer, primary_key=True)
a_id = Column(ForeignKey('a.id'))
d_id = Column(ForeignKey('d.id'))
class D(Base):
__tablename__ = 'd'
id = Column(Integer, primary_key=True)
In the above example, we provide all three of secondary, primaryjoin, and secondaryjoin, in the declara-
tive style referring to the named tables a, b, c, d directly. A query from A to D looks like:
sess.query(A).join(A.d).all()
In the above example, we take advantage of being able to stuff multiple tables into a “secondary” container, so that
we can join across many tables while still keeping things “simple” for relationship(), in that there’s just “one”
table on both the “left” and the “right” side; the complexity is kept within the middle.
New in version 0.9.2: Support is improved for allowing a join() construct to be used directly as the target of the
secondary argument, including support for joins, eager joins and lazy loading, as well as support within declarative
to specify complex conditions such as joins involving class names as targets.
In the previous section, we illustrated a technique where we used secondary in order to place additional tables
within a join condition. There is one complex join case where even this technique is not sufficient; when we seek to
join from A to B, making use of any number of C, D, etc. in between, however there are also join conditions between
A and B directly. In this case, the join from A to B may be difficult to express with just a complex primaryjoin
condition, as the intermediary tables may need special handling, and it is also not expressable with a secondary
object, since the A->secondary->B pattern does not support any references between A and B directly. When this
extremely advanced case arises, we can resort to creating a second mapping as a target for the relationship. This is
where we use mapper() in order to make a mapping to a class that includes all the additional tables we need for this
join. In order to produce this mapper as an “alternative” mapping for our class, we use the non_primary flag.
Below illustrates a relationship() with a simple join from A to B, however the primaryjoin condition is aug-
mented with two additional entities C and D, which also must have rows that line up with the rows in both A and B
simultaneously:
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey('b.id'))
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
class C(Base):
__tablename__ = 'c'
id = Column(Integer, primary_key=True)
a_id = Column(ForeignKey('a.id'))
class D(Base):
__tablename__ = 'd'
id = Column(Integer, primary_key=True)
c_id = Column(ForeignKey('c.id'))
b_id = Column(ForeignKey('b.id'))
In the above case, our non-primary mapper for B will emit for additional columns when we query; these can be ignored:
sess.query(A).join(A.b).all()
Very ambitious custom join conditions may fail to be directly persistable, and in some cases may not even load
correctly. To remove the persistence part of the equation, use the flag viewonly on the relationship(), which
establishes it as a read-only attribute (data written to the collection will be ignored on flush()). However, in extreme
cases, consider using a regular Python property in conjunction with Query as follows:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
def _get_addresses(self):
return object_session(self).query(Address).with_parent(self).filter(...).all()
addresses = property(_get_addresses)
The relationship() function defines a linkage between two classes. When the linkage defines a one-to-many
or many-to-many relationship, it’s represented as a Python collection when objects are loaded and manipulated. This
section presents additional information about collection configuration and techniques.
The default behavior of relationship() is to fully load the collection of items in, as according to the loading
strategy of the relationship. Additionally, the Session by default only knows how to delete objects which are
actually present within the session. When a parent instance is marked for deletion and flushed, the Session loads its
full list of child items in so that they may either be deleted as well, or have their foreign key value set to null; this is
to avoid constraint violations. For large collections of child items, there are several strategies to bypass full loading of
child items both at load time as well as deletion time.
A key feature to enable management of a large collection is the so-called “dynamic” relationship. This is an optional
form of relationship() which returns a Query object in place of a collection when accessed. filter()
criterion may be applied as well as limits and offsets, either explicitly or via array slices:
class User(Base):
__tablename__ = 'user'
jack = session.query(User).get(id)
The dynamic relationship supports limited write operations, via the append() and remove() methods:
oldpost = jack.posts.filter(Post.headline=='old post').one()
jack.posts.remove(oldpost)
jack.posts.append(Post('new post'))
Since the read side of the dynamic relationship always queries the database, changes to the underlying collection will
not be visible until the data has been flushed. However, as long as “autoflush” is enabled on the Session in use, this
will occur automatically each time the collection is about to emit a query.
To place a dynamic relationship on a backref, use the backref() function in conjunction with lazy=’dynamic’:
class Post(Base):
__table__ = posts_table
user = relationship(User,
backref=backref('posts', lazy='dynamic')
)
Note that eager/lazy loading options cannot be used in conjunction dynamic relationships at this time.
Note: The dynamic_loader() function is essentially the same as relationship() with the
lazy=’dynamic’ argument specified.
Warning: The “dynamic” loader applies to collections only. It is not valid to use “dynamic” loaders with many-
to-one, one-to-one, or uselist=False relationships. Newer versions of SQLAlchemy emit warnings or exceptions in
these cases.
Setting Noload
A “noload” relationship never loads from the database, even when accessed. It is configured using lazy=’noload’:
class MyClass(Base):
__tablename__ = 'some_table'
Above, the children collection is fully writeable, and changes to it will be persisted to the database as well as
locally available for reading at the time they are added. However when instances of MyClass are freshly loaded from
the database, the children collection stays empty.
Use passive_deletes to disable child object loading on a DELETE operation, in conjunction with “ON DELETE
(CASCADE|SET NULL)” on your database to automatically cascade deletes to child objects:
class MyClass(Base):
__tablename__ = 'mytable'
id = Column(Integer, primary_key=True)
children = relationship("MyOtherClass",
cascade="all, delete-orphan",
passive_deletes=True)
class MyOtherClass(Base):
__tablename__ = 'myothertable'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer,
ForeignKey('mytable.id', ondelete='CASCADE')
)
Note: To use “ON DELETE CASCADE”, the underlying database engine must support foreign keys.
• When using MySQL, an appropriate storage engine must be selected. See CREATE TABLE arguments including
Storage Engines for details.
• When using SQLite, foreign key support must be enabled explicitly. See Foreign Key Support for details.
When passive_deletes is applied, the children relationship will not be loaded into memory when an instance
of MyClass is marked for deletion. The cascade="all, delete-orphan" will take effect for instances of
MyOtherClass which are currently present in the session; however for instances of MyOtherClass which are
not loaded, SQLAlchemy assumes that “ON DELETE CASCADE” rules will ensure that those rows are deleted by
the database.
Mapping a one-to-many or many-to-many relationship results in a collection of values accessible through an attribute
on the parent instance. By default, this collection is a list:
class Parent(Base):
__tablename__ = 'parent'
parent_id = Column(Integer, primary_key=True)
children = relationship(Child)
parent = Parent()
parent.children.append(Child())
print parent.children[0]
Collections are not limited to lists. Sets, mutable sequences and almost any other Python object that can act as a con-
tainer can be used in place of the default list, by specifying the collection_class option on relationship():
class Parent(Base):
__tablename__ = 'parent'
parent_id = Column(Integer, primary_key=True)
# use a set
children = relationship(Child, collection_class=set)
parent = Parent()
child = Child()
parent.children.add(child)
assert child in parent.children
Dictionary Collections
A little extra detail is needed when using a dictionary as a collection. This because objects are always loaded
from the database as lists, and a key-generation strategy must be available to populate the dictionary correctly. The
attribute_mapped_collection() function is by far the most common way to achieve a simple dictionary
collection. It produces a dictionary class that will apply a particular attribute of the mapped class as a key. Below we
map an Item class containing a dictionary of Note items keyed to the Note.keyword attribute:
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
notes = relationship("Note",
collection_class=attribute_mapped_collection('keyword'),
cascade="all, delete-orphan")
class Note(Base):
__tablename__ = 'note'
id = Column(Integer, primary_key=True)
item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
keyword = Column(String)
text = Column(String)
attribute_mapped_collection() will ensure that the .keyword attribute of each Note complies with the
key in the dictionary. Such as, when assigning to Item.notes, the dictionary key we supply must match that of the
actual Note object:
item = Item()
item.notes = {
'a': Note('a', 'atext'),
'b': Note('b', 'btext')
}
The attribute which attribute_mapped_collection() uses as a key does not need to be mapped at all! Using
a regular Python @property allows virtually any detail or combination of details about the object to be used as the
key, as below when we establish it as a tuple of Note.keyword and the first ten letters of the Note.text field:
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
notes = relationship("Note",
collection_class=attribute_mapped_collection('note_key'),
backref="item",
cascade="all, delete-orphan")
class Note(Base):
__tablename__ = 'note'
id = Column(Integer, primary_key=True)
item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
keyword = Column(String)
text = Column(String)
@property
def note_key(self):
return (self.keyword, self.text[0:10])
Above we added a Note.item backref. Assigning to this reverse relationship, the Note is added to the
Item.notes dictionary and the key is generated for us automatically:
>>> item = Item()
>>> n1 = Note("a", "atext")
>>> n1.item = item
>>> item.notes
{('a', 'atext'): <__main__.Note object at 0x2eaaf0>}
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
notes = relationship("Note",
collection_class=column_mapped_collection(Note.__table__.c.keyword),
cascade="all, delete-orphan")
as well as mapped_collection() which is passed any callable function. Note that it’s usually easier to use
attribute_mapped_collection() along with a @property as mentioned earlier:
from sqlalchemy.orm.collections import mapped_collection
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
notes = relationship("Note",
collection_class=mapped_collection(lambda note: note.text[0:10]),
cascade="all, delete-orphan")
Dictionary mappings are often combined with the “Association Proxy” extension to produce streamlined dictionary
views. See Proxying to Dictionary Based Collections and Composite Association Proxies for examples.
sqlalchemy.orm.collections.attribute_mapped_collection(attr_name)
A dictionary-based collection type with attribute-based keying.
Returns a MappedCollection factory with a keying based on the ‘attr_name’ attribute of entities in the
collection, where attr_name is the string name of the attribute.
The key value must be immutable for the lifetime of the object. You can not, for example, map on foreign key
values if those key values will change during the session, i.e. from None to a database-assigned integer after a
session flush.
sqlalchemy.orm.collections.column_mapped_collection(mapping_spec)
A dictionary-based collection type with column-based keying.
Returns a MappedCollection factory with a keying function generated from mapping_spec, which may be
a Column or a sequence of Columns.
The key value must be immutable for the lifetime of the object. You can not, for example, map on foreign key
values if those key values will change during the session, i.e. from None to a database-assigned integer after a
session flush.
sqlalchemy.orm.collections.mapped_collection(keyfunc)
A dictionary-based collection type with arbitrary keying.
Returns a MappedCollection factory with a keying function generated from keyfunc, a callable that takes
an entity and returns a key value.
The key value must be immutable for the lifetime of the object. You can not, for example, map on foreign key
values if those key values will change during the session, i.e. from None to a database-assigned integer after a
session flush.
You can use your own types for collections as well. In simple cases, inherting from list or set, adding custom
behavior, is all that’s needed. In other cases, special decorators are needed to tell SQLAlchemy more detail about how
the collection operates.
Collections in SQLAlchemy are transparently instrumented. Instrumentation means that normal operations on the col-
lection are tracked and result in changes being written to the database at flush time. Additionally, collection operations
can fire events which indicate some secondary operation must take place. Examples of a secondary operation include
saving the child item in the parent’s Session (i.e. the save-update cascade), as well as synchronizing the state
of a bi-directional relationship (i.e. a backref()).
The collections package understands the basic interface of lists, sets and dicts and will automatically apply instrumen-
tation to those built-in types and their subclasses. Object-derived types that implement a basic collection interface are
detected and instrumented via duck-typing:
class ListLike(object):
def __init__(self):
self.data = []
def append(self, item):
self.data.append(item)
def remove(self, item):
self.data.remove(item)
def extend(self, items):
self.data.extend(items)
def __iter__(self):
return iter(self.data)
def foo(self):
return 'foo'
append, remove, and extend are known list-like methods, and will be instrumented automatically. __iter__ is
not a mutator method and won’t be instrumented, and foo won’t be either.
Duck-typing (i.e. guesswork) isn’t rock-solid, of course, so you can be explicit about the interface you are implement-
ing by providing an __emulates__ class attribute:
class SetLike(object):
__emulates__ = set
def __init__(self):
self.data = set()
def append(self, item):
self.data.add(item)
def remove(self, item):
self.data.remove(item)
def __iter__(self):
return iter(self.data)
This class looks list-like because of append, but __emulates__ forces it to set-like. remove is known to be part
of the set interface and will be instrumented.
But this class won’t work quite yet: a little glue is needed to adapt it for use by SQLAlchemy. The ORM needs to
know which methods to use to append, remove and iterate over members of the collection. When using a type like
list or set, the appropriate methods are well-known and used automatically when present. This set-like class does
not provide the expected add method, so we must supply an explicit mapping for the ORM via a decorator.
Decorators can be used to tag the individual methods the ORM needs to manage collections. Use them when your
class doesn’t quite meet the regular interface for its container type, or when you otherwise would like to use a different
method to get the job done.
from sqlalchemy.orm.collections import collection
class SetLike(object):
__emulates__ = set
def __init__(self):
self.data = set()
@collection.appender
def append(self, item):
self.data.add(item)
def __iter__(self):
return iter(self.data)
And that’s all that’s needed to complete the example. SQLAlchemy will add instances via the append method.
remove and __iter__ are the default methods for sets and will be used for removing and iteration. Default
methods can be changed as well:
from sqlalchemy.orm.collections import collection
class MyList(list):
@collection.remover
def zark(self, item):
# do something special...
@collection.iterator
def hey_use_this_instead_for_iteration(self):
# ...
There is no requirement to be list-, or set-like at all. Collection classes can be any shape, so long as they have the
append, remove and iterate interface marked for SQLAlchemy’s use. Append and remove methods will be called with
a mapped entity as the single argument, and iterator methods are called with no arguments and must return an iterator.
class sqlalchemy.orm.collections.collection
Decorators for entity collection classes.
The decorators fall into two groups: annotations and interception recipes.
The annotating decorators (appender, remover, iterator, linker, converter, internally_instrumented) indicate the
method’s purpose and take no arguments. They are not written with parens:
@collection.appender
def append(self, append): ...
The recipe decorators all require parens, even those that take no arguments:
@collection.adds('entity')
def insert(self, position, entity): ...
@collection.removes_return()
def popitem(self): ...
static adds(arg)
Mark the method as adding an entity to the collection.
Adds “add to collection” handling to the method. The decorator argument indicates which method argu-
ment holds the SQLAlchemy-relevant value. Arguments can be specified positionally (i.e. integer) or by
name:
@collection.adds(1)
def push(self, item): ...
@collection.adds('entity')
def do_stuff(self, thing, entity=None): ...
static appender(fn)
Tag the method as the collection appender.
The appender method is called with one positional argument: the value to append. The method will be
automatically decorated with ‘adds(1)’ if not already decorated:
@collection.appender
def add(self, append): ...
# or, equivalently
@collection.appender
@collection.adds(1)
def add(self, append): ...
If the value to append is not allowed in the collection, you may raise an exception. Something to remember
is that the appender will be called for each object mapped by a database query. If the database contains
rows that violate your collection semantics, you will need to get creative to fix the problem, as access via
the collection will not work.
If the appender method is internally instrumented, you must also receive the keyword argument
‘_sa_initiator’ and ensure its promulgation to collection events.
static converter(fn)
Tag the method as the collection converter.
This optional method will be called when a collection is being replaced entirely, as in:
myobj.acollection = [newvalue1, newvalue2]
The converter method will receive the object being assigned and should return an iterable of values suitable
for use by the appender method. A converter must not assign values or mutate the collection, its sole
job is to adapt the value the user provides into an iterable of values for the ORM’s use.
The default converter implementation will use duck-typing to do the conversion. A dict-like collection will
be convert into an iterable of dictionary values, and other types will simply be iterated:
@collection.converter
def convert(self, other): ...
If the duck-typing of the object does not match the type of this collection, a TypeError is raised.
Supply an implementation of this method if you want to expand the range of possible types that can be
assigned in bulk or perform validation on the values about to be assigned.
static internally_instrumented(fn)
Tag the method as instrumented.
This tag will prevent any decoration from being applied to the method. Use this if you are orchestrating
your own calls to collection_adapter() in one of the basic SQLAlchemy interface methods, or to
prevent an automatic ABC method decoration from wrapping your implementation:
# normally an 'extend' method on a list-like class would be
# automatically intercepted and re-implemented in terms of
# SQLAlchemy events and append(). your implementation will
# never be called, unless:
@collection.internally_instrumented
def extend(self, items): ...
static iterator(fn)
Tag the method as the collection remover.
The iterator method is called with no arguments. It is expected to return an iterator over all collection
members:
@collection.iterator
def __iter__(self): ...
static link(fn)
deprecated; synonym for collection.linker().
static linker(fn)
Tag the method as a “linked to attribute” event handler.
This optional event handler will be called when the collection class is linked to or unlinked from the
InstrumentedAttribute. It is invoked immediately after the ‘_sa_adapter’ property is set on the instance. A
single argument is passed: the collection adapter that has been linked, or None if unlinking.
Deprecated since version 1.0.0: - the collection.linker() han-
dler is superseded by the AttributeEvents.init_collection() and
AttributeEvents.dispose_collection() handlers.
static remover(fn)
Tag the method as the collection remover.
The remover method is called with one positional argument: the value to remove. The method will be
automatically decorated with removes_return() if not already decorated:
@collection.remover
def zap(self, entity): ...
# or, equivalently
@collection.remover
@collection.removes_return()
def zap(self, ): ...
If the value to remove is not present in the collection, you may raise an exception or return None to ignore
the error.
If the remove method is internally instrumented, you must also receive the keyword argument
‘_sa_initiator’ and ensure its promulgation to collection events.
static removes(arg)
Mark the method as removing an entity in the collection.
Adds “remove from collection” handling to the method. The decorator argument indicates which method
argument holds the SQLAlchemy-relevant value to be removed. Arguments can be specified positionally
(i.e. integer) or by name:
@collection.removes(1)
def zap(self, item): ...
For methods where the value to remove is not known at call-time, use collection.removes_return.
static removes_return()
Mark the method as removing an entity in the collection.
Adds “remove from collection” handling to the method. The return value of the method, if any, is consid-
ered the value to remove. The method arguments are not inspected:
@collection.removes_return()
def pop(self): ...
For methods where the value to remove is known at call-time, use collection.remove.
static replaces(arg)
Mark the method as replacing an entity in the collection.
Adds “add to collection” and “remove from collection” handling to the method. The decorator argument
indicates which method argument holds the SQLAlchemy-relevant value to be added, and return value, if
any will be considered the value to remove.
Arguments can be specified positionally (i.e. integer) or by name:
@collection.replaces(2)
def __setitem__(self, index, item): ...
The MappedCollection class can be used as a base class for your custom types or as a mix-in to quickly add dict
collection support to other classes. It uses a keying function to delegate to __setitem__ and __delitem__:
class MyMappedCollection(MappedCollection):
"""Use @internally_instrumented when your methods
call down to already-instrumented methods.
"""
@collection.internally_instrumented
def __setitem__(self, key, value, _sa_initiator=None):
# do something with key, value
super(MyMappedCollection, self).__setitem__(key, value, _sa_initiator)
@collection.internally_instrumented
def __delitem__(self, key, _sa_initiator=None):
# do something with key
super(MyMappedCollection, self).__delitem__(key, _sa_initiator)
The ORM understands the dict interface just like lists and sets, and will automatically instrument all dict-like meth-
ods if you choose to subclass dict or provide dict-like collection behavior in a duck-typed class. You must deco-
rate appender and remover methods, however- there are no compatible methods in the basic dictionary interface for
SQLAlchemy to use by default. Iteration will go through itervalues() unless otherwise decorated.
Note: Due to a bug in MappedCollection prior to version 0.7.6, this workaround usually needs to be called before a
custom subclass of MappedCollection which uses collection.internally_instrumented() can be
used:
from sqlalchemy.orm.collections import _instrument_class, MappedCollection
_instrument_class(MappedCollection)
This will ensure that the MappedCollection has been properly initialized with custom __setitem__() and
__delitem__() methods before used in a custom subclass.
class sqlalchemy.orm.collections.MappedCollection(keyfunc)
Bases: __builtin__.dict
A basic dictionary-based collection class.
Extends dict with the minimal bag semantics that collection classes require. set and remove are implemented
in terms of a keying function: any callable that takes an object and returns an object for use as a dictionary key.
__init__(keyfunc)
Create a new collection with keying provided by keyfunc.
keyfunc may be any callable that takes an object and returns an object for use as a dictionary key.
The keyfunc will be called every time the ORM needs to add a member by value-only (such as when
loading instances from the database) or remove a member. The usual cautions about dictionary keying
apply- keyfunc(object) should return the same output for the life of the collection. Keying based on
mutable properties can result in unreachable instances “lost” in the collection.
clear() → None. Remove all items from D.
pop(k[, d ]) → v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised
popitem() → (k, v), remove and return some (key, value) pair as a
2-tuple; but raise KeyError if D is empty.
remove(value, _sa_initiator=None)
Remove an item by value, consulting the keyfunc for the key.
set(value, _sa_initiator=None)
Add an item by value, consulting the keyfunc for the key.
setdefault(k[, d ]) → D.get(k,d), also set D[k]=d if k not in D
update([E ], **F) → None. Update D from dict/iterable E and F.
If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method,
does: for (k, v) in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]
Many custom types and existing library classes can be used as a entity collection type as-is without further ado.
However, it is important to note that the instrumentation process will modify the type, adding decorators around
methods automatically.
The decorations are lightweight and no-op outside of relationships, but they do add unneeded overhead when triggered
elsewhere. When using a library class as a collection, it can be good practice to use the “trivial subclass” trick to restrict
the decorations to just your usage in relationships. For example:
class MyAwesomeList(some.great.library.AwesomeList):
pass
The ORM uses this approach for built-ins, quietly substituting a trivial subclass when a list, set or dict is used
directly.
Collection Internals
The recipe decorators all require parens, even those that take no arguments:
@collection.adds('entity')
def insert(self, position, entity): ...
@collection.removes_return()
def popitem(self): ...
This is a very specific case where relationship() must perform an INSERT and a second UPDATE in order to properly
populate a row (and vice versa an UPDATE and DELETE in order to delete without violating foreign key constraints).
The two use cases are:
• A table contains a foreign key to itself, and a single row will have a foreign key value pointing to its own primary
key.
• Two tables each contain a foreign key referencing the other table, with a row in each table referencing the other.
For example:
user
---------------------------------
user_id name related_user_id
1 'ed' 1
Or:
widget entry
------------------------------------------- ---------------------------------
widget_id name favorite_entry_id entry_id name widget_id
1 'somewidget' 5 5 'someentry' 1
In the first case, a row points to itself. Technically, a database that uses sequences such as PostgreSQL or Oracle
can INSERT the row at once using a previously generated value, but databases which rely upon autoincrement-style
primary key identifiers cannot. The relationship() always assumes a “parent/child” model of row population
during flush, so unless you are populating the primary key/foreign key columns directly, relationship() needs
to use two statements.
In the second case, the “widget” row must be inserted before any referring “entry” rows, but then the “fa-
vorite_entry_id” column of that “widget” row cannot be set until the “entry” rows have been generated. In this case,
it’s typically impossible to insert the “widget” and “entry” rows using just two INSERT statements; an UPDATE must
be performed in order to keep foreign key constraints fulfilled. The exception is if the foreign keys are configured
as “deferred until commit” (a feature some databases support) and if the identifiers were populated manually (again
essentially bypassing relationship()).
To enable the usage of a supplementary UPDATE statement, we use the post_update option of
relationship(). This specifies that the linkage between the two rows should be created using an UPDATE state-
ment after both rows have been INSERTED; it also causes the rows to be de-associated with each other via UPDATE
before a DELETE is emitted. The flag should be placed on just one of the relationships, preferably the many-to-one
side. Below we illustrate a complete example, including two ForeignKey constructs:
from sqlalchemy import Integer, ForeignKey, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Entry(Base):
__tablename__ = 'entry'
entry_id = Column(Integer, primary_key=True)
widget_id = Column(Integer, ForeignKey('widget.widget_id'))
name = Column(String(50))
class Widget(Base):
__tablename__ = 'widget'
When a structure against the above configuration is flushed, the “widget” row will be INSERTed minus the “fa-
vorite_entry_id” value, then all the “entry” rows will be INSERTed referencing the parent “widget” row, and then an
UPDATE statement will populate the “favorite_entry_id” column of the “widget” table (it’s one row at a time for the
time being):
>>> w1 = Widget(name='somewidget')
>>> e1 = Entry(name='someentry')
>>> w1.favorite_entry = e1
>>> w1.entries = [e1]
>>> session.add_all([w1, e1])
>>> session.commit()
BEGIN (implicit)
INSERT INTO widget (favorite_entry_id, name) VALUES (?, ?)
(None, 'somewidget')
INSERT INTO entry (widget_id, name) VALUES (?, ?)
(1, 'someentry')
UPDATE widget SET favorite_entry_id=? WHERE widget.widget_id = ?
(1, 1)
COMMIT
An additional configuration we can specify is to supply a more comprehensive foreign key constraint on Widget,
such that it’s guaranteed that favorite_entry_id refers to an Entry that also refers to this Widget. We can
use a composite foreign key, as illustrated below:
from sqlalchemy import Integer, ForeignKey, String, \
Column, UniqueConstraint, ForeignKeyConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Entry(Base):
__tablename__ = 'entry'
entry_id = Column(Integer, primary_key=True)
widget_id = Column(Integer, ForeignKey('widget.widget_id'))
name = Column(String(50))
__table_args__ = (
UniqueConstraint("entry_id", "widget_id"),
)
class Widget(Base):
__tablename__ = 'widget'
name = Column(String(50))
__table_args__ = (
ForeignKeyConstraint(
["widget_id", "favorite_entry_id"],
["entry.widget_id", "entry.entry_id"],
name="fk_favorite_entry"
),
)
The above mapping features a composite ForeignKeyConstraint bridging the widget_id and
favorite_entry_id columns. To ensure that Widget.widget_id remains an “autoincrementing” column we
specify autoincrement to the value "ignore_fk" on Column, and additionally on each relationship()
we must limit those columns considered as part of the foreign key for the purposes of joining and cross-population.
When the primary key of an entity changes, related items which reference the primary key must also be updated as well.
For databases which enforce referential integrity, the best strategy is to use the database’s ON UPDATE CASCADE
functionality in order to propagate primary key changes to referenced foreign keys - the values cannot be out of sync
for any moment unless the constraints are marked as “deferrable”, that is, not enforced until the transaction completes.
It is highly recommended that an application which seeks to employ natural primary keys with mutable values to use
the ON UPDATE CASCADE capabilities of the database. An example mapping which illustrates this is:
class User(Base):
__tablename__ = 'user'
__table_args__ = {'mysql_engine': 'InnoDB'}
addresses = relationship("Address")
class Address(Base):
__tablename__ = 'address'
__table_args__ = {'mysql_engine': 'InnoDB'}
Above, we illustrate onupdate="cascade" on the ForeignKey object, and we also illustrate the
mysql_engine=’InnoDB’ setting which, on a MySQL backend, ensures that the InnoDB engine supporting
referential integrity is used. When using SQLite, referential integrity should be enabled, using the configuration de-
scribed at Foreign Key Support.
In those cases when a database that does not support referential integrity is used, and natural primary keys with mu-
table values are in play, SQLAlchemy offers a feature in order to allow propagation of primary key values to already-
referenced foreign keys to a limited extent, by emitting an UPDATE statement against foreign key columns that imme-
diately reference a primary key column whose value has changed. The primary platforms without referential integrity
features are MySQL when the MyISAM storage engine is used, and SQLite when the PRAGMA foreign_keys=ON
pragma is not used. The Oracle database also has no support for ON UPDATE CASCADE, but because it still enforces
referential integrity, needs constraints to be marked as deferrable so that SQLAlchemy can emit UPDATE statements.
The feature is enabled by setting the passive_updates flag to False, most preferably on a one-to-many or
many-to-many relationship(). When “updates” are no longer “passive” this indicates that SQLAlchemy will
issue UPDATE statements individually for objects referenced in the collection referred to by the parent object with a
changing primary key value. This also implies that collections will be fully loaded into memory if not already locally
present.
Our previous mapping using passive_updates=False looks like:
class User(Base):
__tablename__ = 'user'
class Address(Base):
__tablename__ = 'address'
Some arguments accepted by relationship() optionally accept a callable function, which when called
produces the desired value. The callable is invoked by the parent Mapper at “mapper initialization” time, which
happens only when mappers are first used, and is assumed to be after all mappings have been constructed. This
can be used to resolve order-of-declaration and other dependency issues, such as if Child is declared below
Parent in the same file:
mapper(Parent, properties={
"children":relationship(lambda: Child,
order_by=lambda: Child.id)
})
When using the Declarative extension, the Declarative initializer allows string arguments to be passed to
relationship(). These string arguments are converted into callables that evaluate the string as Python
code, using the Declarative class-registry as a namespace. This allows the lookup of related classes to be auto-
matic via their string name, and removes the need to import related classes at all into the local module space:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", order_by="Child.id")
See also:
Relationship Configuration - Full introductory and reference documentation for relationship().
Building a Relationship - ORM tutorial introduction.
Parameters
• argument – a mapped class, or actual Mapper instance, representing the target of the
relationship.
argument may also be passed as a callable function which is evaluated at mapper initial-
ization time, and may be passed as a Python-evaluable string when using Declarative.
See also:
Configuring Relationships - further detail on relationship configuration when using Declar-
ative.
• secondary – for a many-to-many relationship, specifies the intermediary table, and is
typically an instance of Table. In less common circumstances, the argument may also be
specified as an Alias construct, or even a Join construct.
secondary may also be passed as a callable function which is evaluated at mapper ini-
tialization time. When using Declarative, it may also be a string argument noting the name
of a Table that is present in the MetaData collection associated with the parent-mapped
Table.
The secondary keyword argument is typically applied in the case where the intermediary
Table is not otherwise expressed in any direct class mapping. If the “secondary” table
is also explicitly mapped elsewhere (e.g. as in Association Object), one should consider
applying the viewonly flag so that this relationship() is not used for persistence
operations which may conflict with those of the association object pattern.
See also:
Many To Many - Reference example of “many to many”.
Building a Many To Many Relationship - ORM tutorial introduction to many-to-many rela-
tionships.
Self-Referential Many-to-Many Relationship - Specifics on using many-to-many in a self-
referential case.
Configuring Many-to-Many Relationships - Additional options when using Declarative.
Association Object - an alternative to secondary when composing association table rela-
tionships, allowing additional attributes to be specified on the association table.
Composite “Secondary” Joins - a lesser-used pattern which in some cases can enable com-
plex relationship() SQL conditions to be used.
New in version 0.9.2: secondary works more effectively when referring to a Join in-
stance.
• active_history=False – When True, indicates that the “previous” value for a
many-to-one reference should be loaded when replaced, if not already loaded. Normally,
history tracking logic for simple many-to-ones only needs to be aware of the “new” value
in order to perform a flush. This flag is available for applications that make use of
attributes.get_history() which also need to know the “previous” value of the
attribute.
• backref – indicates the string name of a property to be placed on the related mapper’s
class that will handle this relationship in the other direction. The other property will be cre-
ated automatically when the mappers are configured. Can also be passed as a backref()
object to control the configuration of the new relationship.
See also:
Linking Relationships with Backref - Introductory documentation and examples.
back_populates - alternative form of backref specification.
Setting this flag to False when baked queries are otherwise in use might be to reduce ORM
memory use for this relationship(), or to work around unresolved stability issues
observed within the baked query cache system.
New in version 1.0.0.
See also:
Baked Queries
• cascade – a comma-separated list of cascade rules which determines how Session opera-
tions should be “cascaded” from parent to child. This defaults to False, which means the
default cascade should be used - this default cascade is "save-update, merge".
The available cascades are save-update, merge, expunge, delete,
delete-orphan, and refresh-expire. An additional option, all indicates short-
hand for "save-update, merge, refresh-expire, expunge, delete",
and is often used as in "all, delete-orphan" to indicate that related objects should
follow along with the parent object in all cases, and be deleted when de-associated.
See also:
Cascades - Full detail on each of the available cascade options.
Configuring delete/delete-orphan Cascade - Tutorial example describing a delete cascade.
• cascade_backrefs=True – a boolean value indicating if the save-update cascade
should operate along an assignment event intercepted by a backref. When set to False, the
attribute managed by this relationship will not cascade an incoming transient object into the
session of a persistent parent, if the event is received via backref.
See also:
Controlling Cascade on Backrefs - Full discussion and examples on how the
cascade_backrefs option is used.
• collection_class – a class or callable that returns a new list-holding object. will be
used in place of a plain list for storing elements.
See also:
– select - items should be loaded lazily when the property is first accessed, using a
separate SELECT statement, or identity map fetch for simple many-to-one references.
– immediate - items should be loaded as the parents are loaded, using a separate SELECT
statement, or identity map fetch for simple many-to-one references.
– joined - items should be loaded “eagerly” in the same query as that of the parent, using
a JOIN or LEFT OUTER JOIN. Whether the join is “outer” or not is determined by the
innerjoin parameter.
– subquery - items should be loaded “eagerly” as the parents are loaded, using one ad-
ditional SQL statement, which issues a JOIN to a subquery of the original statement, for
each collection requested.
– noload - no loading should occur at any time. This is to support “write-only” attributes,
or attributes which are populated in some manner specific to the application.
– dynamic - the attribute will return a pre-configured Query object for all read opera-
tions, onto which further filtering operations can be applied before iterating the results.
See the section Dynamic Relationship Loaders for more details.
– True - a synonym for ‘select’
– False - a synonym for ‘joined’
– None - a synonym for ‘noload’
See also:
Relationship Loading Techniques - Full documentation on relationship loader configuration.
Dynamic Relationship Loaders - detail on the dynamic option.
• load_on_pending=False – Indicates loading behavior for transient or pending parent
objects.
When set to True, causes the lazy-loader to issue a query for a parent object that is not
persistent, meaning it has never been flushed. This may take effect for a pending object
when autoflush is disabled, or for a transient object that has been “attached” to a Session
but is not part of its pending collection.
The load_on_pending flag does not improve behavior when the ORM is used normally
- object references should be constructed at the object level, not at the foreign key level, so
that they are present in an ordinary way before a flush proceeds. This flag is not not intended
for general use.
See also:
Session.enable_relationship_loading() - this method establishes “load on
pending” behavior for the whole object, and also allows loading on objects that remain
transient or detached.
• order_by – indicates the ordering that should be applied when loading these items.
order_by is expected to refer to one of the Column objects to which the target class
is mapped, or the attribute itself bound to the target class which refers to the column.
order_by may also be passed as a callable function which is evaluated at mapper initial-
ization time, and may be passed as a Python-evaluable string when using Declarative.
• passive_deletes=False – Indicates loading behavior during delete operations.
A value of True indicates that unloaded child items should not be loaded during a delete
operation on the parent. Normally, when a parent item is deleted, all child items are loaded
so that they can either be marked as deleted, or have their foreign key to the parent set
>>> User.addresses.property.uselist
True
See also:
One To One - Introduction to the “one to one” relationship pattern, which is typically when
the uselist flag is needed.
• viewonly=False – when set to True, the relationship is used only for loading objects,
and not for any persistence operation. A relationship() which specifies viewonly
can work with a wider range of SQL operations within the primaryjoin condition, in-
cluding operations that feature the use of a variety of comparison operators as well as SQL
functions such as cast(). The viewonly flag is also of general use when defining any
kind of relationship() that doesn’t represent the full set of related objects, to prevent
modifications of the collection from resulting in persistence operations.
sqlalchemy.orm.backref(name, **kwargs)
Create a back reference with explicit keyword arguments, which are the same arguments one can send to
relationship().
Used with the backref keyword argument to relationship() in place of a string argument, e.g.:
'items':relationship(
SomeItem, backref=backref('parent', lazy='subquery'))
See also:
Linking Relationships with Backref
sqlalchemy.orm.relation(*arg, **kw)
A synonym for relationship().
sqlalchemy.orm.dynamic_loader(argument, **kw)
Construct a dynamically-loading mapper property.
This is essentially the same as using the lazy=’dynamic’ argument with relationship():
dynamic_loader(SomeClass)
# is the same as
relationship(SomeClass, lazy="dynamic")
See the section Dynamic Relationship Loaders for more details on dynamic loading.
sqlalchemy.orm.foreign(expr)
Annotate a portion of a primaryjoin expression with a ‘foreign’ annotation.
See the section Creating Custom Foreign Conditions for a description of use.
New in version 0.8.
See also:
Creating Custom Foreign Conditions
remote()
sqlalchemy.orm.remote(expr)
Annotate a portion of a primaryjoin expression with a ‘remote’ annotation.
See the section Creating Custom Foreign Conditions for a description of use.
New in version 0.8.
See also:
Creating Custom Foreign Conditions
foreign()
This feature allows particular columns of a table be loaded only upon direct access, instead of when the entity is queried
using Query. This feature is useful when one wants to avoid loading a large text or binary field into memory when
it’s not needed. Individual columns can be lazy loaded by themselves or placed into groups that lazy-load together,
using the orm.deferred() function to mark them as “deferred”. In the example below, we define a mapping that
will load each of .excerpt and .photo in separate, individual-row SELECT statements when each attribute is first
referenced on the individual object instance:
from sqlalchemy.orm import deferred
from sqlalchemy import Integer, String, Text, Binary, Column
class Book(Base):
__tablename__ = 'book'
Classical mappings as always place the usage of orm.deferred() in the properties dictionary against the
table-bound Column:
mapper(Book, book_table, properties={
'photo':deferred(book_table.c.photo)
})
Deferred columns can be associated with a “group” name, so that they load together when any of them are first
accessed. The example below defines a mapping with a photos deferred group. When one .photo is accessed, all
three photos will be loaded in one SELECT statement. The .excerpt will be loaded separately when it is accessed:
class Book(Base):
__tablename__ = 'book'
You can defer or undefer columns at the Query level using options, including orm.defer() and
orm.undefer():
from sqlalchemy.orm import defer, undefer
query = session.query(Book)
query = query.options(defer('summary'))
query = query.options(undefer('excerpt'))
query.all()
orm.deferred() attributes which are marked with a “group” can be undeferred using orm.undefer_group(),
sending in the group name:
from sqlalchemy.orm import undefer_group
query = session.query(Book)
query.options(undefer_group('photos')).all()
An arbitrary set of columns can be selected as “load only” columns, which will be loaded while deferring all other
columns on a given entity, using orm.load_only():
from sqlalchemy.orm import load_only
session.query(Book).options(load_only("summary", "excerpt"))
To specify column deferral options within a Query that loads multiple types of entity, the Load object can specify
which parent entity to start with:
from sqlalchemy.orm import Load
To specify column deferral options along the path of various relationships, the options support chaining, where the
loading style of each relationship is specified first, then is chained to the deferral options. Such as, to load Book
instances, then joined-eager-load the Author, then apply deferral options to the Author entity:
query = session.query(Book)
query = query.options(
joinedload(Book.author).load_only("summary", "excerpt"),
)
In the case where the loading style of parent relationships should be left unchanged, use orm.defaultload():
from sqlalchemy.orm import defaultload
query = session.query(Book)
query = query.options(
defaultload(Book.author).load_only("summary", "excerpt"),
)
New in version 0.9.0: support for Load and other options which allow for better targeting of deferral options.
sqlalchemy.orm.deferred(*columns, **kw)
Indicate a column-based mapped attribute that by default will not load unless accessed.
Parameters
• *columns – columns to be mapped. This is typically a single Column object, however
a collection is supported in order to support multiple columns mapped under the same at-
tribute.
• **kw – additional keyword arguments passed to ColumnProperty.
See also:
Deferred Column Loading
sqlalchemy.orm.defer(key, *addl_attrs)
Indicate that the given column-oriented attribute should be deferred, e.g. not loaded until accessed.
This function is part of the Load interface and supports both method-chained and standalone operation.
e.g.:
from sqlalchemy.orm import defer
session.query(MyClass).options(
defer("attribute_one"),
defer("attribute_two"))
session.query(MyClass).options(
defer(MyClass.attribute_one),
defer(MyClass.attribute_two))
To specify a deferred load of an attribute on a related class, the path can be specified one token at a time,
specifying the loading style for each link along the chain. To leave the loading style for a link unchanged, use
orm.defaultload():
session.query(MyClass).options(defaultload("someattr").defer("some_column"))
A Load object that is present on a certain path can have Load.defer() called multiple times, each will
operate on the same parent entity:
session.query(MyClass).options(
defaultload("someattr").
defer("some_column").
defer("some_other_column").
defer("another_column")
)
Parameters
• key – Attribute to be deferred.
• *addl_attrs – Deprecated; this option supports the old 0.8 style of specifying a path as
a series of attributes, which is now superseded by the method-chained style.
See also:
Deferred Column Loading
orm.undefer()
sqlalchemy.orm.load_only(*attrs)
Indicate that for a particular entity, only the given list of column-based attribute names should be loaded; all
others will be deferred.
This function is part of the Load interface and supports both method-chained and standalone operation.
Example - given a class User, load only the name and fullname attributes:
session.query(User).options(load_only("name", "fullname"))
Example - given a relationship User.addresses -> Address, specify subquery loading for the
User.addresses collection, but on each Address object load only the email_address attribute:
session.query(User).options(
subqueryload("addresses").load_only("email_address")
)
For a Query that has multiple entities, the lead entity can be specifically referred to using the Load constructor:
session.query(User, Address).join(User.addresses).options(
Load(User).load_only("name", "fullname"),
Load(Address).load_only("email_addres")
)
Parameters
• key – Attribute to be undeferred.
• *addl_attrs – Deprecated; this option supports the old 0.8 style of specifying a path as
a series of attributes, which is now superseded by the method-chained style.
See also:
Deferred Column Loading
orm.defer()
orm.undefer_group()
sqlalchemy.orm.undefer_group(name)
Indicate that columns within the given deferred group name should be undeferred.
The columns being undeferred are set up on the mapping as deferred() attributes and include a “group”
name.
E.g:
session.query(MyClass).options(undefer_group("large_attrs"))
To undefer a group of attributes on a related entity, the path can be spelled out using relationship loader options,
such as orm.defaultload():
session.query(MyClass).options(
defaultload("someattr").undefer_group("large_attrs"))
Changed in version 0.9.0: orm.undefer_group() is now specific to a particiular entity load path.
See also:
Deferred Column Loading
orm.defer()
orm.undefer()
Column Bundles
The Bundle may be used to query for groups of columns under one namespace.
New in version 0.9.0.
The bundle allows columns to be grouped together:
from sqlalchemy.orm import Bundle
The bundle can be subclassed to provide custom behaviors when results are fetched. The method
Bundle.create_row_processor() is given the Query and a set of “row processor” functions at query execu-
tion time; these processor functions when given a result row will return the individual attribute value, which can then
be adapted into any kind of return data structure. Below illustrates replacing the usual KeyedTuple return structure
with a straight Python dictionary:
class DictBundle(Bundle):
def create_row_processor(self, query, procs, labels):
"""Override create_row_processor to return values as dictionaries"""
def proc(row):
return dict(
zip(labels, (proc(row) for proc in procs))
)
return proc
Changed in version 1.0: The proc() callable passed to the create_row_processor() method of custom
Bundle classes now accepts only a single “row” argument.
A result from the above bundle will return dictionary values:
bn = DictBundle('mybundle', MyClass.data1, MyClass.data2)
for row in session.query(bn).filter(bn.c.data1 == 'd1'):
print row.mybundle['data1'], row.mybundle['data2']
The Bundle construct is also integrated into the behavior of composite(), where it is used to return composite
attributes as objects when queried as individual attributes.
A big part of SQLAlchemy is providing a wide range of control over how related objects get loaded when querying.
This behavior can be configured at mapper construction time using the lazy parameter to the relationship()
function, as well as by using options with the Query object.
By default, all inter-object relationships are lazy loading. The scalar or collection attribute associated with a
relationship() contains a trigger which fires the first time the attribute is accessed. This trigger, in all but
one case, issues a SQL call at the point of access in order to load the related object or objects:
>>> jack.addresses
SELECT addresses.id AS addresses_id, addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE ? = addresses.user_id
[5]
[<Address(u'[email protected]')>, <Address(u'[email protected]')>]
The one case where SQL is not emitted is for a simple many-to-one relationship, when the related object can be
identified by its primary key alone and that object is already present in the current Session.
This default behavior of “load upon attribute access” is known as “lazy” or “select” loading - the name “select” because
a “SELECT” statement is typically emitted when the attribute is first accessed.
In the Object Relational Tutorial, we introduced the concept of Eager Loading. We used an option in conjunction
with the Query object in order to indicate that a relationship should be loaded at the same time as the parent, within
a single SQL query. This option, known as joinedload(), connects a JOIN (by default a LEFT OUTER join) to
the statement and populates the scalar/collection from the same result set as that of the parent:
>>> jack = session.query(User).\
... options(joinedload('addresses')).\
... filter_by(name='jack').all() #doctest: +NORMALIZE_WHITESPACE
In addition to “joined eager loading”, a second option for eager loading exists, called “subquery eager loading”. This
kind of eager loading emits an additional SQL statement for each collection requested, aggregated across all parent
objects:
>>> jack = session.query(User).\
... options(subqueryload('addresses')).\
... filter_by(name='jack').all()
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?
('jack',)
SELECT addresses.id AS addresses_id, addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id, anon_1.users_id AS anon_1_users_id
FROM (SELECT users.id AS users_id
FROM users
WHERE users.name = ?) AS anon_1 JOIN addresses ON anon_1.users_id = addresses.user_id
ORDER BY anon_1.users_id, addresses.id
('jack',)
The default loader strategy for any relationship() is configured by the lazy keyword argument, which de-
faults to select - this indicates a “select” statement . Below we set it as joined so that the children relationship
is eager loaded using a JOIN:
# load the 'children' collection using LEFT OUTER JOIN
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", lazy='joined')
We can also set it to eagerly load using a second query for all collections, using subquery:
# load the 'children' collection using a second query which
# JOINS to a subquery of the original
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", lazy='subquery')
When querying, all three choices of loader strategy are available on a per-query basis, using the joinedload(),
subqueryload() and lazyload() query options:
# set children to load lazily
session.query(Parent).options(lazyload('children')).all()
A query which makes use of subqueryload() in conjunction with a limiting modifier such as Query.first(),
Query.limit(), or Query.offset() should always include Query.order_by() against unique column(s)
such as the primary key, so that the additional queries emitted by subqueryload() include the same ordering as
used by the parent query. Without it, there is a chance that the inner query could return the wrong rows:
# incorrect, no ORDER BY
session.query(User).options(subqueryload(User.addresses)).first()
# correct
session.query(User).options(subqueryload(User.addresses)).order_by(User.name, User.id).first()
See also:
Why is ORDER BY required with LIMIT (especially with subqueryload())? - detailed example
To reference a relationship that is deeper than one level, method chaining may be used. The object returned by all
loader options is an instance of the Load class, which provides a so-called “generative” interface:
session.query(Parent).options(
joinedload('foo').
joinedload('bar').
joinedload('bat')
).all()
Using method chaining, the loader style of each link in the path is explicitly stated. To navigate along a path without
changing the existing loader style of a particular attribute, the defaultload() method/function may be used:
session.query(A).options(
defaultload("atob").joinedload("btoc")
).all()
Changed in version 0.9.0: The previous approach of specifying dot-separated paths within loader options has been su-
perseded by the less ambiguous approach of the Load object and related methods. With this system, the user specifies
the style of loading for each link along the chain explicitly, rather than guessing between options like joinedload()
vs. joinedload_all(). The orm.defaultload() is provided to allow path navigation without modification
of existing loader options. The dot-separated path system as well as the _all() functions will remain available for
backwards- compatibility indefinitely.
Above, the lazyload(’*’) option will supersede the lazy setting of all relationship() constructs in
use for that query, except for those which use the ’dynamic’ style of loading. If some relationships specify
lazy=’joined’ or lazy=’subquery’, for example, using lazyload(’*’) will unilaterally cause all those
relationships to use ’select’ loading, e.g. emit a SELECT statement when each attribute is accessed.
The option does not supersede loader options stated in the query, such as eagerload(), subqueryload(), etc.
The query below will still use joined loading for the widget relationship:
session.query(MyClass).options(
lazyload('*'),
joinedload(MyClass.widget)
)
If multiple ’*’ options are passed, the last one overrides those previously passed.
The philosophy behind loader strategies is that any set of loading schemes can be applied to a particular query, and
the results don’t change - only the number of SQL statements required to fully load related objects and collections
changes. A particular query might start out using all lazy loads. After using it in context, it might be revealed that
particular attributes or collections are always accessed, and that it would be more efficient to change the loader strategy
for these. The strategy can be changed with no other modifications to the query, the results will remain identical, but
fewer SQL statements would be emitted. In theory (and pretty much in practice), nothing you can do to the Query
would make it load a different set of primary or related objects based on a change in loader strategy.
How joinedload() in particular achieves this result of not impacting entity rows returned in any way is that
it creates an anonymous alias of the joins it adds to your query, so that they can’t be referenced by other parts of
the query. For example, the query below uses joinedload() to create a LEFT OUTER JOIN from users to
addresses, however the ORDER BY added against Address.email_address is not valid - the Address
entity is not named in the query:
>>> jack = session.query(User).\
... options(joinedload(User.addresses)).\
... filter(User.name=='jack').\
... order_by(Address.email_address).all()
SELECT addresses_1.id AS addresses_1_id, addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id, users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname, users.password AS users_password
FROM users LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = ? ORDER BY addresses.email_address <-- this part is wrong !
['jack']
Above, ORDER BY addresses.email_address is not valid since addresses is not in the FROM list. The
correct way to load the User records and order by email address is to use Query.join():
The statement above is of course not the same as the previous one, in that the columns from addresses are not
included in the result at all. We can add joinedload() back in, so that there are two joins - one is that which we
are ordering on, the other is used anonymously to load the contents of the User.addresses collection:
>>> jack = session.query(User).\
... join(User.addresses).\
... options(joinedload(User.addresses)).\
... filter(User.name=='jack').\
... order_by(Address.email_address).all()
SELECT addresses_1.id AS addresses_1_id, addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id, users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname, users.password AS users_password
FROM users JOIN addresses ON users.id = addresses.user_id
LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = ? ORDER BY addresses.email_address
['jack']
What we see above is that our usage of Query.join() is to supply JOIN clauses we’d like to use in sub-
sequent query criterion, whereas our usage of joinedload() only concerns itself with the loading of the
User.addresses collection, for each User in the result. In this case, the two joins most probably appear re-
dundant - which they are. If we wanted to use just one JOIN for collection loading as well as ordering, we use
the contains_eager() option, described in Routing Explicit Joins/Statements into Eagerly Loaded Collections
below. But to see why joinedload() does what it does, consider if we were filtering on a particular Address:
>>> jack = session.query(User).\
... join(User.addresses).\
... options(joinedload(User.addresses)).\
... filter(User.name=='jack').\
... filter(Address.email_address=='[email protected]').\
... all()
SELECT addresses_1.id AS addresses_1_id, addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id, users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname, users.password AS users_password
FROM users JOIN addresses ON users.id = addresses.user_id
LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = ? AND addresses.email_address = ?
['jack', '[email protected]']
Above, we can see that the two JOINs have very different roles. One will match exactly one row, that of the join
of User and Address where Address.email_address==’[email protected]’. The other LEFT
OUTER JOIN will match all Address rows related to User, and is only used to populate the User.addresses
collection, for those User objects that are returned.
By changing the usage of joinedload() to another style of loading, we can change how the collection is loaded
completely independently of SQL used to retrieve the actual User rows we want. Below we change joinedload()
into subqueryload():
When using joined eager loading, if the query contains a modifier that impacts the rows returned externally to the
joins, such as when using DISTINCT, LIMIT, OFFSET or equivalent, the completed statement is first wrapped inside
a subquery, and the joins used specifically for joined eager loading are applied to the subquery. SQLAlchemy’s joined
eager loading goes the extra mile, and then ten miles further, to absolutely ensure that it does not affect the end result
of the query, only the way collections and related objects are loaded, no matter what the format of the query is.
Which type of loading to use typically comes down to optimizing the tradeoff between number of SQL executions,
complexity of SQL emitted, and amount of data fetched. Lets take two examples, a relationship() which
references a collection, and a relationship() that references a scalar many-to-one reference.
• One to Many Collection
• When using the default lazy loading, if you load 100 objects, and then access a collection on each of them, a total
of 101 SQL statements will be emitted, although each statement will typically be a simple SELECT without any
joins.
• When using joined loading, the load of 100 objects and their collections will emit only one SQL statement.
However, the total number of rows fetched will be equal to the sum of the size of all the collections, plus one
extra row for each parent object that has an empty collection. Each row will also contain the full set of columns
represented by the parents, repeated for each collection item - SQLAlchemy does not re-fetch these columns
other than those of the primary key, however most DBAPIs (with some exceptions) will transmit the full data
of each parent over the wire to the client connection in any case. Therefore joined eager loading only makes
sense when the size of the collections are relatively small. The LEFT OUTER JOIN can also be performance
intensive compared to an INNER join.
• When using subquery loading, the load of 100 objects will emit two SQL statements. The second statement
will fetch a total number of rows equal to the sum of the size of all collections. An INNER JOIN is used, and
a minimum of parent columns are requested, only the primary keys. So a subquery load makes sense when the
collections are larger.
• When multiple levels of depth are used with joined or subquery loading, loading collections-within- collections
will multiply the total number of rows fetched in a cartesian fashion. Both forms of eager loading always join
from the original parent class.
• Many to One Reference
• When using the default lazy loading, a load of 100 objects will like in the case of the collection emit as many
as 101 SQL statements. However - there is a significant exception to this, in that if the many-to-one reference
is a simple foreign key reference to the target’s primary key, each reference will be checked first in the current
identity map using Query.get(). So here, if the collection of objects references a relatively small set of
target objects, or the full set of possible target objects have already been loaded into the session and are strongly
referenced, using the default of lazy=’select’ is by far the most efficient way to go.
• When using joined loading, the load of 100 objects will emit only one SQL statement. The join will be a LEFT
OUTER JOIN, and the total number of rows will be equal to 100 in all cases. If you know that each parent
definitely has a child (i.e. the foreign key reference is NOT NULL), the joined load can be configured with
innerjoin set to True, which is usually specified within the relationship(). For a load of objects
where there are many possible target references which may have not been loaded already, joined loading with
an INNER JOIN is extremely efficient.
• Subquery loading will issue a second load for all the child objects, so for a load of 100 objects there would be
two SQL statements emitted. There’s probably not much advantage here over joined loading, however, except
perhaps that subquery loading can use an INNER JOIN in all cases whereas joined loading requires that the
foreign key is NOT NULL.
The behavior of joinedload() is such that joins are created automatically, using anonymous aliases as targets, the
results of which are routed into collections and scalar references on loaded objects. It is often the case that a query
already includes the necessary joins which represent a particular collection or scalar reference, and the joins added by
the joinedload feature are redundant - yet you’d still like the collections/references to be populated.
For this SQLAlchemy supplies the contains_eager() option. This option is used in the same manner as the
joinedload() option except it is assumed that the Query will specify the appropriate joins explicitly. Be-
low, we specify a join between User and Address and addtionally establish this as the basis for eager loading
of User.addresses:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
addresses = relationship("Address")
class Address(Base):
__tablename__ = 'address'
# ...
q = session.query(User).join(User.addresses).\
options(contains_eager(User.addresses))
If the “eager” portion of the statement is “aliased”, the alias keyword argument to contains_eager() may be
used to indicate it. This is sent as a reference to an aliased() or Alias construct:
# use an alias of the Address entity
adalias = aliased(Address)
The path given as the argument to contains_eager() needs to be a full path from the starting entity. For example
if we were loading Users->orders->Order->items->Item, the string version would look like:
query(User).options(contains_eager('orders').contains_eager('items'))
When we use contains_eager(), we are constructing ourselves the SQL that will be used to populate collections.
From this, it naturally follows that we can opt to modify what values the collection is intended to store, by writing our
SQL to load a subset of elements for collections or scalar attributes.
As an example, we can load a User object and eagerly load only particular addresses into its .addresses collection
just by filtering:
q = session.query(User).join(User.addresses).\
filter(Address.email.like('%ed%')).\
options(contains_eager(User.addresses))
The above query will load only User objects which contain at least Address object that contains the substring ’ed’
in its email field; the User.addresses collection will contain only these Address entries, and not any other
Address entries that are in fact associated with the collection.
Warning: Keep in mind that when we load only a subset of objects into a collection, that collection no longer
represents what’s actually in the database. If we attempted to add entries to this collection, we might find ourselves
conflicting with entries that are already in the database but not locally loaded.
In addition, the collection will fully reload normally once the object or attribute is expired. This expiration oc-
curs whenever the Session.commit(), Session.rollback() methods are used assuming default session
settings, or the Session.expire_all() or Session.expire() methods are used.
For these reasons, prefer returning separate fields in a tuple rather than artificially altering a collection, when an
object plus a custom set of related objects is desired:
q = session.query(User, Address).join(User.addresses).\
filter(Address.email.like('%ed%'))
The alias argument can be more creatively used, in that it can be made to represent any set of arbitrary names to
match up into a statement. Below it is linked to a select() which links a set of column objects to a string SQL
statement:
# label the columns of the addresses table
eager_columns = select([
addresses.c.address_id.label('a1'),
addresses.c.email_address.label('a2'),
addresses.c.user_id.label('a3')])
# select from a raw SQL statement which uses those label names for the
# addresses table. contains_eager() matches them up.
query = session.query(User).\
from_statement("select users.*, addresses.address_id as a1, "
Warning: This is an advanced technique! Great care and testing should be applied.
The ORM has various edge cases where the value of an attribute is locally available, however the ORM itself doesn’t
have awareness of this. There are also cases when a user-defined system of loading attributes is desirable. To sup-
port the use case of user-defined loading systems, a key function attributes.set_committed_value() is
provided. This function is basically equivalent to Python’s own setattr() function, except that when applied to
a target object, SQLAlchemy’s “attribute history” system which is used to determine flush-time changes is bypassed;
the attribute is assigned in the same way as if the ORM loaded it that way from the database.
The use of attributes.set_committed_value() can be combined with another key event known as
InstanceEvents.load() to produce attribute-population behaviors when an object is loaded. One such ex-
ample is the bi-directional “one-to-one” case, where loading the “many-to-one” side of a one-to-one should also imply
the value of the “one-to-many” side. The SQLAlchemy ORM does not consider backrefs when loading related objects,
and it views a “one-to-one” as just another “one-to-many”, that just happens to be one row.
Given the following mapping:
from sqlalchemy import Integer, ForeignKey, Column
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey('b.id'))
b = relationship("B", backref=backref("a", uselist=False), lazy='joined')
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
If we query for an A row, and then ask it for a.b.a, we will get an extra SELECT:
>>> a1.b.a
SELECT a.id AS a_id, a.b_id AS a_b_id
FROM a
WHERE ? = a.b_id
This SELECT is redundant becasue b.a is the same value as a1. We can create an on-load rule to populate this for
us:
from sqlalchemy import event
from sqlalchemy.orm import attributes
@event.listens_for(A, "load")
def load_b(target, context):
if 'b' in target.__dict__:
attributes.set_committed_value(target.b, 'a', target)
Now when we query for A, we will get A.b from the joined eager load, and A.b.a from our event:
a1 = s.query(A).first()
SELECT a.id AS a_id, a.b_id AS a_b_id, b_1.id AS b_1_id
FROM a LEFT OUTER JOIN b AS b_1 ON b_1.id = a.b_id
LIMIT ? OFFSET ?
(1, 0)
assert a1.b.a is a1
sqlalchemy.orm.contains_alias(alias)
Return a MapperOption that will indicate to the Query that the main table has been aliased.
This is a seldom-used option to suit the very rare case that contains_eager() is being used in conjunction
with a user-defined SELECT statement that aliases the parent table. E.g.:
# define an aliased UNION called 'ulist'
ulist = users.select(users.c.user_id==7).\
union(users.select(users.c.user_id>7)).\
alias('ulist')
Parameters alias – is the string name of an alias, or a Alias object representing the alias.
sqlalchemy.orm.contains_eager(*keys, **kw)
Indicate that the given attribute should be eagerly loaded from columns stated manually in the query.
This function is part of the Load interface and supports both method-chained and standalone operation.
The option is used in conjunction with an explicit join that loads the desired rows, i.e.:
sess.query(Order).\
join(Order.user).\
options(contains_eager(Order.user))
The above query would join from the Order entity to its related User entity, and the returned Order objects
would have the Order.user attribute pre-populated.
contains_eager() also accepts an alias argument, which is the string name of an alias, an alias()
construct, or an aliased() construct. Use this when the eagerly-loaded rows are to come from an aliased
table:
user_alias = aliased(User)
sess.query(Order).\
join((user_alias, Order.user)).\
options(contains_eager(Order.user, alias=user_alias))
See also:
Routing Explicit Joins/Statements into Eagerly Loaded Collections
sqlalchemy.orm.defaultload(*keys)
Indicate an attribute should load using its default loader style.
This method is used to link to other loader options, such as to set the orm.defer() option on a class that is
linked to a relationship of the parent class being loaded, orm.defaultload() can be used to navigate this
path without changing the loading style of the relationship:
session.query(MyClass).options(defaultload("someattr").defer("some_column"))
See also:
orm.defer()
orm.undefer()
sqlalchemy.orm.eagerload(*args, **kwargs)
A synonym for joinedload().
sqlalchemy.orm.eagerload_all(*args, **kwargs)
A synonym for joinedload_all()
sqlalchemy.orm.immediateload(*keys)
Indicate that the given attribute should be loaded using an immediate load with a per-attribute SELECT state-
ment.
This function is part of the Load interface and supports both method-chained and standalone operation.
See also:
Relationship Loading Techniques
orm.joinedload()
orm.lazyload()
relationship.lazy
sqlalchemy.orm.joinedload(*keys, **kw)
Indicate that the given attribute should be loaded using joined eager loading.
This function is part of the Load interface and supports both method-chained and standalone operation.
examples:
# joined-load the "orders" collection on "User"
query(User).options(joinedload(User.orders))
Parameters innerjoin – if True, indicates that the joined eager load should use an inner join
instead of the default of left outer join:
query(Order).options(joinedload(Order.user, innerjoin=True))
In order to chain multiple eager joins together where some may be OUTER and others INNER,
right-nested joins are used to link them:
query(A).options(
joinedload(A.bs, innerjoin=False).
joinedload(B.cs, innerjoin=True)
)
The above query, linking A.bs via “outer” join and B.cs via “inner” join would render the joins
as “a LEFT OUTER JOIN (b JOIN c)”. When using SQLite, this form of JOIN is translated to
use full subqueries as this syntax is otherwise not directly supported.
The innerjoin flag can also be stated with the term "unnested". This will prevent joins
from being right-nested, and will instead link an “innerjoin” eagerload to an “outerjoin” eager-
load by bypassing the “inner” join. Using this form as follows:
query(A).options(
joinedload(A.bs, innerjoin=False).
joinedload(B.cs, innerjoin="unnested")
)
Joins will be rendered as “a LEFT OUTER JOIN b LEFT OUTER JOIN c”, so that all of “a” is
matched rather than being incorrectly limited by a “b” that does not contain a “c”.
Note: The “unnested” flag does not affect the JOIN rendered from a many-to-many association
table, e.g. a table configured as relationship.secondary, to the target table; for cor-
rectness of results, these joins are always INNER and are therefore right-nested if linked to an
OUTER join.
New in version 0.9.4: Added support for “nesting” of eager “inner” joins. See Right-nested
inner joins available in joined eager loads.
Changed in version 1.0.0: innerjoin=True now implies innerjoin="nested",
whereas in 0.9 it implied innerjoin="unnested". In order to achieve the pre-1.0
“unnested” inner join behavior, use the value innerjoin="unnested". See Right inner
join nesting now the default for joinedload with innerjoin=True.
Note: The joins produced by orm.joinedload() are anonymously aliased. The criteria by which the join
proceeds cannot be modified, nor can the Query refer to these joins in any way, including ordering.
To produce a specific SQL JOIN which is explicitly available, use Query.join(). To combine explicit JOINs
with eager loading of collections, use orm.contains_eager(); see Routing Explicit Joins/Statements into
Eagerly Loaded Collections.
See also:
Relationship Loading Techniques
Routing Explicit Joins/Statements into Eagerly Loaded Collections
orm.subqueryload()
orm.lazyload()
relationship.lazy
relationship.innerjoin - relationship()-level version of the joinedload.innerjoin op-
tion.
sqlalchemy.orm.joinedload_all(*keys, **kw)
Produce a standalone “all” option for orm.joinedload().
Deprecated since version 0.9.0: The “_all()” style is replaced by method chaining, e.g.:
session.query(MyClass).options(
joinedload("someattribute").joinedload("anotherattribute")
)
sqlalchemy.orm.lazyload(*keys)
Indicate that the given attribute should be loaded using “lazy” loading.
This function is part of the Load interface and supports both method-chained and standalone operation.
See also:
relationship.lazy
sqlalchemy.orm.noload(*keys)
Indicate that the given relationship attribute should remain unloaded.
This function is part of the Load interface and supports both method-chained and standalone operation.
orm.noload() applies to relationship() attributes; for column-based attributes, see orm.defer().
sqlalchemy.orm.subqueryload(*keys)
Indicate that the given attribute should be loaded using subquery eager loading.
This function is part of the Load interface and supports both method-chained and standalone operation.
examples:
# subquery-load the "orders" collection on "User"
query(User).options(subqueryload(User.orders))
See also:
Relationship Loading Techniques
orm.joinedload()
orm.lazyload()
relationship.lazy
sqlalchemy.orm.subqueryload_all(*keys)
Produce a standalone “all” option for orm.subqueryload().
Deprecated since version 0.9.0: The “_all()” style is replaced by method chaining, e.g.:
session.query(MyClass).options(
subqueryload("someattribute").subqueryload("anotherattribute")
)
Mapping imposes no restrictions or requirements on the constructor (__init__) method for the class. You are free
to require any arguments for the function that you wish, assign attributes to the instance that are unknown to the ORM,
and generally do anything else you would normally do when writing a constructor for a Python class.
The SQLAlchemy ORM does not call __init__ when recreating objects from database rows. The ORM’s process
is somewhat akin to the Python standard library’s pickle module, invoking the low level __new__ method and then
quietly restoring attributes directly on the instance rather than calling __init__.
If you need to do some setup on database-loaded instances before they’re ready to use, you can use the
@reconstructor decorator to tag a method as the ORM counterpart to __init__. SQLAlchemy will call this
method with no arguments every time it loads or reconstructs one of your instances. This is useful for recreating
transient properties that are normally assigned in your __init__:
from sqlalchemy import orm
class MyMappedClass(object):
def __init__(self, data):
self.data = data
# we need stuff on all instances, but not in the database.
self.stuff = []
@orm.reconstructor
def init_on_load(self):
self.stuff = []
When obj = MyMappedClass() is executed, Python calls the __init__ method as normal and the data argu-
ment is required. When instances are loaded during a Query operation as in query(MyMappedClass).one(),
init_on_load is called.
Any method may be tagged as the reconstructor(), even the __init__ method. SQLAlchemy will call the
reconstructor method with no arguments. Scalar (non-collection) database-mapped attributes of the instance will be
available for use within the function. Eagerly-loaded collections are generally not yet available and will usually only
contain the first element. ORM state changes made to objects at this stage will not be recorded for the next flush()
operation, so the activity within a reconstructor should be conservative.
reconstructor() is a shortcut into a larger system of “instance level” events, which can be subscribed to using
the event API - see InstanceEvents for the full API description of these events.
sqlalchemy.orm.reconstructor(fn)
Decorate a method as the ‘reconstructor’ hook.
Designates a method as the “reconstructor”, an __init__-like method that will be called by the ORM after
the instance has been loaded from the database or otherwise reconstituted.
The reconstructor will be invoked with no arguments. Scalar (non-collection) database-mapped attributes of the
instance will be available for use within the function. Eagerly-loaded collections are generally not yet available
and will usually only contain the first element. ORM state changes made to objects at this stage will not be
recorded for the next flush() operation, so the activity within a reconstructor should be conservative.
# this expression:
q.column_descriptions
# would return:
[
{
'name':'User',
'type':User,
'aliased':False,
'expr':User,
'entity': User
},
{
'name':'id',
'type':Integer(),
'aliased':False,
'expr':User.id,
'entity': User
},
{
'name':'user2',
'type':User,
'aliased':True,
'expr':user_alias,
'entity': user_alias
}
]
correlate(*args)
Return a Query construct which will correlate the given FROM clauses to that of an enclosing Query or
select().
The method here accepts mapped classes, aliased() constructs, and mapper() constructs as argu-
ments, which are resolved into expression constructs, in addition to appropriate expression constructs.
The correlation arguments are ultimately passed to Select.correlate() after coercion to expression
constructs.
The correlation arguments take effect in such cases as when Query.from_self() is used, or when a
subquery as returned by Query.subquery() is embedded in another select() construct.
count()
Return a count of rows this Query would return.
This generates the SQL for this Query as follows:
SELECT count(1) AS count_1 FROM (
SELECT <rest of query follows...>
) AS anon_1
group_by(User.name)
cte(name=None, recursive=False)
Return the full SELECT statement represented by this Query represented as a common table expression
(CTE).
New in version 0.7.6.
Parameters and usage are the same as those of the SelectBase.cte() method; see that method for
further details.
Here is the Postgresql WITH RECURSIVE example. Note that, in this example, the included_parts
cte and the incl_alias alias of it are Core selectables, which means the columns are accessed via
the .c. attribute. The parts_alias object is an orm.aliased() instance of the Part entity, so
column-mapped attributes are available directly:
from sqlalchemy.orm import aliased
class Part(Base):
__tablename__ = 'part'
part = Column(String, primary_key=True)
sub_part = Column(String, primary_key=True)
quantity = Column(Integer)
included_parts = session.query(
Part.sub_part,
Part.part,
Part.quantity).\
filter(Part.part=="our part").\
cte(name="included_parts", recursive=True)
q = session.query(
included_parts.c.sub_part,
func.sum(included_parts.c.quantity).
label('total_quantity')
).\
group_by(included_parts.c.sub_part)
See also:
SelectBase.cte()
delete(synchronize_session=’evaluate’)
Perform a bulk delete query.
sess.query(User).filter(User.age == 25).\
delete(synchronize_session='evaluate')
Warning: The Query.delete() method is a “bulk” operation, which bypasses ORM unit-of-work
automation in favor of greater performance. Please read all caveats and warnings below.
Parameters synchronize_session – chooses the strategy for the removal of matched ob-
jects from the session. Valid values are:
False - don’t synchronize the session. This option is the most efficient and is reliable
once the session is expired, which typically occurs after a commit(), or explicitly using ex-
pire_all(). Before the expiration, objects may still remain in the session which were in fact
deleted which can lead to confusing results if they are accessed via get() or already loaded
collections.
’fetch’ - performs a select query before the delete to find objects that are matched by the
delete query and need to be removed from the session. Matched objects are removed from
the session.
’evaluate’ - Evaluate the query’s criteria in Python straight on the objects in the session.
If evaluation of the criteria isn’t implemented, an error is raised.
The expression evaluator currently doesn’t account for differing string collations between the
database and Python.
Returns the count of rows matched as returned by the database’s “row count” feature.
See also:
Query.update()
Note: The distinct() call includes logic that will automatically add columns from the ORDER BY
of the query to the columns clause of the SELECT statement, to satisfy the common need of the database
backend that ORDER BY columns be part of the SELECT list when DISTINCT is used. These columns
are not added to the list of columns actually fetched by the Query, however, so would not affect results.
The columns are passed through when using the Query.statement accessor, however.
Parameters *expr – optional column expressions. When present, the Postgresql dialect will
render a DISTINCT ON (<expressions>>) construct.
enable_assertions(value)
Control whether assertions are generated.
When set to False, the returned Query will not assert its state before certain operations, including that
LIMIT/OFFSET has not been applied when filter() is called, no criterion exists when get() is called, and
no “from_statement()” exists when filter()/order_by()/group_by() etc. is called. This more permissive
mode is used by custom Query subclasses to specify criterion or other modifiers outside of the usual usage
patterns.
Care should be taken to ensure that the usage pattern is even possible. A statement applied by
from_statement() will override any criterion set by filter() or order_by(), for example.
enable_eagerloads(value)
Control whether or not eager joins and subqueries are rendered.
When set to False, the returned Query will not render eager joins regardless of joinedload(),
subqueryload() options or mapper-level lazy=’joined’/lazy=’subquery’ configurations.
This is used primarily when nesting the Query’s statement into a subquery or other selectable, or when
using Query.yield_per().
except_(*q)
Produce an EXCEPT of this Query against one or more queries.
Works the same way as union(). See that method for usage examples.
except_all(*q)
Produce an EXCEPT ALL of this Query against one or more queries.
Works the same way as union(). See that method for usage examples.
execution_options(**kwargs)
Set non-SQL options which take effect during execution.
The options are the same as those accepted by Connection.execution_options().
Note that the stream_results execution option is enabled automatically if the yield_per()
method is used.
exists()
A convenience method that turns a query into an EXISTS subquery of the form EXISTS (SELECT 1
FROM ... WHERE ...).
e.g.:
q = session.query(User).filter(User.name == 'fred')
session.query(q.exists())
Note that some databases such as SQL Server don’t allow an EXISTS expression to be present in the
columns clause of a SELECT. To select a simple boolean value based on the exists as a WHERE, use
literal():
from sqlalchemy import literal
session.query(literal(True)).filter(q.exists()).scalar()
Multiple criteria may be specified as comma separated; the effect is that they will be joined together using
the and_() function:
session.query(MyClass).\
filter(MyClass.name == 'some name', MyClass.id > 5)
The criterion is any SQL expression object applicable to the WHERE clause of a select. String expressions
are coerced into SQL expression constructs via the text() construct.
See also:
Query.filter_by() - filter on keyword expressions.
filter_by(**kwargs)
apply the given filtering criterion to a copy of this Query, using keyword expressions.
e.g.:
session.query(MyClass).filter_by(name = 'some name')
Multiple criteria may be specified as comma separated; the effect is that they will be joined together using
the and_() function:
session.query(MyClass).\
filter_by(name = 'some name', id = 5)
The keyword expressions are extracted from the primary entity of the query, or the last entity that was the
target of a call to Query.join().
See also:
Query.filter() - filter on SQL expressions.
first()
Return the first result of this Query or None if the result doesn’t contain any row.
first() applies a limit of one within the generated SQL, so that only one primary entity row is generated on
the server side (note this may consist of multiple result rows if join-loaded collections are present).
Calling Query.first() results in an execution of the underlying query.
from_self(*entities)
return a Query that selects from this Query’s SELECT statement.
Query.from_self() essentially turns the SELECT statement into a SELECT of itself. Given a query
such as:
q = session.query(User).filter(User.name.like('e%'))
There are lots of cases where Query.from_self() may be useful. A simple one is where above, we
may want to apply a row LIMIT to the set of user objects we query against, and then apply additional joins
against that row-limited set:
q = session.query(User).filter(User.name.like('e%')).\
limit(5).from_self().\
join(User.addresses).filter(Address.email.like('q%'))
The above query joins to the Address entity but only against the first five results of the User query:
SELECT anon_1.user_id AS anon_1_user_id,
anon_1.user_name AS anon_1_user_name
FROM (SELECT "user".id AS user_id, "user".name AS user_name
FROM "user"
WHERE "user".name LIKE :name_1
LIMIT :param_1) AS anon_1
JOIN address ON anon_1.user_id = address.user_id
WHERE address.email LIKE :email_1
Automatic Aliasing
Another key behavior of Query.from_self() is that it applies automatic aliasing to the entities
inside the subquery, when they are referenced on the outside. Above, if we continue to refer to the User
entity without any additional aliasing applied to it, those references wil be in terms of the subquery:
q = session.query(User).filter(User.name.like('e%')).\
limit(5).from_self().\
join(User.addresses).filter(Address.email.like('q%')).\
order_by(User.name)
The automatic aliasing feature only works in a limited way, for simple filters and orderings. More ambi-
tious constructions such as referring to the entity in joins should prefer to use explicit subquery objects,
typically making use of the Query.subquery() method to produce an explicit subquery object. Al-
ways test the structure of queries by viewing the SQL to ensure a particular structure does what’s expected!
Changing the Entities
Query.from_self() also includes the ability to modify what columns are being queried. In our
example, we want User.id to be queried by the inner query, so that we can join to the Address entity
on the outside, but we only wanted the outer query to return the Address.email column:
q = session.query(User).filter(User.name.like('e%')).\
limit(5).from_self(Address.email).\
join(User.addresses).filter(Address.email.like('q%'))
yielding:
SELECT address.email AS address_email
FROM (SELECT "user".id AS user_id, "user".name AS user_name
FROM "user"
WHERE "user".name LIKE :name_1
LIMIT :param_1) AS anon_1
JOIN address ON anon_1.user_id = address.user_id
WHERE address.email LIKE :email_1
q = q.add_entity(User).from_self().\
options(contains_eager(Address.user))
address.user_id AS address_user_id,
"user".id AS user_id,
"user".name AS user_name
FROM address JOIN "user" ON "user".id = address.user_id
WHERE "user".name LIKE :name_1) AS anon_1
If we didn’t call add_entity(User), but still asked contains_eager() to load the User entity,
it would be forced to add the table on the outside without the correct join criteria - note the anon1,
"user" phrase at the end:
-- incorrect query
SELECT anon_1.address_id AS anon_1_address_id,
anon_1.address_email AS anon_1_address_email,
anon_1.address_user_id AS anon_1_address_user_id,
"user".id AS user_id,
"user".name AS user_name
FROM (
SELECT address.id AS address_id,
address.email AS address_email,
address.user_id AS address_user_id
FROM address JOIN "user" ON "user".id = address.user_id
WHERE "user".name LIKE :name_1) AS anon_1, "user"
Parameters *entities – optional list of entities which will replace those being selected.
from_statement(statement)
Execute the given SELECT statement and return results.
This method bypasses all internal statement compilation, and the statement is executed without modifica-
tion.
The statement is typically either a text() or select() construct, and should return the set of columns
appropriate to the entity class represented by this Query.
See also:
Using Textual SQL - usage examples in the ORM tutorial
get(ident)
Return an instance based on the given primary key identifier, or None if not found.
E.g.:
my_user = session.query(User).get(5)
get() is special in that it provides direct access to the identity map of the owning Session. If the
given primary key identifier is present in the local identity map, the object is returned directly from this
collection and no SQL is emitted, unless the object has been marked fully expired. If not present, a
SELECT is performed in order to locate the object.
get() also will perform a check if the object is present in the identity map and marked as expired
- a SELECT is emitted to refresh the object as well as to ensure that the row is still present. If not,
ObjectDeletedError is raised.
get() is only used to return a single mapped instance, not multiple instances or individual column con-
structs, and strictly on a single primary key value. The originating Query must be constructed in this way,
i.e. against a single mapped entity, with no additional filtering criterion. Loading options via options()
may be applied however, and will be used if the object is not yet locally present.
instances(cursor, _Query__context=None)
Given a ResultProxy cursor as returned by connection.execute(), return an ORM result as an iterator.
e.g.:
result = engine.execute("select * from users")
for u in session.query(User).instances(result):
print u
intersect(*q)
Produce an INTERSECT of this Query against one or more queries.
Works the same way as union(). See that method for usage examples.
intersect_all(*q)
Produce an INTERSECT ALL of this Query against one or more queries.
Works the same way as union(). See that method for usage examples.
join(*props, **kwargs)
Create a SQL JOIN against this Query object’s criterion and apply generatively, returning the newly
resulting Query.
Simple Relationship Joins
Consider a mapping between two classes User and Address, with a relationship User.addresses
representing a collection of Address objects associated with each User. The most common usage of
join() is to create a JOIN along this relationship, using the User.addresses attribute as an indicator
for how this should occur:
q = session.query(User).join(User.addresses)
Where above, the call to join() along User.addresses will result in SQL equivalent to:
In the above example we refer to User.addresses as passed to join() as the on clause, that is,
it indicates how the “ON” portion of the JOIN should be constructed. For a single-entity query such as
the one above (i.e. we start by selecting only from User and nothing else), the relationship can also be
specified by its string name:
q = session.query(User).join("addresses")
join() can also accommodate multiple “on clause” arguments to produce a chain of joins, such as below
where a join across four related entities is constructed:
q = session.query(User).join("orders", "items", "keywords")
The above would be shorthand for three separate calls to join(), each using an explicit attribute to
indicate the source entity:
q = session.query(User).\
join(User.orders).\
join(Order.items).\
join(Item.keywords)
The above calling form of join() will raise an error if either there are no foreign keys between the two
entities, or if there are multiple foreign key linkages between them. In the above calling form, join()
is called upon to create the “on clause” automatically for us. The target can be any mapped entity or
selectable, such as a Table:
q = session.query(User).join(addresses_table)
q = session.query(User).\
join(User.addresses).\
join(a_alias, User.addresses).\
filter(Address.email_address=='[email protected]').\
filter(a_alias.email_address=='[email protected]')
The two-argument calling form of join() also allows us to construct arbitrary joins with SQL-oriented
“on clause” expressions, not relying upon configured relationships at all. Any SQL expression can be
passed as the ON clause when using the two-argument form, which should refer to the target entity in
some way as well as an applicable source entity:
q = session.query(User).join(Address, User.id==Address.user_id)
Changed in version 0.7: In SQLAlchemy 0.6 and earlier, the two argument form of join() requires
the usage of a tuple: query(User).join((Address, User.id==Address.user_id)). This
calling form is accepted in 0.7 and further, though is not necessary unless multiple join conditions are
passed to a single join() call, which itself is also not generally necessary as it is now equivalent to
multiple calls (this wasn’t always the case).
Advanced Join Targeting and Adaption
There is a lot of flexibility in what the “target” can be when using join(). As noted previously, it also
accepts Table constructs and other selectables such as alias() and select() constructs, with either
the one or two-argument forms:
addresses_q = select([Address.user_id]).\
where(Address.email_address.endswith("@bar.com")).\
alias()
q = session.query(User).\
join(addresses_q, addresses_q.c.user_id==User.id)
join() also features the ability to adapt a relationship() -driven ON clause to the target selectable.
Below we construct a JOIN from User to a subquery against Address, allowing the relationship denoted
by User.addresses to adapt itself to the altered target:
address_subq = session.query(Address).\
filter(Address.email_address == '[email protected]').\
subquery()
q = session.query(User).join(address_subq, User.addresses)
The above form allows one to fall back onto an explicit ON clause at any time:
q = session.query(User).\
join(address_subq, User.id==address_subq.c.user_id)
q = session.query(Address).select_from(User).\
join(User.addresses).\
filter(User.name == 'ed')
When aliased=True is used, the actual “alias” construct is not explicitly available. To work with it,
methods such as Query.filter() will adapt the incoming entity to the last join point:
q = session.query(Node).\
join("children", "children", aliased=True).\
filter(Node.name == 'grandchild 1')
When using automatic aliasing, the from_joinpoint=True argument can allow a multi-node join to
be broken into multiple calls to join(), so that each path along the way can be further filtered:
q = session.query(Node).\
join("children", aliased=True).\
filter(Node.name='child 1').\
join("children", aliased=True, from_joinpoint=True).\
filter(Node.name == 'grandchild 1')
The filtering aliases above can then be reset back to the original Node entity using
reset_joinpoint():
q = session.query(Node).\
join("children", "children", aliased=True).\
filter(Node.name == 'grandchild 1').\
reset_joinpoint().\
filter(Node.name == 'parent 1)
For an example of aliased=True, see the distribution example XML Persistence which illustrates an
XPath-like query system using algorithmic joins.
Parameters
• *props – A collection of one or more join conditions, each consisting of a relationship-
bound attribute or string relationship name representing an “on clause”, or a single target
entity, or a tuple in the form of (target, onclause). A special two-argument calling
form of the form target, onclause is also accepted.
• aliased=False – If True, indicate that the JOIN target should be anonymously aliased.
Subsequent calls to filter() and similar will adapt the incoming criterion to the target
alias, until reset_joinpoint() is called.
• isouter=False – If True, the join used will be a left outer join, just as if the
Query.outerjoin() method were called. This flag is here to maintain consistency
with the same flag as accepted by FromClause.join() and other Core constructs.
Would render:
q = session.query(User).\
select_entity_from(select_stmt).\
filter(User.name == 'ed')
The query generated will select User entities directly from the given select() construct, and will be:
SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name
FROM (SELECT "user".id AS id, "user".name AS name
FROM "user"
WHERE "user".id = :id_1) AS anon_1
WHERE anon_1.name = :name_1
Notice above that even the WHERE criterion was “adapted” such that the anon_1 subquery effectively
replaces all references to the user table, except for the one that it refers to internally.
Compare this to Query.select_from(), which as of version 0.9, does not affect existing entities.
The statement below:
q = session.query(User).\
select_from(select_stmt).\
filter(User.name == 'ed')
Produces SQL where both the user table as well as the select_stmt construct are present as separate
elements in the FROM clause. No “adaptation” of the user table is applied:
SELECT "user".id AS user_id, "user".name AS user_name
FROM "user", (SELECT "user".id AS id, "user".name AS name
FROM "user"
WHERE "user".id = :id_1) AS anon_1
WHERE "user".name = :name_1
q = session.query(user_from_select)
Parameters from_obj – a FromClause object that will replace the FROM clause of this
Query.
See also:
Query.select_from()
New in version 0.8: Query.select_entity_from() was added to specify the specific behavior of
entity replacement, however the Query.select_from() maintains this behavior as well until 0.9.
select_from(*from_obj)
Set the FROM clause of this Query explicitly.
Query.select_from() is often used in conjunction with Query.join() in order to control which
entity is selected from on the “left” side of the join.
The entity or selectable object here effectively replaces the “left edge” of any calls to join(), when no
joinpoint is otherwise established - usually, the default “join point” is the leftmost entity in the Query
object’s list of entities to be selected.
A typical example:
q = session.query(Address).select_from(User).\
join(User.addresses).\
filter(User.name == 'ed')
Parameters *from_obj – collection of one or more entities to apply to the FROM clause.
Entities can be mapped classes, AliasedClass objects, Mapper objects as well as core
FromClause elements like subqueries.
Changed in version 0.9: This method no longer applies the given FROM object to be the selectable from
which matching entities select from; the select_entity_from() method now accomplishes this.
See that method for a description of this behavior.
See also:
join()
Query.select_entity_from()
selectable
Return the Select object emitted by this Query.
Used for inspect() compatibility, this is equivalent to:
query.enable_eagerloads(False).with_labels().statement
slice(start, stop)
Computes the “slice” of the Query represented by the given indices and returns the resulting Query.
The start and stop indices behave like the argument to Python’s built-in range() function. This method
provides an alternative to using LIMIT/OFFSET to get a slice of the query.
For example,
session.query(User).order_by(User.id).slice(1, 3)
renders as
SELECT users.id AS users_id,
users.name AS users_name
FROM users ORDER BY users.id
LIMIT ? OFFSET ?
(2, 1)
See also:
Query.limit()
Query.offset()
statement
The full SELECT statement represented by this Query.
The statement by default will not have disambiguating labels applied to the construct unless
with_labels(True) is called first.
subquery(name=None, with_labels=False, reduce_columns=False)
return the full SELECT statement represented by this Query, embedded within an Alias.
Eager JOIN generation within the query is disabled.
Parameters
• name – string name to be assigned as the alias; this is passed through to
FromClause.alias(). If None, a name will be deterministically generated at com-
pile time.
• with_labels – if True, with_labels() will be called on the Query first to apply
table-qualified labels to all columns.
• reduce_columns – if True, Select.reduce_columns() will be called on the
resulting select() construct, to remove same-named columns where one also refers to
the other via foreign key or WHERE clause equivalence.
q3 = q1.union(q2)
The method accepts multiple Query objects so as to control the level of nesting. A series of union()
calls such as:
x.union(y).union(z).all()
Whereas:
x.union(y, z).all()
produces:
SELECT * FROM (SELECT * FROM X UNION SELECT * FROM y UNION
SELECT * FROM Z)
Note that many database backends do not allow ORDER BY to be rendered on a query called within
UNION, EXCEPT, etc. To disable all ORDER BY clauses including those configured on mappers, is-
sue query.order_by(None) - the resulting Query object will not render ORDER BY within its
SELECT statement.
union_all(*q)
Produce a UNION ALL of this Query against one or more queries.
Works the same way as union(). See that method for usage examples.
update(values, synchronize_session=’evaluate’, update_args=None)
Perform a bulk update query.
Updates rows matched by this query in the database.
E.g.:
sess.query(User).filter(User.age == 25).\
update({User.age: User.age - 10}, synchronize_session=False)
sess.query(User).filter(User.age == 25).\
update({"age": User.age - 10}, synchronize_session='evaluate')
Warning: The Query.update() method is a “bulk” operation, which bypasses ORM unit-of-work
automation in favor of greater performance. Please read all caveats and warnings below.
Parameters
• values – a dictionary with attributes names, or alternatively mapped attributes
or SQL expressions, as keys, and literal values or sql expressions as values. If
parameter-ordered mode is desired, the values can be passed as a list of 2-
tuples; this requires that the preserve_parameter_order flag is passed to the
Query.update.update_args dictionary as well.
Changed in version 1.0.0: - string names in the values dictionary are now resolved
against the mapped entity; previously, these strings were passed as literal column
names with no mapper-level translation.
• synchronize_session – chooses the strategy to update the attributes on objects in
the session. Valid values are:
False - don’t synchronize the session. This option is the most efficient and is reli-
able once the session is expired, which typically occurs after a commit(), or explicitly
using expire_all(). Before the expiration, updated objects may still remain in the
session with stale values on their attributes, which can lead to confusing results.
’fetch’ - performs a select query before the update to find objects that are matched
by the update query. The updated attributes are expired on matched objects.
’evaluate’ - Evaluate the Query’s criteria in Python straight on the objects in the
session. If evaluation of the criteria isn’t implemented, an exception is raised.
The expression evaluator currently doesn’t account for differing string collations be-
tween the database and Python.
• update_args – Optional dictionary, if present will be passed to the underlying
update() construct as the **kw for the object. May be used to pass dialect-
specific arguments such as mysql_limit, as well as other special arguments such as
preserve_parameter_order.
New in version 1.0.0.
Returns the count of rows matched as returned by the database’s “row count” feature.
session.query(Engineer).\
filter(Engineer.id == Employee.id).\
filter(Employee.name == 'dilbert').\
update({"engineer_type": "programmer"})
See also:
Query.delete()
Inserts, Updates and Deletes - Core SQL tutorial
value(column)
Return a scalar result corresponding to the given column expression.
values(*columns)
Return an iterator yielding result tuples corresponding to the given list of columns
whereclause
A readonly attribute which returns the current WHERE criterion for this Query.
This returned value is a SQL expression construct, or None if no criterion has been established.
with_entities(*entities)
Return a new Query replacing the SELECT list with the given entities.
e.g.:
# Users, filtered on some arbitrary criterion
# and then ordered by related email address
q = session.query(User).\
join(User.address).\
filter(User.name.like('%ed%')).\
order_by(Address.email)
Note: The Query.with_labels() method only applies the output of Query.statement, and not
to any of the result-row invoking systems of Query itself, e.g. Query.first(), Query.all(),
etc. To execute a query using Query.with_labels(), invoke the Query.statement using
Session.execute():
result = session.execute(query.with_labels().statement)
with_lockmode(mode)
Return a new Query object with the specified “locking mode”, which essentially refers to the FOR
UPDATE clause.
Deprecated since version 0.9.0: superseded by Query.with_for_update().
Parameters mode – a string representing the desired locking mode. Valid values are:
• None - translates to no lockmode
• ’update’ - translates to FOR UPDATE (standard SQL, supported by most dialects)
• ’update_nowait’ - translates to FOR UPDATE NOWAIT (supported by Oracle,
PostgreSQL 8.1 upwards)
• ’read’ - translates to LOCK IN SHARE MODE (for MySQL), and FOR SHARE (for
PostgreSQL)
See also:
Query.with_for_update() - improved API for specifying the FOR UPDATE clause.
with_parent(instance, property=None)
Add filtering criterion that relates the given instance to a child object or collection, using its attribute state
as well as an established relationship() configuration.
The method uses the with_parent() function to generate the clause, the result of which is passed to
Query.filter().
Parameters are the same as with_parent(), with the exception that the given property can be None, in
which case a search is performed against this Query object’s target mapper.
with_polymorphic(cls_or_mappers, selectable=None, polymorphic_on=None)
Load columns for inheriting classes.
Query.with_polymorphic() applies transformations to the “main” mapped class represented by
this Query. The “main” mapped class here means the Query object’s first argument is a full class, i.e.
session.query(SomeClass). These transformations allow additional tables to be present in the
FROM clause so that columns for a joined-inheritance subclass are available in the query, both for the
purposes of load-time efficiency as well as the ability to use these columns at query time.
See the documentation section Basic Control of Which Tables are Queried for details on how this method
is used.
Changed in version 0.8: A new and more flexible function orm.with_polymorphic() supersedes
Query.with_polymorphic(), as it can apply the equivalent functionality to any set of columns or
classes in the Query, not just the “zero mapper”. See that function for a description of arguments.
with_session(session)
Return a Query that will use the given Session.
with_statement_hint(text, dialect_name=’*’)
add a statement hint to this Select.
This method is similar to Select.with_hint() except that it does not require an individual table, and
instead applies to the statement as a whole.
This feature calls down into Select.with_statement_hint().
New in version 1.0.0.
See also:
Query.with_hint()
with_transformation(fn)
Return a new Query object transformed by the given function.
E.g.:
def filter_something(criterion):
def transform(q):
return q.filter(criterion)
return transform
q = q.with_transformation(filter_something(x==5))
This allows ad-hoc recipes to be created for Query objects. See the example at Building Transformers.
New in version 0.7.4.
yield_per(count)
Yield only count rows at a time.
The purpose of this method is when fetching very large result sets (> 10K rows), to batch results in sub-
collections and yield them out partially, so that the Python interpreter doesn’t need to declare very large
areas of memory which is both time consuming and leads to excessive memory use. The performance
from fetching hundreds of thousands of rows can often double when a suitable yield-per setting (e.g.
approximately 1000) is used, even with DBAPIs that buffer rows (which are most).
The Query.yield_per() method is not compatible with most eager loading schemes, including
subqueryload and joinedload with collections. For this reason, it may be helpful to disable eager loads,
either unconditionally with Query.enable_eagerloads():
q = sess.query(Object).yield_per(100).enable_eagerloads(False)
Or more selectively using lazyload(); such as with an asterisk to specify the default loader scheme:
q = sess.query(Object).yield_per(100).\
options(lazyload('*'), joinedload(Object.some_related))
Warning: Use this method with caution; if the same instance is present in more than one batch of
rows, end-user changes to attributes will be overwritten.
In particular, it’s usually impossible to use this setting with eagerly loaded collections (i.e. any
lazy=’joined’ or ‘subquery’) since those collections will be cleared for a new load when encountered
in a subsequent result batch. In the case of ‘subquery’ loading, the full result for all rows is fetched
which generally defeats the purpose of yield_per().
Also note that while yield_per() will set the stream_results execution option to True, cur-
rently this is only understood by psycopg2 dialect which will stream results using server side cursors
instead of pre-buffer all rows for this query. Other DBAPIs pre-buffer all rows before making them
available. The memory use of raw database rows is much less than that of an ORM-mapped object, but
should still be taken into consideration when benchmarking.
See also:
Query.enable_eagerloads()
my_alias = aliased(MyClass)
The aliased() function is used to create an ad-hoc mapping of a mapped class to a new selectable.
By default, a selectable is generated from the normally mapped selectable (typically a Table) using the
FromClause.alias() method. However, aliased() can also be used to link the class to a new
select() statement. Also, the with_polymorphic() function is a variant of aliased() that is
intended to specify a so-called “polymorphic selectable”, that corresponds to the union of several joined-
inheritance subclasses at once.
For convenience, the aliased() function also accepts plain FromClause constructs, such as a Table or
select() construct. In those cases, the FromClause.alias() method is called on the object and the new
Alias object returned. The returned Alias is not ORM-mapped in this case.
Parameters
• element – element to be aliased. Is normally a mapped class, but for convenience can also
be a FromClause element.
• alias – Optional selectable unit to map the element to. This should normally be a Alias
object corresponding to the Table to which the class is mapped, or to a select() con-
struct that is compatible with the mapping. By default, a simple anonymous alias of the
mapped table is generated.
• name – optional string name to use for the alias, if not specified by the alias parameter.
The name, among other things, forms the attribute name that will be accessible via tuples
returned by a Query object.
• flat – Boolean, will be passed through to the FromClause.alias() call so that
aliases of Join objects don’t include an enclosing SELECT. This can lead to more effi-
cient queries in many circumstances. A JOIN against a nested JOIN will be rewritten as a
JOIN against an aliased SELECT subquery on backends that don’t support this syntax.
New in version 0.9.0.
See also:
Join.alias()
• adapt_on_names – if True, more liberal “matching” will be used when mapping the
mapped columns of the ORM entity to those of the given selectable - a name-based match
will be performed if the given selectable doesn’t otherwise have a column that corresponds
to one on the entity. The use case for this is when associating an entity with some derived
selectable such as one that uses aggregate functions:
class UnitPrice(Base):
__tablename__ = 'unit_price'
...
unit_id = Column(Integer)
price = Column(Numeric)
aggregated_unit_price = Session.query(
func.sum(UnitPrice.price).label('price')
).group_by(UnitPrice.unit_id).subquery()
aggregated_unit_price = aliased(UnitPrice,
alias=aggregated_unit_price, adapt_on_names=True)
The resulting object is an instance of AliasedClass. This object implements an attribute scheme which
produces the same attribute and method interface as the original mapped class, allowing AliasedClass to
be compatible with any attribute technique which works on the original class, including hybrid attributes (see
Hybrid Attributes).
The AliasedClass can be inspected for its underlying Mapper, aliased selectable, and other information
using inspect():
from sqlalchemy import inspect
my_alias = aliased(MyClass)
insp = inspect(my_alias)
my_alias = aliased(MyMappedClass)
insp = inspect(my_alias)
•selectable - the Alias construct which ultimately represents an aliased Table or Select con-
struct.
•name - the name of the alias. Also is used as the attribute name when returned in a result tuple from
Query.
•with_polymorphic_mappers - collection of Mapper objects indicating all those mappers ex-
pressed in the select construct for the AliasedClass.
•polymorphic_on - an alternate column or SQL expression which will be used as the “discriminator”
for a polymorphic load.
See also:
Runtime Inspection API
class sqlalchemy.orm.query.Bundle(name, *exprs, **kw)
Bases: sqlalchemy.orm.base.InspectionAttr
A grouping of SQL expressions that are returned by a Query under one namespace.
The Bundle essentially allows nesting of the tuple-based results returned by a column-oriented Query object.
It also is extensible via simple subclassing, where the primary capability to override is that of how the set
of expressions should be returned, allowing post-processing as well as custom return types, without involving
ORM identity-mapped classes.
New in version 0.9.0.
See also:
Column Bundles
__init__(name, *exprs, **kw)
Construct a new Bundle.
e.g.:
bn = Bundle("mybundle", MyClass.x, MyClass.y)
Parameters
• name – name of the bundle.
• *exprs – columns or SQL expressions comprising the bundle.
• single_entity=False – if True, rows for this Bundle can be returned as a “single
entity” outside of any enclosing tuple in the same manner as a mapped entity.
c = None
An alias for Bundle.columns.
columns = None
A namespace of SQL expressions referred to by this Bundle.
e.g.:
q = sess.query(bn).filter(bn.c.x == 5)
b1 = Bundle("b1",
Bundle('b2', MyClass.a, MyClass.b),
Bundle('b3', MyClass.x, MyClass.y)
)
q = sess.query(b1).filter(
b1.c.b2.c.a == 5).filter(b1.c.b3.c.y == 9)
See also:
Bundle.c
create_row_processor(query, procs, labels)
Produce the “row processing” function for this Bundle.
May be overridden by subclasses.
See also:
Column Bundles - includes an example of subclassing.
label(name)
Provide a copy of this Bundle passing a new label.
single_entity = False
If True, queries for a single Bundle will be returned as a single entity, rather than an element within a
keyed tuple.
class sqlalchemy.util.KeyedTuple
Bases: sqlalchemy.util._collections.AbstractKeyedTuple
tuple subclass that adds labeled names.
E.g.:
>>> k = KeyedTuple([1, 2, 3], labels=["one", "two", "three"])
>>> k.one
1
>>> k.two
2
Result rows returned by Query that contain multiple ORM entities and/or column expressions make use of this
class to return rows.
The KeyedTuple exhibits similar behavior to the collections.namedtuple() construct provided in
the Python standard library, however is architected very differently. Unlike collections.namedtuple(),
KeyedTuple is does not rely on creation of custom subtypes in order to represent a new series of
keys, instead each KeyedTuple instance receives its list of keys in place. The subtype approach of
collections.namedtuple() introduces significant complexity and performance overhead, which is not
necessary for the Query object’s use case.
Changed in version 0.8: Compatibility methods with collections.namedtuple() have been added in-
cluding KeyedTuple._fields and KeyedTuple._asdict().
See also:
Querying
_asdict()
Return the contents of this KeyedTuple as a dictionary.
This method provides compatibility with collections.namedtuple(), with the exception that the
dictionary returned is not ordered.
New in version 0.8.
_fields
Return a tuple of string key names for this KeyedTuple.
This method provides compatibility with collections.namedtuple().
New in version 0.8.
See also:
KeyedTuple.keys()
keys()
inherited from the keys() method of AbstractKeyedTuple
Return a list of string key names for this KeyedTuple.
See also:
KeyedTuple._fields
class sqlalchemy.orm.strategy_options.Load(entity)
Bases: sqlalchemy.sql.expression.Generative, sqlalchemy.orm.interfaces.MapperOption
Represents loader options which modify the state of a Query in order to affect how various mapped attributes
are loaded.
New in version 0.9.0: The Load() system is a new foundation for the existing system of loader options,
including options such as orm.joinedload(), orm.defer(), and others. In particular, it introduces a
new method-chained system that replaces the need for dot-separated paths as well as “_all()” options such as
orm.joinedload_all().
A Load object can be used directly or indirectly. To use one directly, instantiate given the parent class. This
style of usage is useful when dealing with a Query that has multiple entities, or when producing a loader option
that can be applied generically to any style of query:
myopt = Load(MyClass).joinedload("widgets")
The Load construct is invoked indirectly whenever one makes use of the various loader options that
are present in sqlalchemy.orm, including options such as orm.joinedload(), orm.defer(),
orm.subqueryload(), and all the rest. These constructs produce an “anonymous” form of the Load
object which tracks attributes and options, but is not linked to a parent class until it is associated with a parent
Query:
# produce "unbound" Load object
myopt = joinedload("widgets")
Whether the direct or indirect style is used, the Load object returned now represents a specific “path” along
the entities of a Query. This path can be traversed using a standard method-chaining approach. Suppos-
ing a class hierarchy such as User, User.addresses -> Address, User.orders -> Order and
Order.items -> Item, we can specify a variety of loader options along each element in the “path”:
session.query(User).options(
joinedload("addresses"),
subqueryload("orders").joinedload("items")
)
Where above, the addresses collection will be joined-loaded, the orders collection will be subquery-
loaded, and within that subquery load the items collection will be joined-loaded.
baked_lazyload(loadopt, attr)
Produce a new Load object with the orm.baked_lazyload() option applied.
See orm.baked_lazyload() for usage examples.
contains_eager(loadopt, attr, alias=None)
Produce a new Load object with the orm.contains_eager() option applied.
See orm.contains_eager() for usage examples.
defaultload(loadopt, attr)
Produce a new Load object with the orm.defaultload() option applied.
See orm.defaultload() for usage examples.
defer(loadopt, key)
Produce a new Load object with the orm.defer() option applied.
See orm.defer() for usage examples.
immediateload(loadopt, attr)
Produce a new Load object with the orm.immediateload() option applied.
See orm.immediateload() for usage examples.
joinedload(loadopt, attr, innerjoin=None)
Produce a new Load object with the orm.joinedload() option applied.
See orm.joinedload() for usage examples.
lazyload(loadopt, attr)
Produce a new Load object with the orm.lazyload() option applied.
See orm.lazyload() for usage examples.
load_only(loadopt, *attrs)
Produce a new Load object with the orm.load_only() option applied.
See orm.load_only() for usage examples.
noload(loadopt, attr)
Produce a new Load object with the orm.noload() option applied.
See orm.noload() for usage examples.
subqueryload(loadopt, attr)
Produce a new Load object with the orm.subqueryload() option applied.
See orm.subqueryload() for usage examples.
undefer(loadopt, key)
Produce a new Load object with the orm.undefer() option applied.
See orm.undefer() for usage examples.
undefer_group(loadopt, name)
Produce a new Load object with the orm.undefer_group() option applied.
In modern SQLAlchemy the above join can be written more succinctly as:
session.query(User).\
join(User.addresses).\
filter(Address.email_address=='[email protected]')
The orm.mapper() function and declarative extensions are the primary configurational interface for the ORM.
Once mappings are configured, the primary usage interface for persistence operations is the Session.
In the most general sense, the Session establishes all conversations with the database and represents a “holding
zone” for all the objects which you’ve loaded or associated with it during its lifespan. It provides the entrypoint to
acquire a Query object, which sends queries to the database using the Session object’s current database connection,
populating result rows into objects that are then stored in the Session, inside a structure called the Identity Map - a
data structure that maintains unique copies of each object, where “unique” means “only one object with a particular
primary key”.
The Session begins in an essentially stateless form. Once queries are issued or other objects are persisted with it, it
requests a connection resource from an Engine that is associated either with the Session itself or with the mapped
Table objects being operated upon. This connection represents an ongoing transaction, which remains in effect until
the Session is instructed to commit or roll back its pending state.
All changes to objects maintained by a Session are tracked - before the database is queried again or before the
current transaction is committed, it flushes all pending changes to the database. This is known as the Unit of Work
pattern.
When using a Session, it’s important to note that the objects which are associated with it are proxy objects to the
transaction being held by the Session - there are a variety of events that will cause objects to re-access the database
in order to keep synchronized. It is possible to “detach” objects from a Session, and to continue using them, though
this practice has its caveats. It’s intended that usually, you’d re-associate detached objects with another Session
when you want to work with them again, so that they can resume their normal task of representing database state.
Getting a Session
Session is a regular Python class which can be directly instantiated. However, to standardize how sessions are
configured and acquired, the sessionmaker class is normally used to create a top level Session configuration
which can then be used throughout an application without the need to repeat the configurational arguments.
The usage of sessionmaker is illustrated below:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# create a Session
session = Session()
Above, the sessionmaker call creates a factory for us, which we assign to the name Session. This factory, when
called, will create a new Session object using the configurational arguments we’ve given the factory. In this case,
as is typical, we’ve configured the factory to specify a particular Engine for connection resources.
A typical setup will associate the sessionmaker with an Engine, so that each Session generated will use this
Engine to acquire connection resources. This association can be set up as in the example above, using the bind
argument.
When you write your application, place the sessionmaker factory at the global level. This factory can then be used
by the rest of the applcation as the source of new Session instances, keeping the configuration for how Session
objects are constructed in one place.
The sessionmaker factory can also be used in conjunction with other helpers, which are passed a user-defined
sessionmaker that is then maintained by the helper. Some of these helpers are discussed in the section When do I
construct a Session, when do I commit it, and when do I close it?.
A common scenario is where the sessionmaker is invoked at module import time, however the generation of one
or more Engine instances to be associated with the sessionmaker has not yet proceeded. For this use case,
the sessionmaker construct offers the sessionmaker.configure() method, which will place additional
configuration directives into an existing sessionmaker that will take place when the construct is invoked:
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
For the use case where an application needs to create a new Session with special arguments that deviate from
what is normally used throughout the application, such as a Session that binds to an alternate source of con-
nectivity, or a Session that should have other arguments such as expire_on_commit established differently
from what most of the application wants, specific arguments can be passed to the sessionmaker factory’s
sessionmaker.__call__() method. These arguments will override whatever configurations have already been
placed, such as below, where a new Session is constructed against a specific Connection:
# at the module level, the global sessionmaker,
# bound to a specific Engine
Session = sessionmaker(bind=engine)
The typical rationale for the association of a Session with a specific Connection is that of a test fixture that
maintains an external transaction - see Joining a Session into an External Transaction (such as for test suites) for an
example of this.
By this point, many users already have questions about sessions. This section presents a mini-FAQ (note that we have
also a real FAQ) of the most basic issues one is presented with when using a Session.
Just one time, somewhere in your application’s global scope. It should be looked upon as part of your application’s
configuration. If your application has three .py files in a package, you could, for example, place the sessionmaker
line in your __init__.py file; from that point on your other modules say “from mypackage import Session”. That
way, everyone else just uses Session(), and the configuration of that session is controlled by that central point.
If your application starts up, does imports, but does not know what database it’s going to be connecting to, you can
bind the Session at the “class” level to the engine later on, using sessionmaker.configure().
In the examples in this section, we will frequently show the sessionmaker being created right above the line
where we actually invoke Session. But that’s just for example’s sake! In reality, the sessionmaker would be
somewhere at the module level. The calls to instantiate Session would then be placed at the point in the application
where database conversations begin.
When do I construct a Session, when do I commit it, and when do I close it?
tl;dr;
1. As a general rule, keep the lifecycle of the session separate and external from functions and objects that
access and/or manipulate database data. This will greatly help with achieving a predictable and consistent
transactional scope.
2. Make sure you have a clear notion of where transactions begin and end, and keep transactions short,
meaning, they end at the series of a sequence of operations, instead of being held open indefinitely.
A Session is typically constructed at the beginning of a logical operation where database access is potentially
anticipated.
The Session, whenever it is used to talk to the database, begins a database transaction as soon as it starts commu-
nicating. Assuming the autocommit flag is left at its recommended default of False, this transaction remains in
progress until the Session is rolled back, committed, or closed. The Session will begin a new transaction if it is
used again, subsequent to the previous transaction ending; from this it follows that the Session is capable of having
a lifespan across many transactions, though only one at a time. We refer to these two concepts as transaction scope
and session scope.
The implication here is that the SQLAlchemy ORM is encouraging the developer to establish these two scopes in
their application, including not only when the scopes begin and end, but also the expanse of those scopes, for example
should a single Session instance be local to the execution flow within a function or method, should it be a global
object used by the entire application, or somewhere in between these two.
The burden placed on the developer to determine this scope is one area where the SQLAlchemy ORM necessarily has
a strong opinion about how the database should be used. The unit of work pattern is specifically one of accumulating
changes over time and flushing them periodically, keeping in-memory state in sync with what’s known to be present
in a local transaction. This pattern is only effective when meaningful transaction scopes are in place.
It’s usually not very hard to determine the best points at which to begin and end the scope of a Session, though the
wide variety of application architectures possible can introduce challenging situations.
A common choice is to tear down the Session at the same time the transaction ends, meaning the transaction and
session scopes are the same. This is a great choice to start out with as it removes the need to consider session scope as
separate from transaction scope.
While there’s no one-size-fits-all recommendation for how transaction scope should be determined, there are common
patterns. Especially if one is writing a web application, the choice is pretty much established.
A web application is the easiest case because such an application is already constructed around a single, consistent
scope - this is the request, which represents an incoming request from a browser, the processing of that request to
formulate a response, and finally the delivery of that response back to the client. Integrating web applications with
the Session is then the straightforward task of linking the scope of the Session to that of the request. The
Session can be established as the request begins, or using a lazy initialization pattern which establishes one as
soon as it is needed. The request then proceeds, with some system in place where application logic can access the
current Session in a manner associated with how the actual request object is accessed. As the request ends, the
Session is torn down as well, usually through the usage of event hooks provided by the web framework. The
transaction used by the Session may also be committed at this point, or alternatively the application may opt for an
explicit commit pattern, only committing for those requests where one is warranted, but still always tearing down the
Session unconditionally at the end.
Some web frameworks include infrastructure to assist in the task of aligning the lifespan of a Session with that
of a web request. This includes products such as Flask-SQLAlchemy, for usage in conjunction with the Flask web
framework, and Zope-SQLAlchemy, typically used with the Pyramid framework. SQLAlchemy recommends that
these products be used as available.
In those situations where the integration libraries are not provided or are insufficient, SQLAlchemy includes its own
“helper” class known as scoped_session. A tutorial on the usage of this object is at Contextual/Thread-local
Sessions. It provides both a quick way to associate a Session with the current thread, as well as patterns to associate
Session objects with other kinds of scopes.
As mentioned before, for non-web applications there is no one clear pattern, as applications themselves don’t have
just one pattern of architecture. The best strategy is to attempt to demarcate “operations”, points at which a particular
thread begins to perform a series of operations for some period of time, which can be committed at the end. Some
examples:
• A background daemon which spawns off child forks would want to create a Session local to each child
process, work with that Session through the life of the “job” that the fork is handling, then tear it down when
the job is completed.
• For a command-line script, the application would create a single, global Session that is established when the
program begins to do its work, and commits it right as the program is completing its task.
• For a GUI interface-driven application, the scope of the Session may best be within the scope of a user-
generated event, such as a button push. Or, the scope may correspond to explicit user interaction, such as the
user “opening” a series of records, then “saving” them.
As a general rule, the application should manage the lifecycle of the session externally to functions that deal with
specific data. This is a fundamental separation of concerns which keeps data-specific operations agnostic of the
context in which they access and manipulate that data.
E.g. don’t do this:
### this is the **wrong way to do it** ###
class ThingOne(object):
def go(self):
session = Session()
try:
session.query(FooBar).update({"x": 5})
session.commit()
except:
session.rollback()
raise
class ThingTwo(object):
def go(self):
session = Session()
try:
session.query(Widget).update({"q": 18})
session.commit()
except:
session.rollback()
raise
def run_my_program():
ThingOne().go()
ThingTwo().go()
Keep the lifecycle of the session (and usually the transaction) separate and external:
### this is a **better** (but not the only) way to do it ###
class ThingOne(object):
def go(self, session):
session.query(FooBar).update({"x": 5})
class ThingTwo(object):
def go(self, session):
session.query(Widget).update({"q": 18})
def run_my_program():
session = Session()
try:
ThingOne().go(session)
ThingTwo().go(session)
session.commit()
except:
session.rollback()
raise
finally:
session.close()
The advanced developer will try to keep the details of session, transaction and exception management as far as possible
from the details of the program doing its work. For example, we can further separate concerns using a context manager:
### another way (but again *not the only way*) to do it ###
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
def run_my_program():
with session_scope() as session:
ThingOne().go(session)
ThingTwo().go(session)
Yeee...no. It’s somewhat used as a cache, in that it implements the identity map pattern, and stores objects
keyed to their primary key. However, it doesn’t do any kind of query caching. This means, if you say
session.query(Foo).filter_by(name=’bar’), even if Foo(name=’bar’) is right there, in the iden-
tity map, the session has no idea about that. It has to issue SQL to the database, get the rows back, and then when it
sees the primary key in the row, then it can look in the local identity map and see that the object is already there. It’s
only when you say query.get({some primary key}) that the Session doesn’t have to issue a query.
Additionally, the Session stores object instances using a weak reference by default. This also defeats the purpose of
using the Session as a cache.
The Session is not designed to be a global object from which everyone consults as a “registry” of objects. That’s
more the job of a second level cache. SQLAlchemy provides a pattern for implementing second level caching using
dogpile.cache, via the Dogpile Caching example.
The Session is very much intended to be used in a non-concurrent fashion, which usually means in only one thread
at a time.
The Session should be used in such a way that one instance exists for a single series of operations within a sin-
gle transaction. One expedient way to get this effect is by associating a Session with the current thread (see
Contextual/Thread-local Sessions for background). Another is to use a pattern where the Session is passed between
functions and is otherwise not shared with other threads.
The bigger point is that you should not want to use the session with multiple concurrent threads. That would be like
having everyone at a restaurant all eat from the same plate. The session is a local “workspace” that you use for a
specific set of tasks; you don’t want to, or need to, share that session with other threads who are doing some other task.
Making sure the Session is only used in a single concurrent thread at a time is called a “share nothing” approach
to concurrency. But actually, not sharing the Session implies a more significant pattern; it means not just the
Session object itself, but also all objects that are associated with that Session, must be kept within the scope
of a single concurrent thread. The set of mapped objects associated with a Session are essentially proxies for
data within database rows accessed over a database connection, and so just like the Session itself, the whole set
of objects is really just a large-scale proxy for a database connection (or connections). Ultimately, it’s mostly the
DBAPI connection itself that we’re keeping away from concurrent access; but since the Session and all the objects
associated with it are all proxies for that DBAPI connection, the entire graph is essentially not safe for concurrent
access.
If there are in fact multiple threads participating in the same task, then you may consider sharing the session and its
objects between those threads; however, in this extremely unusual scenario the application would need to ensure that
a proper locking scheme is implemented so that there isn’t concurrent access to the Session or its state. A more
common approach to this situation is to maintain a single Session per concurrent thread, but to instead copy objects
from one Session to another, often using the Session.merge() method to copy the state of an object into a new
object local to a different Session.
Querying
The query() function takes one or more entities and returns a new Query object which will issue mapper queries
within the context of this Session. An entity is defined as a mapped class, a Mapper object, an orm-enabled descriptor,
or an AliasedClass object:
# query from a class
session.query(User).filter_by(name='ed').all()
When Query returns results, each object instantiated is stored within the identity map. When a row matches an
object which is already present, the same object is returned. In the latter case, whether or not the row is populated
onto an existing object depends upon whether the attributes of the instance have been expired or not. A default-
configured Session automatically expires all instances along transaction boundaries, so that with a normally isolated
transaction, there shouldn’t be any issue of instances representing data which is stale with regards to the current
transaction.
The Query object is introduced in great detail in Object Relational Tutorial, and further documented in
query_api_toplevel.
add() is used to place instances in the session. For transient (i.e. brand new) instances, this will have the effect of
an INSERT taking place for those instances upon the next flush. For instances which are persistent (i.e. were loaded
by this session), they are already present and do not need to be added. Instances which are detached (i.e. have been
removed from a session) may be re-associated with a session using this method:
user1 = User(name='user1')
user2 = User(name='user2')
session.add(user1)
session.add(user2)
The add() operation cascades along the save-update cascade. For more details see the section Cascades.
Deleting
The delete() method places an instance into the Session’s list of objects to be marked as deleted:
# mark two objects to be deleted
session.delete(obj1)
session.delete(obj2)
Deleting from Collections A common confusion that arises regarding delete() is when objects which are mem-
bers of a collection are being deleted. While the collection member is marked for deletion from the database, this
does not impact the collection itself in memory until the collection is expired. Below, we illustrate that even after an
Address object is marked for deletion, it’s still present in the collection associated with the parent User, even after
a flush:
>>> address = user.addresses[1]
>>> session.delete(address)
>>> session.flush()
>>> address in user.addresses
True
When the above session is committed, all attributes are expired. The next access of user.addresses will re-load
the collection, revealing the desired state:
>>> session.commit()
>>> address in user.addresses
False
The usual practice of deleting items within collections is to forego the usage of delete() directly, and instead use
cascade behavior to automatically invoke the deletion as a result of removing the object from the parent collection.
The delete-orphan cascade accomplishes this, as illustrated in the example below:
mapper(User, users_table, properties={
'addresses':relationship(Address, cascade="all, delete, delete-orphan")
})
del user.addresses[1]
session.flush()
Where above, upon removing the Address object from the User.addresses collection, the delete-orphan
cascade has the effect of marking the Address object for deletion in the same way as passing it to delete().
See also Cascades for detail on cascades.
Deleting based on Filter Criterion The caveat with Session.delete() is that you need to have an object
handy already in order to delete. The Query includes a delete() method which deletes based on filtering criteria:
session.query(User).filter(User.id==7).delete()
The Query.delete() method includes functionality to “expire” objects already in the session which match the
criteria. However it does have some caveats, including that “delete” and “delete-orphan” cascades won’t be fully
expressed for collections which are already loaded. See the API docs for delete() for more details.
Flushing
When the Session is used with its default configuration, the flush step is nearly always done transparently. Specif-
ically, the flush occurs before any individual Query is issued, as well as within the commit() call before the
transaction is committed. It also occurs before a SAVEPOINT is issued when begin_nested() is used.
Regardless of the autoflush setting, a flush can always be forced by issuing flush():
session.flush()
The “flush-on-Query” aspect of the behavior can be disabled by constructing sessionmaker with the flag
autoflush=False:
Session = sessionmaker(autoflush=False)
Additionally, autoflush can be temporarily disabled by setting the autoflush flag at any time:
mysession = Session()
mysession.autoflush = False
Committing
commit() is used to commit the current transaction. It always issues flush() beforehand to flush any remaining
state to the database; this is independent of the “autoflush” setting. If no transaction is present, it raises an error. Note
that the default behavior of the Session is that a “transaction” is always present; this behavior can be disabled by
setting autocommit=True. In autocommit mode, a transaction can be initiated by calling the begin() method.
Note: The term “transaction” here refers to a transactional construct within the Session itself which may be main-
taining zero or more actual database (DBAPI) transactions. An individual DBAPI connection begins participation in
the “transaction” as it is first used to execute a SQL statement, then remains present until the session-level “transaction”
is completed. See Managing Transactions for further detail.
Another behavior of commit() is that by default it expires the state of all instances present after the commit is
complete. This is so that when the instances are next accessed, either through attribute access or by them being present
in a Query result set, they receive the most recent state. To disable this behavior, configure sessionmaker with
expire_on_commit=False.
Normally, instances loaded into the Session are never changed by subsequent queries; the assumption is that the
current transaction is isolated so the state most recently loaded is correct as long as the transaction continues. Setting
autocommit=True works against this model to some degree since the Session behaves in exactly the same way
with regard to attribute state, except no transaction is present.
Rolling Back
rollback() rolls back the current transaction. With a default configured session, the post-rollback state of the
session is as follows:
• All transactions are rolled back and all connections returned to the connection pool, unless the Session was
bound directly to a Connection, in which case the connection is still maintained (but still rolled back).
• Objects which were initially in the pending state when they were added to the Session within the lifespan
of the transaction are expunged, corresponding to their INSERT statement being rolled back. The state of their
attributes remains unchanged.
• Objects which were marked as deleted within the lifespan of the transaction are promoted back to the persistent
state, corresponding to their DELETE statement being rolled back. Note that if those objects were first pending
within the transaction, that operation takes precedence instead.
• All objects not expunged are fully expired.
With that state understood, the Session may safely continue usage after a rollback occurs.
When a flush() fails, typically for reasons like primary key, foreign key, or “not nullable” constraint violations,
a rollback() is issued automatically (it’s currently not possible for a flush to continue after a partial failure).
However, the flush process always uses its own transactional demarcator called a subtransaction, which is described
more fully in the docstrings for Session. What it means here is that even though the database transaction has been
rolled back, the end user must still issue rollback() to fully reset the state of the Session.
Closing
The close() method issues a expunge_all(), and releases any transactional/connection resources. When con-
nections are returned to the connection pool, transactional state is rolled back as well.
It’s helpful to know the states which an instance can have within a session:
• Transient - an instance that’s not in a session, and is not saved to the database; i.e. it has no database identity.
The only relationship such an object has to the ORM is that its class has a mapper() associated with it.
• Pending - when you add() a transient instance, it becomes pending. It still wasn’t actually flushed to the
database yet, but it will be when the next flush occurs.
• Persistent - An instance which is present in the session and has a record in the database. You get persistent
instances by either flushing so that the pending instances become persistent, or by querying the database for
existing instances (or moving persistent instances from other sessions into your local session).
Note: An object that is marked as deleted, e.g. via the Session.delete() method, is still considered
persistent. The object remains in the identity map until the flush proceeds and a DELETE state is emitted, at
which point the object moves to the state that is for most practical purposes “detached” - after the session’s
transaction is committed, the object becomes fully detached. SQLAlchemy 1.1 will introduce a new object state
called “deleted” which represents this “deleted but not quite detached” state explicitly.
• Detached - an instance which corresponds, or previously corresponded, to a record in the database, but is not
currently in any session. The detached object will contain a database identity marker, however because it is
not associated with a session, it is unknown whether or not this database identity actually exists in a target
database. Detached objects are safe to use normally, except that they have no ability to load unloaded attributes
or attributes that were previously marked as “expired”.
Knowing these states is important, since the Session tries to be strict about ambiguous operations (such as trying to
save the same object to two different sessions at the same time).
The actual state of any mapped object can be viewed at any time using the inspect() system:
>>> from sqlalchemy import inspect
>>> insp = inspect(my_object)
>>> insp.persistent
True
See also:
InstanceState.transient
InstanceState.pending
InstanceState.persistent
InstanceState.detached
Session Attributes
The Session itself acts somewhat like a set-like collection. All items present may be accessed using the iterator
interface:
for obj in session:
print obj
The session is also keeping track of all newly created (i.e. pending) objects, all objects which have had changes since
they were last loaded or saved (i.e. “dirty”), and everything that’s been marked as deleted:
# pending objects recently added to the Session
session.new
# identity key
session.identity_map
Note: To disable the weak referencing behavior and force all objects within the session to remain until explicitly
expunged, configure sessionmaker with the weak_identity_map=False setting. However note that this
option is deprecated; it is present only to allow compatibility with older applications, typically those that were made
back before SQLAlchemy had the ability to effectively weak-reference all objects. It is recommended that strong
references to objects be maintained by the calling application externally to the Session itself, to the extent that is
required by the application. This eliminates the Session as a possible source of unbounded memory growth in the
case where large numbers of objects are being loaded and/or persisted.
Simple examples of externally managed strong-referencing behavior include loading objects into a local dictionary
keyed to their primary key, or into lists or sets for the span of time that they need to remain referenced. These
collections can be associated with a Session, if desired, by placing them into the Session.info dictionary.
Events such as the SessionEvents.after_attach() and MapperEvents.load() event may also be of
use for intercepting objects as they are associated with a Session.
Merging
merge() transfers state from an outside object into a new or already existing instance within a session. It also
reconciles the incoming data against the state of the database, producing a history stream which will be applied
towards the next flush, or alternatively can be made to produce a simple “transfer” of state without producing change
history or accessing the database. Usage is as follows:
merged_object = session.merge(existing_object)
With merge(), the given “source” instance is not modified nor is it associated with the target Session, and remains
available to be merged with any number of other Session objects. merge() is useful for taking the state of any
kind of object structure without regard for its origins or current session associations and copying its state into a new
session. Here’s some examples:
• An application which reads an object structure from a file and wishes to save it to the database might parse the
file, build up the structure, and then use merge() to save it to the database, ensuring that the data within the
file is used to formulate the primary key of each element of the structure. Later, when the file has changed, the
same process can be re-run, producing a slightly different object structure, which can then be merged in again,
and the Session will automatically update the database to reflect those changes, loading each object from the
database by primary key and then updating its state with the new state given.
• An application is storing objects in an in-memory cache, shared by many Session objects simultaneously.
merge() is used each time an object is retrieved from the cache to create a local copy of it in each Session
which requests it. The cached object remains detached; only its state is moved into copies of itself that are local
to individual Session objects.
In the caching use case, it’s common to use the load=False flag to remove the overhead of reconciling the
object’s state with the database. There’s also a “bulk” version of merge() called merge_result() that was
designed to work with cache-extended Query objects - see the section Dogpile Caching.
• An application wants to transfer the state of a series of objects into a Session maintained by a worker thread
or other concurrent system. merge() makes a copy of each object to be placed into this new Session. At
the end of the operation, the parent thread/process maintains the objects it started with, and the thread/worker
can proceed with local copies of those objects.
In the “transfer between threads/processes” use case, the application may want to use the load=False flag as
well to avoid overhead and redundant SQL queries as the data is transferred.
Merge Tips
merge() is an extremely useful method for many purposes. However, it deals with the intricate border between
objects that are transient/detached and those that are persistent, as well as the automated transference of state. The
wide variety of scenarios that can present themselves here often require a more careful approach to the state of objects.
Common problems with merge usually involve some unexpected state regarding the object being passed to merge().
Lets use the canonical example of the User and Address objects:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
addresses = relationship("Address", backref="user")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email_address = Column(String(50), nullable=False)
user_id = Column(Integer, ForeignKey('user.id'), nullable=False)
We now create a1, an object outside the session, which we’d like to merge on top of the existing Address:
>>> existing_a1 = u1.addresses[0]
>>> a1 = Address(id=existing_a1.id)
Why is that ? We weren’t careful with our cascades. The assignment of a1.user to a persistent object cascaded to
the backref of User.addresses and made our a1 object pending, as though we had added it. Now we have two
Address objects in the session:
>>> a1 = Address()
>>> a1.user = u1
>>> a1 in session
True
>>> existing_a1 in session
True
>>> a1 is existing_a1
False
Above, our a1 is already pending in the session. The subsequent merge() operation essentially does nothing.
Cascade can be configured via the cascade option on relationship(), although in this case it would mean
removing the save-update cascade from the User.addresses relationship - and usually, that behavior is ex-
tremely convenient. The solution here would usually be to not assign a1.user to an object already persistent in the
target session.
The cascade_backrefs=False option of relationship() will also prevent the Address from being added
to the session via the a1.user = u1 assignment.
Further detail on cascade operation is at Cascades.
Another example of unexpected state:
>>> a1 = Address(id=existing_a1.id, user_id=u1.id)
>>> assert a1.user is None
>>> True
>>> a1 = session.merge(a1)
>>> session.commit()
sqlalchemy.exc.IntegrityError: (IntegrityError) address.user_id
may not be NULL
Here, we accessed a1.user, which returned its default value of None, which as a result of this access, has been placed
in the __dict__ of our object a1. Normally, this operation creates no change event, so the user_id attribute takes
precedence during a flush. But when we merge the Address object into the session, the operation is equivalent to:
>>> existing_a1.id = existing_a1.id
>>> existing_a1.user_id = u1.id
>>> existing_a1.user = None
Where above, both user_id and user are assigned to, and change events are emitted for both. The user association
takes precedence, and None is applied to user_id, causing a failure.
Most merge() issues can be examined by first checking - is the object prematurely in the session ?
Or is there state on the object that we don’t want ? Examining __dict__ is a quick way to check:
>>> a1 = Address(id=existing_a1, user_id=user.id)
>>> a1.user
>>> a1.__dict__
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x1298d10>,
'user_id': 1,
'id': 1,
'user': None}
>>> # we don't want user=None merged, remove it
>>> del a1.user
>>> a1 = session.merge(a1)
>>> # success
>>> session.commit()
Expunging
Expunge removes an object from the Session, sending persistent instances to the detached state, and pending instances
to the transient state:
session.expunge(obj1)
To remove all items, call expunge_all() (this method was formerly known as clear()).
Refreshing / Expiring
Expiring means that the database-persisted data held inside a series of object attributes is erased, in such a way that
when those attributes are next accessed, a SQL query is emitted which will refresh that data from the database.
When we talk about expiration of data we are usually talking about an object that is in the persistent state. For example,
if we load an object as follows:
user = session.query(User).filter_by(name='user1').first()
The above User object is persistent, and has a series of attributes present; if we were to look inside its __dict__,
we’d see that state loaded:
>>> user.__dict__
{
'id': 1, 'name': u'user1',
'_sa_instance_state': <...>,
}
where id and name refer to those columns in the database. _sa_instance_state is a non-database-persisted
value used by SQLAlchemy internally (it refers to the InstanceState for the instance. While not directly relevant
to this section, if we want to get at it, we should use the inspect() function to access it).
At this point, the state in our User object matches that of the loaded database row. But upon expiring the object using
a method such as Session.expire(), we see that the state is removed:
>>> session.expire(user)
>>> user.__dict__
{'_sa_instance_state': <...>}
We see that while the internal “state” still hangs around, the values which correspond to the id and name columns
are gone. If we were to access one of these columns and are watching SQL, we’d see this:
>>> print(user.name)
SELECT user.id AS user_id, user.name AS user_name
FROM user
WHERE user.id = ?
(1,)
user1
Above, upon accessing the expired attribute user.name, the ORM initiated a lazy load to retrieve the most recent
state from the database, by emitting a SELECT for the user row to which this user refers. Afterwards, the __dict__
is again populated:
>>> user.__dict__
{
'id': 1, 'name': u'user1',
'_sa_instance_state': <...>,
}
Note: While we are peeking inside of __dict__ in order to see a bit of what SQLAlchemy does with object
attributes, we should not modify the contents of __dict__ directly, at least as far as those attributes which the
SQLAlchemy ORM is maintaining (other attributes outside of SQLA’s realm are fine). This is because SQLAlchemy
uses descriptors in order to track the changes we make to an object, and when we modify __dict__ directly, the
ORM won’t be able to track that we changed something.
Another key behavior of both expire() and refresh() is that all un-flushed changes on an object are discarded.
That is, if we were to modify an attribute on our User:
>>> user.name = 'user2'
but then we call expire() without first calling flush(), our pending value of ’user2’ is discarded:
>>> session.expire(user)
>>> user.name
'user1'
The expire() method can be used to mark as “expired” all ORM-mapped attributes for an instance:
# expire all ORM-mapped attributes on obj1
session.expire(obj1)
it can also be passed a list of string attribute names, referring to specific attributes to be marked as expired:
# expire only attributes obj1.attr1, obj1.attr2
session.expire(obj1, ['attr1', 'attr2'])
The refresh() method has a similar interface, but instead of expiring, it emits an immediate SELECT for the
object’s row immediately:
# reload all attributes on obj1
session.refresh(obj1)
refresh() also accepts a list of string attribute names, but unlike expire(), expects at least one name to be that
of a column-mapped attribute:
# reload obj1.attr1, obj1.attr2
session.refresh(obj1, ['attr1', 'attr2'])
The Session.expire_all() method allows us to essentially call Session.expire() on all objects con-
tained within the Session at once:
session.expire_all()
The SELECT statement that’s emitted when an object marked with expire() or loaded with refresh() varies
based on several factors, including:
• The load of expired attributes is triggered from column-mapped attributes only. While any kind of at-
tribute can be marked as expired, including a relationship() - mapped attribute, accessing an expired
relationship() attribute will emit a load only for that attribute, using standard relationship-oriented lazy
loading. Column-oriented attributes, even if expired, will not load as part of this operation, and instead will load
when any column-oriented attribute is accessed.
• relationship()- mapped attributes will not load in response to expired column-based attributes being
accessed.
• Regarding relationships, refresh() is more restrictive than expire() with regards to attributes that aren’t
column-mapped. Calling refresh() and passing a list of names that only includes relationship-mapped
attributes will actually raise an error. In any case, non-eager-loading relationship() attributes will not be
included in any refresh operation.
• relationship() attributes configured as “eager loading” via the lazy parameter will load in the case of
refresh(), if either no attribute names are specified, or if their names are inclued in the list of attributes to
be refreshed.
• Attributes that are configured as deferred() will not normally load, during either the expired-attribute load
or during a refresh. An unloaded attribute that’s deferred() instead loads on its own when directly accessed,
or if part of a “group” of deferred attributes where an unloaded attribute in that group is accessed.
• For expired attributes that are loaded on access, a joined-inheritance table mapping will emit a SELECT that
typically only includes those tables for which unloaded attributes are present. The action here is sophisticated
enough to load only the parent or child table, for example, if the subset of columns that were originally expired
encompass only one or the other of those tables.
• When refresh() is used on a joined-inheritance table mapping, the SELECT emitted will resemble that of
when Session.query() is used on the target object’s class. This is typically all those tables that are set up
as part of the mapping.
The Session uses the expiration feature automatically whenever the transaction referred to by the session ends.
Meaning, whenever Session.commit() or Session.rollback() is called, all objects within the Session
are expired, using a feature equivalent to that of the Session.expire_all() method. The rationale is that the
end of a transaction is a demarcating point at which there is no more context available in order to know what the
current state of the database is, as any number of other transactions may be affecting it. Only when a new transaction
starts can we again have access to the current state of the database, at which point any number of changes may have
occurred.
Transaction Isolation
Of course, most databases are capable of handling multiple transactions at once, even involving the same rows
of data. When a relational database handles multiple transactions involving the same tables or rows, this is
when the isolation aspect of the database comes into play. The isolation behavior of different databases varies
considerably and even on a single database can be configured to behave in different ways (via the so-called
isolation level setting). In that sense, the Session can’t fully predict when the same SELECT statement,
emitted a second time, will definitely return the data we already have, or will return new data. So as a best guess,
it assumes that within the scope of a transaction, unless it is known that a SQL expression has been emitted to
modify a particular row, there’s no need to refresh a row unless explicitly told to do so.
The Session.expire() and Session.refresh() methods are used in those cases when one wants to force
an object to re-load its data from the database, in those cases when it is known that the current state of data is possibly
stale. Reasons for this might include:
• some SQL has been emitted within the transaction outside of the scope of the ORM’s object handling, such as
if a Table.update() construct were emitted using the Session.execute() method;
• if the application is attempting to acquire data that is known to have been modified in a concurrent transaction,
and it is also known that the isolation rules in effect allow this data to be visible.
The second bullet has the important caveat that “it is also known that the isolation rules in effect allow this data to be
visible.” This means that it cannot be assumed that an UPDATE that happened on another database connection will
yet be visible here locally; in many cases, it will not. This is why if one wishes to use expire() or refresh() in
order to view data between ongoing transactions, an understanding of the isolation behavior in effect is essential.
See also:
Session.expire()
Session.expire_all()
Session.refresh()
isolation - glossary explanation of isolation which includes links to Wikipedia.
The SQLAlchemy Session In-Depth - a video + slides with an in-depth discussion of the object lifecycle including the
role of data expiration.
2.5.3 Cascades
Mappers support the concept of configurable cascade behavior on relationship() constructs. This refers to how
operations performed on a “parent” object relative to a particular Session should be propagated to items referred to
by that relationship (e.g. “child” objects), and is affected by the relationship.cascade option.
The default behavior of cascade is limited to cascades of the so-called save-update and merge settings. The typical
“alternative” setting for cascade is to add the delete and delete-orphan options; these settings are appropriate for related
objects which only exist as long as they are attached to their parent, and are otherwise deleted.
Cascade behavior is configured using the cascade option on relationship():
class Order(Base):
__tablename__ = 'order'
To set cascades on a backref, the same flag can be used with the backref() function, which ultimately feeds its
arguments back into relationship():
class Item(Base):
__tablename__ = 'item'
order = relationship("Order",
backref=backref("items", cascade="all, delete-orphan")
)
The default value of cascade is save-update, merge. The typical alternative setting for this parameter is either
all or more commonly all, delete-orphan. The all symbol is a synonym for save-update, merge,
refresh-expire, expunge, delete, and using it in conjunction with delete-orphan indicates that the
child object should follow along with its parent in all cases, and be deleted once it is no longer associated with that
parent.
The list of available values which can be specified for the cascade parameter are described in the following subsec-
tions.
save-update
save-update cascade indicates that when an object is placed into a Session via Session.add(), all the
objects associated with it via this relationship() should also be added to that same Session. Suppose we have
an object user1 with two related objects address1, address2:
>>> user1 = User()
>>> address1, address2 = Address(), Address()
>>> user1.addresses = [address1, address2]
save-update cascade also affects attribute operations for objects that are already present in a Session. If we add
a third object, address3 to the user1.addresses collection, it becomes part of the state of that Session:
>>> address3 = Address()
>>> user1.append(address3)
>>> address3 in sess
>>> True
save-update has the possibly surprising behavior which is that persistent objects which were removed from a
collection or in some cases a scalar attribute may also be pulled into the Session of a parent object; this is so that
the flush process may handle that related object appropriately. This case can usually only arise if an object is removed
from one Session and added to another:
>>> user1 = sess1.query(User).filter_by(id=1).first()
>>> address1 = user1.addresses[0]
>>> sess1.close() # user1, address1 no longer associated with sess1
The save-update cascade is on by default, and is typically taken for granted; it simplifies code by allowing a
single call to Session.add() to register an entire structure of objects within that Session at once. While it can
be disabled, there is usually not a need to do so.
One case where save-update cascade does sometimes get in the way is in that it takes place in both directions for
bi-directional relationships, e.g. backrefs, meaning that the association of a child object with a particular parent can
have the effect of the parent object being implicitly associated with that child object’s Session; this pattern, as well
as how to modify its behavior using the cascade_backrefs flag, is discussed in the section Controlling Cascade
on Backrefs.
delete
The delete cascade indicates that when a “parent” object is marked for deletion, its related “child” objects should
also be marked for deletion. If for example we we have a relationship User.addresses with delete cascade
configured:
class User(Base):
# ...
If using the above mapping, we have a User object and two related Address objects:
>>> user1 = sess.query(User).filter_by(id=1).first()
>>> address1, address2 = user1.addresses
If we mark user1 for deletion, after the flush operation proceeds, address1 and address2 will also be deleted:
>>> sess.delete(user1)
>>> sess.commit()
DELETE FROM address WHERE address.id = ?
((1,), (2,))
DELETE FROM user WHERE user.id = ?
(1,)
COMMIT
Alternatively, if our User.addresses relationship does not have delete cascade, SQLAlchemy’s default behav-
ior is to instead de-associate address1 and address2 from user1 by setting their foreign key reference to NULL.
Using a mapping as follows:
class User(Base):
# ...
addresses = relationship("Address")
Upon deletion of a parent User object, the rows in address are not deleted, but are instead de-associated:
>>> sess.delete(user1)
>>> sess.commit()
UPDATE address SET user_id=? WHERE address.id = ?
(None, 1)
UPDATE address SET user_id=? WHERE address.id = ?
(None, 2)
DELETE FROM user WHERE user.id = ?
(1,)
COMMIT
delete cascade is more often than not used in conjunction with delete-orphan cascade, which will emit a DELETE
for the related row if the “child” object is deassociated from the parent. The combination of delete and
delete-orphan cascade covers both situations where SQLAlchemy has to decide between setting a foreign key
column to NULL versus deleting the row entirely.
ORM-level “delete” cascade vs. FOREIGN KEY level “ON DELETE” cascade
The behavior of SQLAlchemy’s “delete” cascade has a lot of overlap with the ON DELETE CASCADE feature
of a database foreign key, as well as with that of the ON DELETE SET NULL foreign key setting when “delete”
cascade is not specified. Database level “ON DELETE” cascades are specific to the “FOREIGN KEY” construct
of the relational database; SQLAlchemy allows configuration of these schema-level constructs at the DDL level
using options on ForeignKeyConstraint which are described at ON UPDATE and ON DELETE.
It is important to note the differences between the ORM and the relational database’s notion of “cascade” as well
as how they integrate:
• A database level ON DELETE cascade is configured effectively on the many-to-one side of the rela-
tionship; that is, we configure it relative to the FOREIGN KEY constraint that is the “many” side of a
relationship. At the ORM level, this direction is reversed. SQLAlchemy handles the deletion of “child”
objects relative to a “parent” from the “parent” side, which means that delete and delete-orphan
cascade are configured on the one-to-many side.
• Database level foreign keys with no ON DELETE setting are often used to prevent a parent row from
being removed, as it would necessarily leave an unhandled related row present. If this behavior is desired
in a one-to-many relationship, SQLAlchemy’s default behavior of setting a foreign key to NULL can be
caught in one of two ways:
– The easiest and most common is just to set the foreign-key-holding column to NOT NULL at the
database schema level. An attempt by SQLAlchemy to set the column to NULL will fail with a
simple NOT NULL constraint exception.
– The other, more special case way is to set the passive_deletes flag to the string "all". This
has the effect of entirely disabling SQLAlchemy’s behavior of setting the foreign key column to
NULL, and a DELETE will be emitted for the parent row without any affect on the child row, even
if the child row is present in memory. This may be desirable in the case when database-level foreign
key triggers, either special ON DELETE settings or otherwise, need to be activated in all cases when
a parent row is deleted.
• Database level ON DELETE cascade is vastly more efficient than that of SQLAlchemy. The database
can chain a series of cascade operations across many relationships at once; e.g. if row A is deleted, all the
related rows in table B can be deleted, and all the C rows related to each of those B rows, and on and on,
all within the scope of a single DELETE statement. SQLAlchemy on the other hand, in order to support
the cascading delete operation fully, has to individually load each related collection in order to target all
rows that then may have further related collections. That is, SQLAlchemy isn’t sophisticated enough to
emit a DELETE for all those related rows at once within this context.
• SQLAlchemy doesn’t need to be this sophisticated, as we instead provide smooth integration with the
database’s own ON DELETE functionality, by using the passive_deletes option in conjunction with
properly configured foreign key constraints. Under this behavior, SQLAlchemy only emits DELETE for
those rows that are already locally present in the Session; for any collections that are unloaded, it leaves
them to the database to handle, rather than emitting a SELECT for them. The section Using Passive
Deletes provides an example of this use.
• While database-level ON DELETE functionality works only on the “many” side of a relationship,
SQLAlchemy’s “delete” cascade has limited ability to operate in the reverse direction as well, mean-
ing it can be configured on the “many” side to delete an object on the “one” side when the reference on
the “many” side is deleted. However this can easily result in constraint violations if there are other objects
referring to this “one” side from the “many”, so it typically is only useful when a relationship is in fact a
“one to one”. The single_parent flag should be used to establish an in-Python assertion for this case.
When using a relationship() that also includes a many-to-many table using the secondary option,
SQLAlchemy’s delete cascade handles the rows in this many-to-many table automatically. Just like, as described
in Deleting Rows from the Many to Many Table, the addition or removal of an object from a many-to-many collection
results in the INSERT or DELETE of a row in the many-to-many table, the delete cascade, when activated as the re-
sult of a parent object delete operation, will DELETE not just the row in the “child” table but also in the many-to-many
table.
delete-orphan
delete-orphan cascade adds behavior to the delete cascade, such that a child object will be marked for deletion
when it is de-associated from the parent, not just when the parent is marked for deletion. This is a common feature
when dealing with a related object that is “owned” by its parent, with a NOT NULL foreign key, so that removal of
the item from the parent collection results in its deletion.
delete-orphan cascade implies that each child object can only have one parent at a time, so is configured in
the vast majority of cases on a one-to-many relationship. Setting it on a many-to-one or many-to-many relation-
ship is more awkward; for this use case, SQLAlchemy requires that the relationship() be configured with the
single_parent argument, establishes Python-side validation that ensures the object is associated with only one
parent at a time.
merge
merge cascade indicates that the Session.merge() operation should be propagated from a parent that’s the
subject of the Session.merge() call down to referred objects. This cascade is also on by default.
refresh-expire
refresh-expire is an uncommon option, indicating that the Session.expire() operation should be propa-
gated from a parent down to referred objects. When using Session.refresh(), the referred objects are expired
only, but not actually refreshed.
expunge
expunge cascade indicates that when the parent object is removed from the Session using
Session.expunge(), the operation should be propagated down to referred objects.
The save-update cascade by default takes place on attribute change events emitted from backrefs. This is probably a
confusing statement more easily described through demonstration; it means that, given a mapping such as this:
mapper(Order, order_table, properties={
'items' : relationship(Item, backref='order')
})
If an Order is already in the session, and is assigned to the order attribute of an Item, the backref appends the
Item to the items collection of that Order, resulting in the save-update cascade taking place:
>>> o1 = Order()
>>> session.add(o1)
>>> o1 in session
True
>>> i1 = Item()
>>> i1.order = o1
>>> i1 in o1.items
True
>>> i1 in session
True
So above, the assignment of i1.order = o1 will append i1 to the items collection of o1, but will not add
i1 to the session. You can, of course, add() i1 to the session at a later point. This option may be helpful for
situations where an object needs to be kept out of a session until it’s construction is completed, but still needs to be
given associations to objects which are already persistent in the target session.
Managing Transactions
A newly constructed Session may be said to be in the “begin” state. In this state, the Session has not established
any connection or transactional state with any of the Engine objects that may be associated with it.
The Session then receives requests to operate upon a database connection. Typically, this means it is
called upon to execute SQL statements using a particular Engine, which may be via Session.query(),
Session.execute(), or within a flush operation of pending data, which occurs when such state exists and
Session.commit() or Session.flush() is called.
As these requests are received, each new Engine encountered is associated with an ongoing transactional state
maintained by the Session. When the first Engine is operated upon, the Session can be said to have left the
“begin” state and entered “transactional” state. For each Engine encountered, a Connection is associated with it,
which is acquired via the Engine.contextual_connect() method. If a Connection was directly associated
with the Session (see Joining a Session into an External Transaction (such as for test suites) for an example of this),
it is added to the transactional state directly.
For each Connection, the Session also maintains a Transaction object, which is ac-
quired by calling Connection.begin() on each Connection, or if the Session object has
been established using the flag twophase=True, a TwoPhaseTransaction object acquired via
Connection.begin_twophase(). These transactions are all committed or rolled back corresponding to
the invocation of the Session.commit() and Session.rollback() methods. A commit operation will also
call the TwoPhaseTransaction.prepare() method on all transactions if applicable.
When the transactional state is completed after a rollback or commit, the Session releases all Transaction
and Connection resources, and goes back to the “begin” state, which will again invoke new Connection and
Transaction objects as new requests to emit SQL statements are received.
The example below illustrates this lifecycle:
engine = create_engine("...")
Session = sessionmaker(bind=engine)
Using SAVEPOINT
SAVEPOINT transactions, if supported by the underlying engine, may be delineated using the begin_nested()
method:
Session = sessionmaker()
session = Session()
session.add(u1)
session.add(u2)
begin_nested() may be called any number of times, which will issue a new SAVEPOINT with a unique identifier
for each call. For each begin_nested() call, a corresponding rollback() or commit() must be issued. (But
note that if the return value is used as a context manager, i.e. in a with-statement, then this rollback/commit is issued
by the context manager upon exiting the context, and so should not be added explicitly.)
When begin_nested() is called, a flush() is unconditionally issued (regardless of the autoflush setting).
This is so that when a rollback() occurs, the full state of the session is expired, thus causing all subsequent
attribute/instance access to reference the full state of the Session right before begin_nested() was called.
begin_nested(), in the same manner as the less often used begin() method, returns a transactional object
which also works as a context manager. It can be succinctly used around individual record inserts in order to catch
things like unique constraint exceptions:
for record in records:
try:
with session.begin_nested():
session.merge(record)
except:
print "Skipped record %s" % record
session.commit()
Autocommit Mode
The example of Session transaction lifecycle illustrated at the start of Managing Transactions applies to a Session
configured in the default mode of autocommit=False. Constructing a Session with autocommit=True
produces a Session placed into “autocommit” mode, where each SQL statement invoked by a Session.query()
or Session.execute() occurs using a new connection from the connection pool, discarding it after results have
been iterated. The Session.flush() operation still occurs within the scope of a single transaction, though this
transaction is closed out after the Session.flush() operation completes.
Warning: “autocommit” mode should not be considered for general use. If used, it should always be combined
with the usage of Session.begin() and Session.commit(), to ensure a transaction demarcation.
Executing queries outside of a demarcated transaction is a legacy mode of usage, and can in some cases lead to
concurrent connection checkouts.
In the absence of a demarcated transaction, the Session cannot make appropriate decisions as to when
autoflush should occur nor when auto-expiration should occur, so these features should be disabled with
autoflush=False, expire_on_commit=False.
Modern usage of “autocommit” is for framework integrations that need to control specifically when the “be-
gin” state occurs. A session which is configured with autocommit=True may be placed into the “be-
gin” state using the Session.begin() method. After the cycle completes upon Session.commit() or
Session.rollback(), connection and transaction resources are released and the Session goes back into “au-
tocommit” mode, until Session.begin() is called again:
Session = sessionmaker(bind=engine, autocommit=True)
session = Session()
session.begin()
try:
item1 = session.query(Item).get(1)
item2 = session.query(Item).get(2)
item1.foo = 'bar'
item2.bar = 'foo'
session.commit()
except:
session.rollback()
raise
The Session.begin() method also returns a transactional token which is compatible with the Python 2.6 with
statement:
Session = sessionmaker(bind=engine, autocommit=True)
session = Session()
with session.begin():
item1 = session.query(Item).get(1)
item2 = session.query(Item).get(2)
item1.foo = 'bar'
item2.bar = 'foo'
Using Subtransactions with Autocommit A subtransaction indicates usage of the Session.begin() method
in conjunction with the subtransactions=True flag. This produces a non-transactional, delimiting construct
that allows nesting of calls to begin() and commit(). Its purpose is to allow the construction of code that can
function within a transaction both independently of any external code that starts a transaction, as well as within a block
that has already demarcated a transaction.
subtransactions=True is generally only useful in conjunction with autocommit, and is equivalent to the pattern
described at Nesting of Transaction Blocks, where any number of functions can call Connection.begin() and
Transaction.commit() as though they are the initiator of the transaction, but in fact may be participating in an
already ongoing transaction:
# method_a starts a transaction and calls method_b
def method_a(session):
session.begin(subtransactions=True)
try:
method_b(session)
session.commit() # transaction is committed here
except:
session.rollback() # rolls back the transaction
raise
Subtransactions are used by the Session.flush() process to ensure that the flush operation takes place within a
transaction, regardless of autocommit. When autocommit is disabled, it is still useful in that it forces the Session
into a “pending rollback” state, as a failed flush cannot be resumed in mid-operation, where the end user still maintains
the “scope” of the transaction overall.
For backends which support two-phase operaration (currently MySQL and PostgreSQL), the session can be instructed
to use two-phase commit semantics. This will coordinate the committing of transactions across databases so that the
transaction is either committed or rolled back in all databases. You can also prepare() the session for interacting
with transactions not managed by SQLAlchemy. To use two phase transactions set the flag twophase=True on the
session:
engine1 = create_engine('postgresql://db1')
engine2 = create_engine('postgresql://db2')
Session = sessionmaker(twophase=True)
session = Session()
# commit. session will issue a flush to all DBs, and a prepare step to all DBs,
Isolation refers to the behavior of the transaction at the database level in relation to other transactions occurring
concurrently. There are four well-known modes of isolation, and typically the Python DBAPI allows these to be set
on a per-connection basis, either through explicit APIs or via database-specific calls.
SQLAlchemy’s dialects support settable isolation modes on a per-Engine or per-Connection basis, using flags at
both the create_engine() level as well as at the Connection.execution_options() level.
When using the ORM Session, it acts as a facade for engines and connections, but does not expose transaction
isolation directly. So in order to affect transaction isolation level, we need to act upon the Engine or Connection
as appropriate.
See also:
create_engine.isolation_level
SQLite Transaction Isolation
Postgresql Isolation Level
MySQL Isolation Level
Setting Isolation Engine-Wide To set up a Session or sessionmaker with a specific isolation level globally,
use the create_engine.isolation_level parameter:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
eng = create_engine(
"postgresql://scott:tiger@localhost/test",
isolation_level='REPEATABLE_READ')
maker = sessionmaker(bind=eng)
session = maker()
Setting Isolation for Individual Sessions When we make a new Session, either using the constructor directly or
when we call upon the callable produced by a sessionmaker, we can pass the bind argument directly, overriding
the pre-existing bind. We can combine this with the Engine.execution_options() method in order to produce
a copy of the original Engine that will add this option:
session = maker(
bind=engine.execution_options(isolation_level='SERIALIZABLE'))
For the case where the Session or sessionmaker is configured with multiple “binds”, we can either re-specify
the binds argument fully, or if we want to only replace specific binds, we can use the Session.bind_mapper()
or Session.bind_table() methods:
session = maker()
session.bind_mapper(
User, user_engine.execution_options(isolation_level='SERIALIZABLE'))
Setting Isolation for Individual Transactions A key caveat regarding isolation level is that the setting cannot be
safely modified on a Connection where a transaction has already started. Databases cannot change the isolation
level of a transaction in progress, and some DBAPIs and SQLAlchemy dialects have inconsistent behaviors in this area.
Some may implicitly emit a ROLLBACK and some may implicitly emit a COMMIT, others may ignore the setting
until the next transaction. Therefore SQLAlchemy emits a warning if this option is set when a transaction is already in
play. The Session object does not provide for us a Connection for use in a transaction where the transaction is
not already begun. So here, we need to pass execution options to the Session at the start of a transaction by passing
Session.connection.execution_options provided by the Session.connection() method:
from sqlalchemy.orm import Session
sess = Session(bind=engine)
sess.connection(execution_options={'isolation_level': 'SERIALIZABLE'})
Above, we first produce a Session using either the constructor or a sessionmaker. Then we explicitly set
up the start of a transaction by calling upon Session.connection(), which provides for execution options
that will be passed to the connection before the transaction is begun. If we are working with a Session that has
multiple binds or some other custom scheme for Session.get_bind(), we can pass additional arguments to
Session.connection() in order to affect how the bind is procured:
sess = my_sesssionmaker()
See the section Transaction Events for an overview of the available event hooks for session transaction state changes.
If a Connection is being used which is already in a transactional state (i.e. has a Transaction established), a
Session can be made to participate within that transaction by just binding the Session to that Connection. The
usual rationale for this is a test suite that allows ORM code to work freely with a Session, including the ability to
call Session.commit(), where afterwards the entire database interaction is rolled back:
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from unittest import TestCase
engine = create_engine('postgresql://...')
class SomeTest(TestCase):
def setUp(self):
# connect to the database
self.connection = engine.connect()
def test_something(self):
# use the session in tests.
self.session.add(Foo())
self.session.commit()
def tearDown(self):
self.session.close()
class SomeTest(TestCase):
def setUp(self):
# connect to the database
self.connection = engine.connect()
session.begin_nested()
This feature allows the value of a database column to be set to a SQL expression instead of a literal value. It’s especially
useful for atomic updates, calling stored procedures, etc. All you do is assign an expression to an attribute:
class SomeClass(object):
pass
mapper(SomeClass, some_table)
someobject = session.query(SomeClass).get(5)
This technique works both for INSERT and UPDATE statements. After the flush/commit operation, the value
attribute on someobject above is expired, so that when next accessed the newly generated value will be loaded
from the database.
SQL expressions and strings can be executed via the Session within its transactional context. This is most easily
accomplished using the execute() method, which returns a ResultProxy in the same manner as an Engine or
Connection:
Session = sessionmaker(bind=engine)
session = Session()
The current Connection held by the Session is accessible using the connection() method:
connection = session.connection()
The examples above deal with a Session that’s bound to a single Engine or Connection. To execute statements
using a Session which is bound either to multiple engines, or none at all (i.e. relies upon bound metadata), both
execute() and connection() accept a mapper keyword argument, which is passed a mapped class or Mapper
instance, which is used to locate the proper context for the desired engine:
Session = sessionmaker()
session = Session()
connection = session.connection(MyMappedClass)
Partitioning Strategies
Vertical partitioning places different kinds of objects, or different tables, across multiple databases:
engine1 = create_engine('postgresql://db1')
engine2 = create_engine('postgresql://db2')
Session = sessionmaker(twophase=True)
session = Session()
Above, operations against either class will make usage of the Engine linked to that class. Upon a flush operation,
similar rules take place to ensure each class is written to the right database.
The transactions among the multiple databases can optionally be coordinated via two phase commit, if the underlying
backend supports it. See Enabling Two-Phase Commit for an example.
More comprehensive rule-based class-level partitioning can be built by overriding the Session.get_bind()
method. Below we illustrate a custom Session which delivers the following rules:
1. Flush operations are delivered to the engine named master.
2. Operations on objects that subclass MyOtherClass all occur on the other engine.
3. Read operations for all other classes occur on a random choice of the slave1 or slave2 database.
engines = {
'master':create_engine("sqlite:///master.db"),
'other':create_engine("sqlite:///other.db"),
'slave1':create_engine("sqlite:///slave1.db"),
'slave2':create_engine("sqlite:///slave2.db"),
}
class RoutingSession(Session):
def get_bind(self, mapper=None, clause=None):
if mapper and issubclass(mapper.class_, MyOtherClass):
return engines['other']
elif self._flushing:
return engines['master']
else:
return engines[
random.choice(['slave1','slave2'])
]
The above Session class is plugged in using the class_ argument to sessionmaker:
Session = sessionmaker(class_=RoutingSession)
This approach can be combined with multiple MetaData objects, using an approach such as that of using the declar-
ative __abstract__ keyword, described at __abstract__.
Horizontal Partitioning
Horizontal partitioning partitions the rows of a single table (or a set of tables) across multiple databases.
See the “sharding” example: Horizontal Sharding.
Bulk Operations
Note: Bulk Operations mode is a new series of operations made available on the Session object for the purpose
of invoking INSERT and UPDATE statements with greatly reduced Python overhead, at the expense of much less
functionality, automation, and error checking. As of SQLAlchemy 1.0, these features should be considered as “beta”,
and additionally are intended for advanced users.
Usage
The methods each work in the context of the Session object’s transaction, like any other:
s = Session()
objects = [
User(name="u1"),
User(name="u2"),
User(name="u3")
]
s.bulk_save_objects(objects)
See also:
Session.bulk_save_objects()
Session.bulk_insert_mappings()
Session.bulk_update_mappings()
The bulk methods offer performance that under particular circumstances can be close to that of us-
ing the core Insert and Update constructs in an “executemany” context (for a description of “ex-
ecutemany”, see Executing Multiple Statements in the Core tutorial). In order to achieve this, the
Session.bulk_insert_mappings.return_defaults flag should be disabled so that rows can be batched
together. The example suite in Performance should be carefully studied in order to gain familiarity with how fast bulk
performance can be achieved.
ORM Compatibility
The bulk insert / update methods lose a significant amount of functionality versus traditional ORM use. The following
is a listing of features that are not available when using these methods:
• persistence along relationship() linkages
• sorting of rows within order of dependency; rows are inserted or updated directly in the order in which they are
passed to the methods
• Session-management on the given objects, including attachment to the session, identity map management.
• Functionality related to primary key mutation, ON UPDATE cascade
• SQL expression inserts / updates (e.g. Embedding SQL Insert/Update Expressions into a Flush)
• ORM events such as MapperEvents.before_insert(), etc. The bulk session methods have no event
support.
Features that are available include:
• INSERTs and UPDATEs of mapped objects
• Version identifier support
• Multi-table mappings, such as joined-inheritance - however, an object to be inserted across mul-
tiple tables either needs to have primary key identifiers fully populated ahead of time, else the
Session.bulk_save_objects.return_defaults flag must be used, which will greatly reduce the
performance benefits
Recall from the section When do I construct a Session, when do I commit it, and when do I close it?, the concept
of “session scopes” was introduced, with an emphasis on web applications and the practice of linking the scope of a
Session with that of a web request. Most modern web frameworks include integration tools so that the scope of the
Session can be managed automatically, and these tools should be used as they are available.
SQLAlchemy includes its own helper object, which helps with the establishment of user-defined Session scopes. It
is also used by third-party integration systems to help construct their integration schemes.
The object is the scoped_session object, and it represents a registry of Session objects. If you’re not familiar
with the registry pattern, a good introduction can be found in Patterns of Enterprise Architecture.
Note: The scoped_session object is a very popular and useful object used by many SQLAlchemy applications.
However, it is important to note that it presents only one approach to the issue of Session management. If you’re
new to SQLAlchemy, and especially if the term “thread-local variable” seems strange to you, we recommend that if
possible you familiarize first with an off-the-shelf integration system such as Flask-SQLAlchemy or zope.sqlalchemy.
A scoped_session is constructed by calling it, passing it a factory which can create new Session objects. A
factory is just something that produces a new object when called, and in the case of Session, the most common
factory is the sessionmaker, introduced earlier in this section. Below we illustrate this usage:
>>> from sqlalchemy.orm import scoped_session
>>> from sqlalchemy.orm import sessionmaker
The scoped_session object we’ve created will now call upon the sessionmaker when we “call” the registry:
>>> some_session = Session()
Above, some_session is an instance of Session, which we can now use to talk to the database. This same
Session is also present within the scoped_session registry we’ve created. If we call upon the registry a second
time, we get back the same Session:
>>> some_other_session = Session()
>>> some_session is some_other_session
True
This pattern allows disparate sections of the application to call upon a global scoped_session, so that all those
areas may share the same session without the need to pass it explicitly. The Session we’ve established in our registry
will remain, until we explicitly tell our registry to dispose of it, by calling scoped_session.remove():
>>> Session.remove()
The scoped_session.remove() method first calls Session.close() on the current Session, which
has the effect of releasing any connection/transactional resources owned by the Session first, then discarding the
Session itself. “Releasing” here means that connections are returned to their connection pool and any transactional
state is rolled back, ultimately using the rollback() method of the underlying DBAPI connection.
At this point, the scoped_session object is “empty”, and will create a new Session when called again. As
illustrated below, this is not the same Session we had before:
>>> new_session = Session()
>>> new_session is some_session
False
The above series of steps illustrates the idea of the “registry” pattern in a nutshell. With that basic idea in hand, we
can discuss some of the details of how this pattern proceeds.
The job of the scoped_session is simple; hold onto a Session for all who ask for it. As a means of producing
more transparent access to this Session, the scoped_session also includes proxy behavior, meaning that the
registry itself can be treated just like a Session directly; when methods are called on this object, they are proxied
to the underlying Session being maintained by the registry:
Session = scoped_session(some_factory)
# equivalent to:
#
# session = Session()
# print session.query(MyClass).all()
#
print Session.query(MyClass).all()
The above code accomplishes the same task as that of acquiring the current Session by calling upon the registry,
then using that Session.
Thread-Local Scope
Users who are familiar with multithreaded programming will note that representing anything as a global variable is
usually a bad idea, as it implies that the global object will be accessed by many threads concurrently. The Session
object is entirely designed to be used in a non-concurrent fashion, which in terms of multithreading means “only
in one thread at a time”. So our above example of scoped_session usage, where the same Session object is
maintained across multiple calls, suggests that some process needs to be in place such that mutltiple calls across many
threads don’t actually get a handle to the same session. We call this notion thread local storage, which means, a
special object is used that will maintain a distinct object per each application thread. Python provides this via the
threading.local() construct. The scoped_session object by default uses this object as storage, so that a single
Session is maintained for all who call upon the scoped_session registry, but only within the scope of a single
thread. Callers who call upon the registry in a different thread get a Session instance that is local to that other thread.
Using this technique, the scoped_session provides a quick and relatively simple (if one is familiar with thread-
local storage) way of providing a single, global object in an application that is safe to be called upon from multiple
threads.
The scoped_session.remove() method, as always, removes the current Session associated with the thread,
if any. However, one advantage of the threading.local() object is that if the application thread itself ends, the
“storage” for that thread is also garbage collected. So it is in fact “safe” to use thread local scope with an application
that spawns and tears down threads, without the need to call scoped_session.remove(). However, the scope
of transactions themselves, i.e. ending them via Session.commit() or Session.rollback(), will usually
still be something that must be explicitly arranged for at the appropriate time, unless the application actually ties the
lifespan of a thread to the lifespan of a transaction.
As discussed in the section When do I construct a Session, when do I commit it, and when do I close it?, a web
application is architected around the concept of a web request, and integrating such an application with the Session
usually implies that the Session will be associated with that request. As it turns out, most Python web frameworks,
with notable exceptions such as the asynchronous frameworks Twisted and Tornado, use threads in a simple way, such
that a particular web request is received, processed, and completed within the scope of a single worker thread. When
the request ends, the worker thread is released to a pool of workers where it is available to handle another request.
This simple correspondence of web request and thread means that to associate a Session with a thread implies it is
also associated with the web request running within that thread, and vice versa, provided that the Session is created
only after the web request begins and torn down just before the web request ends. So it is a common practice to use
scoped_session as a quick way to integrate the Session with a web application. The sequence diagram below
illustrates this flow:
Web Server Web Framework SQLAlchemy ORM Code
-------------- -------------- ------------------------------
startup -> Web framework # Session registry is established
incoming
web request -> web request -> # The registry is *optionally*
starts # called upon explicitly to create
# a Session local to the thread and/or request
Session()
Session.add(some_object) # ...
Using the above flow, the process of integrating the Session with the web application has exactly two requirements:
1. Create a single scoped_session registry when the web application first starts, ensuring that this object is
accessible by the rest of the application.
2. Ensure that scoped_session.remove() is called when the web request ends, usually by integrating with
the web framework’s event system to establish an “on request end” event.
As noted earlier, the above pattern is just one potential way to integrate a Session with a web framework, one which
in particular makes the significant assumption that the web framework associates web requests with application
threads. It is however strongly recommended that the integration tools provided with the web framework itself
be used, if available, instead of scoped_session.
In particular, while using a thread local can be convenient, it is preferable that the Session be associated directly
with the request, rather than with the current thread. The next section on custom scopes details a more advanced
configuration which can combine the usage of scoped_session with direct request based scope, or any kind of
scope.
The scoped_session object’s default behavior of “thread local” scope is only one of many options on how to
“scope” a Session. A custom scope can be defined based on any existing system of getting at “the current thing we
are working with”.
Suppose a web framework defines a library function get_current_request(). An application built using this
framework can call this function at any time, and the result will be some kind of Request object that represents
the current request being processed. If the Request object is hashable, then this function can be easily integrated
with scoped_session to associate the Session with the request. Below we illustrate this in conjunction with
a hypothetical event marker provided by the web framework on_request_end, which allows code to be invoked
whenever a request ends:
@on_request_end
def remove_session(req):
Session.remove()
Above, we instantiate scoped_session in the usual way, except that we pass our request-returning function as
the “scopefunc”. This instructs scoped_session to use this function to generate a dictionary key whenever the
registry is called upon to return the current Session. In this case it is particularly important that we ensure a reliable
“remove” system is implemented, as this dictionary is not otherwise self-managed.
class MyClass(object):
query = Session.query_property()
Produces instances of the session’s configured query class by default. To override and use a custom im-
plementation, provide a query_cls callable. The callable will be invoked with the class’s mapper as a
positional argument and a session keyword argument.
There is no limit to the number of query properties placed on a class.
remove()
Dispose of the current Session, if present.
This will first call Session.close() method on the current Session, which releases any existing
transactional/connection resources still being held; transactions specifically are rolled back. The Session
is then discarded. Upon next usage within the same scope, the scoped_session will produce a new
Session object.
session_factory = None
The session_factory provided to __init__ is stored in this attribute and may be accessed at a later time.
This can be useful when a new non-scoped Session or Connection to the database is needed.
class sqlalchemy.util.ScopedRegistry(createfunc, scopefunc)
A Registry that can store one or multiple instances of a single class on the basis of a “scope” function.
The object implements __call__ as the “getter”, so by calling myregistry() the contained object is
returned for the current scope.
Parameters
• createfunc – a callable that returns a new object to be placed in the registry
• scopefunc – a callable that will return a key to store/retrieve an object.
__init__(createfunc, scopefunc)
Construct a new ScopedRegistry.
Parameters
• createfunc – A creation function that will generate a new value for the current scope,
if none is present.
• scopefunc – A function that returns a hashable token representing the current scope
(such as, current thread identifier).
clear()
Clear the current scope, if any.
has()
Return True if an object is present in the current scope.
set(obj)
Set the value for the current scope.
class sqlalchemy.util.ThreadLocalRegistry(createfunc)
Bases: sqlalchemy.util._collections.ScopedRegistry
A ScopedRegistry that uses a threading.local() variable for storage.
SQLAlchemy features an extensive Event Listening system used throughout the Core and ORM. Within the ORM,
there are a wide variety of event listener hooks, which are documented at an API level at ORM Events. This collection
of events has grown over the years to include lots of very useful new events as well as some older events that aren’t as
relevant as they once were. This section will attempt to introduce the major event hooks and when they might be used.
Persistence Events
Probably the most widely used series of events are the “persistence” events, which correspond to the flush process.
The flush is where all the decisions are made about pending changes to objects and are then emitted out to the database
in the form of INSERT, UPDATE, and DELETE staetments.
before_flush()
The SessionEvents.before_flush() hook is by far the most generally useful event to use when an appli-
cation wants to ensure that additional persistence changes to the database are made when a flush proceeds. Use
SessionEvents.before_flush() in order to operate upon objects to validate their state as well as to compose
additional objects and references before they are persisted. Within this event, it is safe to manipulate the Session’s
state, that is, new objects can be attached to it, objects can be deleted, and indivual attributes on objects can be changed
freely, and these changes will be pulled into the flush process when the event hook completes.
The typical SessionEvents.before_flush() hook will be tasked with scanning the collections
Session.new, Session.dirty and Session.deleted in order to look for objects where something will
be happening.
For illustrations of SessionEvents.before_flush(), see examples such as Versioning with a History Table
and Versioning using Temporal Rows.
after_flush()
The SessionEvents.after_flush() hook is called after the SQL has been emitted for a flush process, but
before the state of the objects that were flushed has been altered. That is, you can still inspect the Session.new,
Session.dirty and Session.deleted collections to see what was just flushed, and you can also use his-
tory tracking features like the ones provided by AttributeState to see what changes were just persisted. In
the SessionEvents.after_flush() event, additional SQL can be emitted to the database based on what’s
observed to have changed.
after_flush_postexec()
Mapper-level Events
In addition to the flush-level hooks, there is also a suite of hooks that are more fine-grained, in that they are called
on a per-object basis and are broken out based on INSERT, UPDATE or DELETE. These are the mapper persistence
hooks, and they too are very popular, however these events need to be approached more cautiously, as they proceed
within the context of the flush process that is already ongoing; many operations are not safe to proceed here.
The events are:
• MapperEvents.before_insert()
• MapperEvents.after_insert()
• MapperEvents.before_update()
• MapperEvents.after_update()
• MapperEvents.before_delete()
• MapperEvents.after_delete()
Each event is passed the Mapper, the mapped object itself, and the Connection which is being used to emit an
INSERT, UPDATE or DELETE statement. The appeal of these events is clear, in that if an application wants to tie
some activity to when a specific type of object is persisted with an INSERT, the hook is very specific; unlike the
SessionEvents.before_flush() event, there’s no need to search through collections like Session.new in
order to find targets. However, the flush plan which represents the full list of every single INSERT, UPDATE, DELETE
statement to be emitted has already been decided when these events are called, and no changes may be made at this
stage. Therefore the only changes that are even possible to the given objects are upon attributes local to the object’s
row. Any other change to the object or other objects will impact the state of the Session, which will fail to function
properly.
Operations that are not supported within these mapper-level persistence events include:
• Session.add()
• Session.delete()
• Mapped collection append, add, remove, delete, discard, etc.
• Mapped relationship attribute set/del events, i.e. someobject.related = someotherobject
The reason the Connection is passed is that it is encouraged that simple SQL operations take place here, directly
on the Connection, such as incrementing counters or inserting extra rows within log tables. When dealing with the
Connection, it is expected that Core-level SQL operations will be used; e.g. those described in SQL Expression
Language Tutorial.
There are also many per-object operations that don’t need to be handled within a flush event at all. The most common
alternative is to simply establish additional state along with an object inside its __init__() method, such as creating
additional objects that are to be associated with the new object. Using validators as described in Simple Validators
is another approach; these functions can intercept changes to attributes and establish additional state changes on the
target object in response to the attribute change. With both of these approaches, the object is in the correct state before
it ever gets to the flush step.
Another use case for events is to track the lifecycle of objects. This refers to the states first introduced at Quickie Intro
to Object States.
As of SQLAlchemy 1.0, there is no direct event interface for tracking of these states. Events that can be used at the
moment to track the state of objects include:
• InstanceEvents.init()
• InstanceEvents.load()
• SessionEvents.before_attach()
• SessionEvents.after_attach()
• SessionEvents.before_flush() - by scanning the session’s collections
• SessionEvents.after_flush() - by scanning the session’s collections
SQLAlchemy 1.1 will introduce a comprehensive event system to track the object persistence states fully and unam-
biguously.
Transaction Events
Transaction events allow an application to be notifed when transaction boundaries occur at the Session level as well
as when the Session changes the transactional state on Connection objects.
• SessionEvents.after_transaction_create(), SessionEvents.after_transaction_end()
- these events track the logical transaction scopes of the Session in a way that is not specific to individual
database connections. These events are intended to help with integration of transaction-tracking systems such
as zope.sqlalchemy. Use these events when the application needs to align some external scope with the
transactional scope of the Session. These hooks mirror the “nested” transactional behavior of the Session,
in that they track logical “subtransactions” as well as “nested” (e.g. SAVEPOINT) transactions.
• SessionEvents.before_commit(), SessionEvents.after_commit(),
SessionEvents.after_begin(), SessionEvents.after_rollback(),
SessionEvents.after_soft_rollback() - These events allow tracking of transaction events
from the perspective of database connections. SessionEvents.after_begin() in particular is a per-
connection event; a Session that maintains more than one connection will emit this event for each connection
individually as those connections become used within the current transaction. The rollback and commit events
then refer to when the DBAPI connections themselves have received rollback or commit instructions directly.
The attribute change events allow interception of when specific attributes on an object are modified. These events in-
clude AttributeEvents.set(), AttributeEvents.append(), and AttributeEvents.remove().
These events are extremely useful, particularly for per-object validation operations; however, it is often much more
convenient to use a “validator” hook, which uses these hooks behind the scenes; see Simple Validators for background
on this. The attribute events are also behind the mechanics of backreferences. An example illustrating use of attribute
events is in Attribute Instrumentation.
The sessionmaker factory generates new Session objects when called, creating them given the configu-
rational arguments established here.
e.g.:
# global scope
Session = sessionmaker(autoflush=False)
Any keyword arguments sent to the constructor itself will override the “configured” keywords:
Session = sessionmaker()
The class also includes a method configure(), which can be used to specify additional keyword arguments to
the factory, which will take effect for subsequent Session objects generated. This is usually used to associate
one or more Engine objects with an existing sessionmaker factory before it is first used:
# application starts
Session = sessionmaker()
# ... later
engine = create_engine('sqlite:///foo.db')
Session.configure(bind=engine)
sess = Session()
__call__(**local_kw)
Produce a new Session object using the configuration established in this sessionmaker.
In Python, the __call__ method is invoked on an object when it is “called” in the same way as a
function:
Session = sessionmaker()
session = Session() # invokes sessionmaker.__call__()
Session.configure(bind=create_engine('sqlite://'))
identity_key(*args, **kwargs)
inherited from the identity_key() method of _SessionClassMethods
Return an identity key.
This is an alias of util.identity_key().
object_session(instance)
inherited from the object_session() method of _SessionClassMethods
Return the Session to which an object belongs.
This is an alias of object_session().
class sqlalchemy.orm.session.Session(bind=None, autoflush=True, expire_on_commit=True,
_enable_transaction_accounting=True, autocom-
mit=False, twophase=False, weak_identity_map=True,
binds=None, extension=None, info=None,
query_cls=<class ‘sqlalchemy.orm.query.Query’>)
Bases: sqlalchemy.orm.session._SessionClassMethods
Manages persistence operations for ORM-mapped objects.
The Session’s usage paradigm is described at Using the Session.
__init__(bind=None, autoflush=True, expire_on_commit=True, _en-
able_transaction_accounting=True, autocommit=False, twophase=False,
weak_identity_map=True, binds=None, extension=None, info=None, query_cls=<class
‘sqlalchemy.orm.query.Query’>)
Construct a new Session.
See also the sessionmaker function which is used to generate a Session-producing callable with a
given set of arguments.
Parameters
Warning: The autocommit flag is not for general use, and if it is used, queries should
only be invoked within the span of a Session.begin() / Session.commit()
• autocommit –
pair. Executing queries outside of a demarcated transaction is a legacy mode of usage,
and can in some cases lead to concurrent connection checkouts.
Defaults to False. When True, the Session does not keep a persistent transaction run-
ning, and will acquire connections from the engine on an as-needed basis, returning them
immediately after their use. Flushes will begin and commit (or possibly rollback) their own
transaction if no transaction is present. When using this mode, the Session.begin()
method is used to explicitly start transactions.
See also:
Autocommit Mode
• autoflush – When True, all query operations will issue a flush() call to this
Session before proceeding. This is a convenience feature so that flush() need not
be called repeatedly in order for database queries to retrieve results. It’s typical that
autoflush is used in conjunction with autocommit=False. In this scenario, ex-
plicit calls to flush() are rarely needed; you usually only need to call commit()
(which flushes) to finalize changes.
• bind – An optional Engine or Connection to which this Session should be bound.
When specified, all SQL operations performed by this session will execute via this con-
nectable.
• binds –
An optional dictionary which contains more granular “bind” information than the
bind parameter provides. This dictionary can map individual :class‘.Table‘ instances
as well as Mapper instances to individual Engine or Connection objects. Op-
erations which proceed relative to a particular Mapper will consult this dictionary
for the direct Mapper instance as well as the mapper’s mapped_table attribute
in order to locate a connectable to use. The full resolution is described in the
Session.get_bind(). Usage looks like:
Session = sessionmaker(binds={
SomeMappedClass: create_engine('postgresql://engine1'),
somemapper: create_engine('postgresql://engine2'),
some_table: create_engine('postgresql://engine3'),
})
The bulk insert feature allows plain Python dictionaries to be used as the source of simple INSERT op-
erations which can be more easily grouped together into higher performing “executemany” operations.
Using dictionaries, there is no “history” or session state management features in use, reducing latency
when inserting large numbers of simple rows.
The values within the dictionaries as given are typically passed without modification into Core
Insert() constructs, after organizing the values within them across the tables to which the given map-
per is mapped.
New in version 1.0.0.
Warning: The bulk insert feature allows for a lower-latency INSERT of rows at the expense of most
other unit-of-work features. Features such as object management, relationship handling, and SQL
clause support are silently omitted in favor of raw INSERT of records.
Please read the list of caveats at Bulk Operations before using this method, and fully test and
confirm the functionality of all code developed using these systems.
Parameters
• mapper – a mapped class, or the actual Mapper object, representing the single kind
of object represented within the mapping list.
• mappings – a list of dictionaries, each one containing the state of the mapped row
to be inserted, in terms of the attribute names on the mapped class. If the mapping
refers to multiple tables, such as a joined-inheritance mapping, each dictionary must
contain all keys to be populated into all tables.
• return_defaults – when True, rows that are missing values which gen-
erate defaults, namely integer primary key defaults and sequences, will be in-
serted one at a time, so that the primary key value is available. In partic-
ular this will allow joined-inheritance and other multi-table mappings to insert
correctly without the need to provide primary key values ahead of time; how-
ever, Session.bulk_insert_mappings.return_defaults greatly re-
duces the performance gains of the method overall. If the rows to be inserted only
refer to a single table, then there is no reason this flag should be set as the returned
default information is not used.
See also:
Bulk Operations
Session.bulk_save_objects()
Session.bulk_update_mappings()
bulk_save_objects(objects, return_defaults=False, update_changed_only=True)
Perform a bulk save of the given list of objects.
The bulk save feature allows mapped objects to be used as the source of simple INSERT and UPDATE
operations which can be more easily grouped together into higher performing “executemany” operations;
the extraction of data from the objects is also performed using a lower-latency process that ignores whether
or not attributes have actually been modified in the case of UPDATEs, and also ignores SQL expressions.
The objects as given are not added to the session and no additional state is established on them, unless the
return_defaults flag is also set, in which case primary key attributes and server-side default values
will be populated.
New in version 1.0.0.
Warning: The bulk save feature allows for a lower-latency INSERT/UPDATE of rows at the expense
of most other unit-of-work features. Features such as object management, relationship handling, and
SQL clause support are silently omitted in favor of raw INSERT/UPDATES of records.
Please read the list of caveats at Bulk Operations before using this method, and fully test and
confirm the functionality of all code developed using these systems.
Parameters
• objects – a list of mapped object instances. The mapped objects are persisted as
is, and are not associated with the Session afterwards.
For each object, whether the object is sent as an INSERT or an UPDATE is dependent
on the same rules used by the Session in traditional operation; if the object has the
InstanceState.key attribute set, then the object is assumed to be “detached”
and will result in an UPDATE. Otherwise, an INSERT is used.
In the case of an UPDATE, statements are grouped based on which attributes
have changed, and are thus to be the subject of each SET clause. If
update_changed_only is False, then all attributes present within each object
are applied to the UPDATE statement, which may help in allowing the statements to
be grouped together into a larger executemany(), and will also reduce the overhead of
checking history on attributes.
• return_defaults – when True, rows that are missing values which gen-
erate defaults, namely integer primary key defaults and sequences, will be in-
serted one at a time, so that the primary key value is available. In partic-
ular this will allow joined-inheritance and other multi-table mappings to insert
correctly without the need to provide primary key values ahead of time; how-
ever, Session.bulk_save_objects.return_defaults greatly reduces
the performance gains of the method overall.
• update_changed_only – when True, UPDATE statements are rendered based
on those attributes in each state that have logged changes. When False, all attributes
present are rendered into the SET clause with the exception of primary key attributes.
See also:
Bulk Operations
Session.bulk_insert_mappings()
Session.bulk_update_mappings()
bulk_update_mappings(mapper, mappings)
Perform a bulk update of the given list of mapping dictionaries.
The bulk update feature allows plain Python dictionaries to be used as the source of simple UPDATE
operations which can be more easily grouped together into higher performing “executemany” operations.
Using dictionaries, there is no “history” or session state management features in use, reducing latency
when updating large numbers of simple rows.
New in version 1.0.0.
Warning: The bulk update feature allows for a lower-latency UPDATE of rows at the expense of
most other unit-of-work features. Features such as object management, relationship handling, and
SQL clause support are silently omitted in favor of raw UPDATES of records.
Please read the list of caveats at Bulk Operations before using this method, and fully test and
confirm the functionality of all code developed using these systems.
Parameters
• mapper – a mapped class, or the actual Mapper object, representing the single kind
of object represented within the mapping list.
• mappings – a list of dictionaries, each one containing the state of the mapped row
to be updated, in terms of the attribute names on the mapped class. If the mapping
refers to multiple tables, such as a joined-inheritance mapping, each dictionary may
contain keys corresponding to all tables. All those keys which are present and are not
part of the primary key are applied to the SET clause of the UPDATE statement; the
primary key values, which are required, are applied to the WHERE clause.
See also:
Bulk Operations
Session.bulk_insert_mappings()
Session.bulk_save_objects()
close()
Close this Session.
This clears all items and ends any transaction in progress.
If this session were created with autocommit=False, a new transaction is immediately begun. Note
that this new transaction does not use any connection resources until they are first needed.
close_all()
inherited from the close_all() method of _SessionClassMethods
Close all sessions in memory.
commit()
Flush pending changes and commit the current transaction.
If no transaction is in progress, this method raises an InvalidRequestError.
By default, the Session also expires all database loaded state on all ORM-managed attributes after
transaction commit. This so that subsequent operations load the most recent data from the database. This
behavior can be disabled using the expire_on_commit=False option to sessionmaker or the
Session constructor.
If a subtransaction is in effect (which occurs when begin() is called multiple times), the subtransaction
will be closed, and the next call to commit() will operate on the enclosing transaction.
When using the Session in its default mode of autocommit=False, a new transaction will be begun
immediately after the commit, but note that the newly begun transaction does not use any connection
resources until the first SQL is actually emitted.
See also:
Committing
connection(mapper=None, clause=None, bind=None, close_with_result=False, execu-
tion_options=None, **kw)
Return a Connection object corresponding to this Session object’s transactional state.
If this Session is configured with autocommit=False, either the Connection corresponding
to the current transaction is returned, or if no transaction is in progress, a new one is begun and the
Connection returned (note that no transactional state is established with the DBAPI until the first SQL
statement is emitted).
Alternatively, if this Session is configured with autocommit=True, an ad-hoc Connection is
returned using Engine.contextual_connect() on the underlying Engine.
Ambiguity in multi-bind or unbound Session objects can be resolved through any of the optional key-
word arguments. This ultimately makes usage of the get_bind() method for resolution.
Parameters
• bind – Optional Engine to be used as the bind. If this engine is already involved in
an ongoing transaction, that connection will be used. This argument takes precedence
over mapper, clause.
• mapper – Optional mapper() mapped class, used to identify the appropriate bind.
This argument takes precedence over clause.
• clause – A ClauseElement (i.e. select(), text(), etc.) which will be
used to locate a bind, if a bind cannot otherwise be identified.
• close_with_result – Passed to Engine.connect(), indicating the
Connection should be considered “single use”, automatically closing when the
first result set is closed. This flag only has an effect if this Session is configured
with autocommit=True and does not already have a transaction in progress.
• execution_options – a dictionary of execution options that will be passed to
Connection.execution_options(), when the connection is first procured
only. If the connection is already present within the Session, a warning is emitted
and the arguments are ignored.
New in version 0.9.9.
See also:
Setting Transaction Isolation Levels
• **kw – Additional keyword arguments are sent to get_bind(), allowing addi-
tional arguments to be passed to custom implementations of get_bind().
delete(instance)
Mark an instance as deleted.
The database delete operation occurs upon flush().
deleted
The set of all instances marked as ‘deleted’ within this Session
dirty
The set of all persistent instances considered dirty.
E.g.:
some_mapped_object in session.dirty
Instances are considered dirty when they were modified but not deleted.
Note that this ‘dirty’ calculation is ‘optimistic’; most attribute-setting or collection modification opera-
tions will mark an instance as ‘dirty’ and place it in this set, even if there is no net change to the attribute’s
value. At flush time, the value of each attribute is compared to its previously saved value, and if there’s
no net change, no SQL operation will occur (this is a more expensive operation so it’s only done at flush
time).
To check if an instance has actionable net changes to its attributes, use the Session.is_modified()
method.
enable_relationship_loading(obj)
Associate an object with this Session for related object loading.
Accesses of attributes mapped with relationship() will attempt to load a value from the database
using this Session as the source of connectivity. The values will be loaded based on foreign key
values present on this object - it follows that this functionality generally only works for many-to-one-
relationships.
The object will be attached to this session, but will not participate in any persistence operations; its state
for almost all purposes will remain either “transient” or “detached”, except for the case of relationship
loading.
Also note that backrefs will often not work as expected. Altering a relationship-bound attribute on the
target object may not fire off a backref event, if the effective value is what was already loaded from a
foreign-key-holding value.
The Session.enable_relationship_loading() method is similar to
the load_on_pending flag on relationship(). Unlike that flag,
Session.enable_relationship_loading() allows an object to remain transient while
still being able to load related items.
To make a transient object associated with a Session via
Session.enable_relationship_loading() pending, add it to the Session using
Session.add() normally.
Session.enable_relationship_loading() does not improve behavior when the ORM is used
normally - object references should be constructed at the object level, not at the foreign key level, so that
they are present in an ordinary way before flush() proceeds. This method is not intended for general use.
New in version 0.8.
See also:
load_on_pending at relationship() - this flag allows per-relationship loading of many-to-ones
on items that are pending.
execute(clause, params=None, mapper=None, bind=None, **kw)
Execute a SQL expression construct or string statement within the current transaction.
Returns a ResultProxy representing results of the statement execution, in the same manner as that of
an Engine or Connection.
E.g.:
result = session.execute(
user_table.select().where(user_table.c.id == 5)
)
execute() accepts any executable clause construct, such as select(), insert(), update(),
delete(), and text(). Plain SQL strings can be passed as well, which in the case of
Session.execute() only will be interpreted the same as if it were passed via a text() construct.
That is, the following usage:
result = session.execute(
"SELECT * FROM user WHERE id=:param",
{"param":5}
)
is equivalent to:
The second positional argument to Session.execute() is an optional parameter set. Similar to that
of Connection.execute(), whether this is passed as a single dictionary, or a list of dictionaries,
determines whether the DBAPI cursor’s execute() or executemany() is used to execute the state-
ment. An INSERT construct may be invoked for a single row:
result = session.execute(
users.insert(), {"id": 7, "name": "somename"})
The statement is executed within the current transactional context of this Session. The
Connection which is used to execute the statement can also be acquired directly by calling the
Session.connection() method. Both methods use a rule-based resolution scheme in order to de-
termine the Connection, which in the average case is derived directly from the “bind” of the Session
itself, and in other cases can be based on the mapper() and Table objects passed to the method; see
the documentation for Session.get_bind() for a full description of this scheme.
The Session.execute() method does not invoke autoflush.
The ResultProxy returned by the Session.execute() method is returned with the
“close_with_result” flag set to true; the significance of this flag is that if this Session is autocommit-
ting and does not have a transaction-dedicated Connection available, a temporary Connection is
established for the statement execution, which is closed (meaning, returned to the connection pool) when
the ResultProxy has consumed all available data. This applies only when the Session is configured
with autocommit=True and no transaction has been started.
Parameters
• clause – An executable statement (i.e. an Executable expression such as
expression.select()) or string SQL statement to be executed.
• params – Optional dictionary, or list of dictionaries, containing bound parameter
values. If a single dictionary, single-row execution occurs; if a list of dictionaries,
an “executemany” will be invoked. The keys in each dictionary must correspond to
parameter names present in the statement.
• mapper – Optional mapper() or mapped class, used to identify the appropriate
bind. This argument takes precedence over clause when locating a bind. See
Session.get_bind() for more details.
• bind – Optional Engine to be used as the bind. If this engine is already involved in
an ongoing transaction, that connection will be used. This argument takes precedence
over mapper and clause when locating a bind.
• **kw – Additional keyword arguments are sent to Session.get_bind() to al-
low extensibility of “bind” schemes.
See also:
expunge_all()
Remove all object instances from this Session.
This is equivalent to calling expunge(obj) on all objects in this Session.
flush(objects=None)
Flush all the object changes to the database.
Writes out all pending object creations, deletions and modifications to the database as INSERTs,
DELETEs, UPDATEs, etc. Operations are automatically ordered by the Session’s unit of work depen-
dency solver.
Database operations will be issued in the current transactional context and do not affect the state of the
transaction, unless an error occurs, in which case the entire transaction is rolled back. You may flush() as
often as you like within a transaction to move changes from Python to the database’s transaction buffer.
For autocommit Sessions with no active manual transaction, flush() will create a transaction on the fly
that surrounds the entire set of operations into the flush.
Parameters objects – Optional; restricts the flush operation to operate only on elements
that are in the given collection.
This feature is for an extremely narrow set of use cases where particular objects may need
to be operated upon before the full flush() occurs. It is not intended for general use.
get_bind(mapper=None, clause=None)
Return a “bind” to which this Session is bound.
The “bind” is usually an instance of Engine, except in the case where the Session has been explicitly
bound directly to a Connection.
For a multiply-bound or unbound Session, the mapper or clause arguments are used to determine
the appropriate bind to return.
Note that the “mapper” argument is usually present when Session.get_bind() is called via an ORM
operation such as a Session.query(), each individual INSERT/UPDATE/DELETE operation within
a Session.flush(), call, etc.
The order of resolution is:
1.if mapper given and session.binds is present, locate a bind based on mapper.
2.if clause given and session.binds is present, locate a bind based on Table objects found in the given
clause present in session.binds.
3.if session.bind is present, return that.
4.if clause given, attempt to return a bind linked to the MetaData ultimately associated with the
clause.
5.if mapper given, attempt to return a bind linked to the MetaData ultimately associated with the
Table or other selectable to which the mapper is mapped.
6.No bind can be found, UnboundExecutionError is raised.
Parameters
• mapper – Optional mapper() mapped class or instance of Mapper. The bind can
be derived from a Mapper first by consulting the “binds” map associated with this
Session, and secondly by consulting the MetaData associated with the Table to
which the Mapper is mapped for a bind.
• clause – A ClauseElement (i.e. select(), text(), etc.). If the mapper
argument is not present or could not produce a bind, the given expression construct
will be searched for a bound element, typically a Table associated with bound
MetaData.
identity_key(*args, **kwargs)
inherited from the identity_key() method of _SessionClassMethods
Return an identity key.
This is an alias of util.identity_key().
identity_map = None
A mapping of object identities to objects themselves.
Iterating through Session.identity_map.values() provides access to the full set of persistent
objects (i.e., those that have row identity) currently in the session.
See also:
identity_key() - helper function to produce the keys used in this dictionary.
info
A user-modifiable dictionary.
The initial value of this dictionary can be populated using the info argument to the Session constructor
or sessionmaker constructor or factory methods. The dictionary here is always local to this Session
and can be modified independently of all other Session objects.
New in version 0.9.0.
invalidate()
Close this Session, using connection invalidation.
This is a variant of Session.close() that will additionally ensure that the
Connection.invalidate() method will be called on all Connection objects. This can
be called when the database is known to be in a state where the connections are no longer safe to be used.
E.g.:
try:
sess = Session()
sess.add(User())
sess.commit()
except gevent.Timeout:
sess.invalidate()
raise
except:
sess.rollback()
raise
“Transaction mode” does not indicate whether or not actual database connection resources are in use; the
SessionTransaction object coordinates among zero or more actual database transactions, and starts
out with none, accumulating individual DBAPI connections as different data sources are used within its
scope. The best way to track when a particular Session has actually begun to use DBAPI resources
is to implement a listener using the SessionEvents.after_begin() method, which will deliver
both the Session as well as the target Connection to a user-defined event listener.
The “partial rollback” state refers to when an “inner” transaction, typically used during a flush, encoun-
ters an error and emits a rollback of the DBAPI connection. At this point, the Session is in “partial
rollback” and awaits for the user to call Session.rollback(), in order to close out the transaction
stack. It is in this “partial rollback” period that the is_active flag returns False. After the call to
Session.rollback(), the SessionTransaction is replaced with a new one and is_active
returns True again.
When a Session is used in autocommit=True mode, the SessionTransaction is only instan-
tiated within the scope of a flush call, or when Session.begin() is called. So is_active will
always be False outside of a flush or Session.begin() block in this mode, and will be True
within the Session.begin() block as long as it doesn’t enter “partial rollback” state.
From all the above, it follows that the only purpose to this flag is for application frameworks that wish
to detect is a “rollback” is necessary within a generic error handling routine, for Session objects that
would otherwise be in “partial rollback” mode. In a typical integration case, this is also not necessary as
it is standard practice to emit Session.rollback() unconditionally within the outermost exception
catch.
To track the transactional state of a Session fully, use event listeners, primar-
ily the SessionEvents.after_begin(), SessionEvents.after_commit(),
SessionEvents.after_rollback() and related events.
is_modified(instance, include_collections=True, passive=True)
Return True if the given instance has locally modified attributes.
This method retrieves the history for each instrumented attribute on the instance and performs a compari-
son of the current value to its previously committed value, if any.
It is in effect a more expensive and accurate version of checking for the given instance in the
Session.dirty collection; a full test for each attribute’s net “dirty” status is performed.
E.g.:
return session.is_modified(someobject)
Changed in version 0.8: When using SQLAlchemy 0.7 and earlier, the passive flag should always
be explicitly set to True, else SQL loads/autoflushes may proceed which can affect the modified state
itself: session.is_modified(someobject, passive=True). In 0.8 and above, the behavior
is corrected and this flag is ignored.
A few caveats to this method apply:
•Instances present in the Session.dirty collection may report False when tested with this
method. This is because the object may have received change events via attribute mutation, thus
placing it in Session.dirty, but ultimately the state is the same as that loaded from the database,
resulting in no net change here.
•Scalar attributes may not have recorded the previously set value when a new value was applied, if the
attribute was not loaded, or was expired, at the time the new value was received - in these cases, the
attribute is assumed to have a change, even if there is ultimately no net change against its database
value. SQLAlchemy in most cases does not need the “old” value when a set event occurs, so it skips
the expense of a SQL call if the old value isn’t present, based on the assumption that an UPDATE of
the scalar value is usually needed, and in those few cases where it isn’t, is less expensive on average
than issuing a defensive SELECT.
The “old” value is fetched unconditionally upon set only if the attribute container has the
active_history flag set to True. This flag is set typically for primary key attributes and
scalar object references that are not a simple many-to-one. To set this flag for any arbitrary mapped
column, use the active_history argument with column_property().
Parameters
• instance – mapped instance to be tested for pending changes.
• include_collections – Indicates if multivalued collections should be included
in the operation. Setting this to False is a way to detect only local-column based
properties (i.e. scalar columns or many-to-one foreign keys) that would result in an
UPDATE for this instance upon flush.
• passive – Changed in version 0.8: Ignored for backwards compatibility. When
using SQLAlchemy 0.7 and earlier, this flag should always be set to True.
merge(instance, load=True)
Copy the state of a given instance into a corresponding instance within this Session.
Session.merge() examines the primary key attributes of the source instance, and attempts to recon-
cile it with an instance of the same primary key in the session. If not found locally, it attempts to load
the object from the database based on primary key, and if none can be located, creates a new instance.
The state of each attribute on the source instance is then copied to the target instance. The resulting target
instance is then returned by the method; the original source instance is left unmodified, and un-associated
with the Session if not already.
This operation cascades to associated instances if the association is mapped with cascade="merge".
See Merging for a detailed discussion of merging.
Parameters
• instance – Instance to be merged.
• load – Boolean, when False, merge() switches into a “high performance” mode
which causes it to forego emitting history events as well as all database access. This
flag is used for cases such as transferring graphs of objects into a Session from a
second level cache, or to transfer just-loaded objects into the Session owned by a
worker thread or process without re-querying the database.
The load=False use case adds the caveat that the given object has to be in a “clean”
state, that is, has no pending changes to be flushed - even if the incoming object is de-
tached from any Session. This is so that when the merge operation populates local
attributes and cascades to related objects and collections, the values can be “stamped”
onto the target object as is, without generating any history or attribute events, and
without the need to reconcile the incoming data with any existing related objects or
collections that might not be loaded. The resulting objects from load=False are
always produced as “clean”, so it is only appropriate that the given objects should be
“clean” as well, else this suggests a mis-use of the method.
new
The set of all instances marked as ‘new’ within this Session.
no_autoflush
Return a context manager that disables autoflush.
e.g.:
with session.no_autoflush:
some_object = SomeClass()
session.add(some_object)
# won't autoflush
some_object.related_thing = session.query(SomeRelated).first()
Operations that proceed within the with: block will not be subject to flushes occurring upon query
access. This is useful when initializing a series of objects which involve existing database queries, where
the uncompleted object should not yet be flushed.
New in version 0.7.6.
object_session(instance)
inherited from the object_session() method of _SessionClassMethods
Return the Session to which an object belongs.
This is an alias of object_session().
prepare()
Prepare the current transaction in progress for two phase commit.
If no transaction is in progress, this method raises an InvalidRequestError.
Only root transactions of two phase sessions can be prepared. If the current transaction is not such, an
InvalidRequestError is raised.
prune()
Remove unreferenced instances cached in the identity map.
Deprecated since version 0.7: The non-weak-referencing identity map feature is no longer needed.
Note that this method is only meaningful if “weak_identity_map” is set to False. The default weak identity
map is self-pruning.
Removes any object in this Session’s identity map that is not referenced in user code, modified, new or
scheduled for deletion. Returns the number of objects pruned.
query(*entities, **kwargs)
Return a new Query object corresponding to this Session.
refresh(instance, attribute_names=None, lockmode=None)
Expire and refresh the attributes on the given instance.
A query will be issued to the database and all attributes will be refreshed with their current database value.
Lazy-loaded relational attributes will remain lazily loaded, so that the instance-wide refresh operation will
be followed immediately by the lazy load of that attribute.
Eagerly-loaded relational attributes will eagerly load within the single refresh operation.
Note that a highly isolated transaction will return the same values as were previously read in that same
transaction, regardless of changes in database state outside of that transaction - usage of refresh()
usually only makes sense if non-ORM SQL statement were emitted in the ongoing transaction, or if
autocommit mode is turned on.
Parameters
• attribute_names – optional. An iterable collection of string attribute names
indicating a subset of attributes to be refreshed.
• lockmode – Passed to the Query as used by with_lockmode().
See also:
Refreshing / Expiring - introductory material
Session.expire()
Session.expire_all()
rollback()
Rollback the current transaction in progress.
If no transaction is in progress, this method is a pass-through.
This method rolls back the current transaction or nested transaction regardless of subtransactions being
in effect. All subtransactions up to the first real transaction are closed. Subtransactions occur when
begin() is called multiple times.
See also:
Rolling Back
scalar(clause, params=None, mapper=None, bind=None, **kw)
Like execute() but return a scalar result.
transaction = None
The current active or inactive SessionTransaction.
class sqlalchemy.orm.session.SessionTransaction(session, parent=None, nested=False)
A Session-level transaction.
SessionTransaction is a mostly behind-the-scenes object not normally referenced directly by application
code. It coordinates among multiple Connection objects, maintaining a database transaction for each one
individually, committing or rolling them back all at once. It also provides optional two-phase commit behavior
which can augment this coordination operation.
The Session.transaction attribute of Session refers to the current SessionTransaction object
in use, if any.
A SessionTransaction is associated with a Session in its default mode of autocommit=False
immediately, associated with no database connections. As the Session is called upon to emit SQL on behalf
of various Engine or Connection objects, a corresponding Connection and associated Transaction
is added to a collection within the SessionTransaction object, becoming one of the connection/transaction
pairs maintained by the SessionTransaction.
The lifespan of the SessionTransaction ends when the Session.commit(),
Session.rollback() or Session.close() methods are called. At this point, the
SessionTransaction removes its association with its parent Session. A Session that is in
autocommit=False mode will create a new SessionTransaction to replace it immediately, whereas
a Session that’s in autocommit=True mode will remain without a SessionTransaction until the
Session.begin() method is called.
Another detail of SessionTransaction behavior is that it is capable of “nesting”. This means that the
Session.begin() method can be called while an existing SessionTransaction is already present,
producing a new SessionTransaction that temporarily replaces the parent SessionTransaction.
When a SessionTransaction is produced as nested, it assigns itself to the Session.transaction
attribute. When it is ended via Session.commit() or Session.rollback(), it restores its parent
SessionTransaction back onto the Session.transaction attribute. The behavior is effectively a
stack, where Session.transaction refers to the current head of the stack.
The purpose of this stack is to allow nesting of Session.rollback() or Session.commit()
calls in context with various flavors of Session.begin(). This nesting behavior applies to when
Session.begin_nested() is used to emit a SAVEPOINT transaction, and is also used to produce a so-
called “subtransaction” which allows a block of code to use a begin/rollback/commit sequence regardless of
whether or not its enclosing code block has begun a transaction. The flush() method, whether called explic-
itly or via autoflush, is the primary consumer of the “subtransaction” feature, in that it wishes to guarantee that
it works within in a transaction block regardless of whether or not the Session is in transactional mode when
the method is called.
See also:
Session.rollback()
Session.commit()
Session.begin()
Session.begin_nested()
Session.is_active
SessionEvents.after_commit()
SessionEvents.after_rollback()
SessionEvents.after_soft_rollback()
Session Utilites
sqlalchemy.orm.session.make_transient(instance)
Alter the state of the given instance so that it is transient.
The given mapped instance is assumed to be in the persistent or detached state. The function will remove its
association with any Session as well as its InstanceState.identity. The effect is that the object will
behave as though it were newly constructed, except retaining any attribute / collection values that were loaded
at the time of the call. The InstanceState.deleted flag is also reset if this object had been deleted as a
result of using Session.delete().
Warning: make_transient() does not “unexpire” or otherwise eagerly load ORM-mapped attributes
that are not currently loaded at the time the function is called. This includes attributes which:
•were expired via Session.expire()
•were expired as the natural effect of committing a session transaction, e.g. Session.commit()
•are normally lazy loaded but are not currently loaded
•are “deferred” via Deferred Column Loading and are not yet loaded
•were not present in the query which loaded this object, such as that which is common in joined table
inheritance and other scenarios.
After make_transient() is called, unloaded attributes such as those above will normally resolve to
the value None when accessed, or an empty collection for a collection-oriented attribute. As the object is
transient and un-associated with any database identity, it will no longer retrieve these values.
See also:
make_transient_to_detached()
sqlalchemy.orm.session.make_transient_to_detached(instance)
Make the given transient instance detached.
All attribute history on the given instance will be reset as though the instance were freshly loaded from a query.
Missing attributes will be marked as expired. The primary key attributes of the object, which are required, will
be made into the “key” of the instance.
The object can then be added to a session, or merged possibly with the load=False flag, at which point it will
look as if it were loaded that way, without emitting SQL.
This is a special use case function that differs from a normal call to Session.merge() in that a given
persistent state can be manufactured without any SQL calls.
New in version 0.9.5.
See also:
make_transient()
sqlalchemy.orm.session.object_session(instance)
Return the Session to which the given instance belongs.
This is essentially the same as the InstanceState.session accessor. See that attribute for details.
sqlalchemy.orm.util.was_deleted(object)
Return True if the given object was deleted within a session flush.
New in version 0.8.0.
These functions are provided by the SQLAlchemy attribute instrumentation API to provide a detailed interface for
dealing with instances, attribute values, and history. Some of them are useful when constructing event listener func-
tions, such as those described in ORM Events.
sqlalchemy.orm.util.object_state(instance)
Given an object, return the InstanceState associated with the object.
Raises sqlalchemy.orm.exc.UnmappedInstanceError if no mapping is configured.
Equivalent functionality is available via the inspect() function as:
inspect(instance)
A 3-tuple of added, unchanged and deleted values, representing the changes which have occurred on an instru-
mented attribute.
The easiest way to get a History object for a particular attribute on an object is to use the inspect()
function:
from sqlalchemy import inspect
hist = inspect(myobject).attrs.myattribute.history
Attribute Events
class sqlalchemy.orm.events.AttributeEvents
Bases: sqlalchemy.event.base.Events
Define events for object attributes.
These are typically defined on the class-bound descriptor for the target class.
e.g.:
from sqlalchemy import event
Listeners have the option to return a possibly modified version of the value, when the retval=True flag is
passed to listen():
def validate_phone(target, value, oldvalue, initiator):
"Strip non-numeric characters from a phone number"
A validation function like the above can also raise an exception such as ValueError to halt the operation.
Several modifiers are available to the listen() function.
Parameters
• active_history=False – When True, indicates that the “set” event would like
to receive the “old” value being replaced unconditionally, even if this requires fir-
ing off database loads. Note that active_history can also be set directly via
column_property() and relationship().
• propagate=False – When True, the listener function will be established not just for
the class attribute given, but for attributes of the same name on all current subclasses of
that class, as well as all future subclasses of that class, using an additional listener that
listens for instrumentation events.
• raw=False – When True, the “target” argument to the event will be the
InstanceState management object, rather than the mapped instance itself.
• retval=False – when True, the user-defined event listening must return the “value”
argument from the function. This gives the listening function the opportunity to change
the value that is ultimately used for a “set” or “append” event.
append(target, value, initiator)
Receive a collection append event.
Example argument forms:
from sqlalchemy import event
Parameters
• target – the object instance receiving the event. If the listener is registered with
raw=True, this will be the InstanceState object.
• value – the value being appended. If this listener is registered with retval=True,
the listener function must return this value, or a new value which replaces it.
This event is triggered for a collection-based attribute when a collection is replaced, that is:
u1.addresses.append(a1)
The mechanics of the event will typically include that the given collection is empty, even if it stored
objects while being replaced.
New in version 1.0.0: the AttributeEvents.init_collection() and
AttributeEvents.dispose_collection() events supersede the collection.linker
hook.
init_collection(target, collection, collection_adapter)
Receive a ‘collection init’ event.
Example argument forms:
from sqlalchemy import event
This event is triggered for a collection-based attribute, when the initial “empty collection” is first generated
for a blank attribute, as well as for when the collection is replaced with a new one, such as via a set event.
E.g., given that User.addresses is a relationship-based collection, the event is triggered here:
u1 = User()
u1.addresses.append(a1) # <- new collection
Parameters
• target – the object instance receiving the event. If the listener is registered with
raw=True, this will be the InstanceState object.
• collection – the new collection. This will always be generated from what was
specified as RelationshipProperty.collection_class, and will always
be empty.
• collection_adpater – the CollectionAdapter that will mediate internal
access to the collection.
Parameters
• target – the object instance receiving the event. If the listener is registered with
raw=True, this will be the InstanceState object.
• value – the value being removed.
• initiator – An instance of attributes.Event representing the initiation of
the event. May be modified from its original value by backref handlers in order to
control chained event propagation.
Changed in version 0.9.0: the initiator argument is now passed as a
attributes.Event object, and may be modified by backref handlers within a
chain of backref-linked events.
Returns No return value is defined for this event.
Parameters
• target – the object instance receiving the event. If the listener is registered with
raw=True, this will be the InstanceState object.
• value – the value being set. If this listener is registered with retval=True, the
listener function must return this value, or a new value which replaces it.
• oldvalue – the previous value being replaced. This may also be
the symbol NEVER_SET or NO_VALUE. If the listener is registered with
active_history=True, the previous value of the attribute will be loaded from
the database if the existing value is currently unloaded or expired.
• initiator – An instance of attributes.Event representing the initiation of
the event. May be modified from its original value by backref handlers in order to
control chained event propagation.
Changed in version 0.9.0: the initiator argument is now passed as a
attributes.Event object, and may be modified by backref handlers within a
chain of backref-linked events.
Returns if the event was registered with retval=True, the given value, or a new effective
value, should be returned.
Mapper Events
class sqlalchemy.orm.events.MapperEvents
Bases: sqlalchemy.event.base.Events
Define events specific to mappings.
e.g.:
from sqlalchemy import event
all cross-configurations (e.g. backrefs) will also have been made available for any mappers that were
pending. Also constrast to MapperEvents.before_configured(), which is invoked before the
series of mappers has been configured.
This event can only be applied to the Mapper class or mapper() function, and not to individual map-
pings or mapped classes. It is only invoked for all mappings as a whole:
from sqlalchemy.orm import mapper
@event.listens_for(mapper, "after_configured")
def go():
# ...
Theoretically this event is called once per application, but is actually called any time new mappers have
been affected by a orm.configure_mappers() call. If new mappings are constructed after existing
ones have already been used, this event will likely be called again. To ensure that a particular event is
only called once and no further, the once=True argument (new in 0.9.4) can be applied:
from sqlalchemy.orm import mapper
See also:
MapperEvents.mapper_configured()
MapperEvents.before_configured()
after_delete(mapper, connection, target)
Receive an object instance after a DELETE statement has been emitted corresponding to that instance.
Example argument forms:
from sqlalchemy import event
This event is used to emit additional SQL statements on the given connection as well as to perform
application specific bookkeeping related to a deletion event.
The event is often called for a batch of objects of the same class after their DELETE statements have been
emitted at once in a previous step.
Warning: Mapper-level flush events only allow very limited operations, on attributes local to the
row being operated upon only, as well as allowing any SQL to be emitted on the given Connection.
Please read fully the notes at Mapper-level Events for guidelines on using these methods; gener-
ally, the SessionEvents.before_flush() method should be preferred for general on-flush
changes.
Parameters
• mapper – the Mapper which is the target of this event.
• connection – the Connection being used to emit DELETE statements for this
instance. This provides a handle into the current transaction on the target database
specific to this instance.
• target – the mapped instance being deleted. If the event is configured with
raw=True, this will instead be the InstanceState state-management object as-
sociated with the instance.
Returns No return value is supported by this event.
See also:
Persistence Events
after_insert(mapper, connection, target)
Receive an object instance after an INSERT statement is emitted corresponding to that instance.
Example argument forms:
from sqlalchemy import event
This event is used to modify in-Python-only state on the instance after an INSERT occurs, as well as to
emit additional SQL statements on the given connection.
The event is often called for a batch of objects of the same class after their INSERT statements have been
emitted at once in a previous step. In the extremely rare case that this is not desirable, the mapper() can
be configured with batch=False, which will cause batches of instances to be broken up into individual
(and more poorly performing) event->persist->event steps.
Warning: Mapper-level flush events only allow very limited operations, on attributes local to the
row being operated upon only, as well as allowing any SQL to be emitted on the given Connection.
Please read fully the notes at Mapper-level Events for guidelines on using these methods; gener-
ally, the SessionEvents.before_flush() method should be preferred for general on-flush
changes.
Parameters
• mapper – the Mapper which is the target of this event.
• connection – the Connection being used to emit INSERT statements for this
instance. This provides a handle into the current transaction on the target database
specific to this instance.
• target – the mapped instance being persisted. If the event is configured with
raw=True, this will instead be the InstanceState state-management object as-
sociated with the instance.
Returns No return value is supported by this event.
See also:
Persistence Events
after_update(mapper, connection, target)
Receive an object instance after an UPDATE statement is emitted corresponding to that instance.
This event is used to modify in-Python-only state on the instance after an UPDATE occurs, as well as to
emit additional SQL statements on the given connection.
This method is called for all instances that are marked as “dirty”, even those which have no net changes to
their column-based attributes, and for which no UPDATE statement has proceeded. An object is marked
as dirty when any of its column-based attributes have a “set attribute” operation called or when any of its
collections are modified. If, at update time, no column-based attributes have any net changes, no UPDATE
statement will be issued. This means that an instance being sent to after_update() is not a guarantee
that an UPDATE statement has been issued.
To detect if the column-based attributes on the object have net changes, and therefore resulted
in an UPDATE statement, use object_session(instance).is_modified(instance,
include_collections=False).
The event is often called for a batch of objects of the same class after their UPDATE statements have been
emitted at once in a previous step. In the extremely rare case that this is not desirable, the mapper() can
be configured with batch=False, which will cause batches of instances to be broken up into individual
(and more poorly performing) event->persist->event steps.
Warning: Mapper-level flush events only allow very limited operations, on attributes local to the
row being operated upon only, as well as allowing any SQL to be emitted on the given Connection.
Please read fully the notes at Mapper-level Events for guidelines on using these methods; gener-
ally, the SessionEvents.before_flush() method should be preferred for general on-flush
changes.
Parameters
• mapper – the Mapper which is the target of this event.
• connection – the Connection being used to emit UPDATE statements for this
instance. This provides a handle into the current transaction on the target database
specific to this instance.
• target – the mapped instance being persisted. If the event is configured with
raw=True, this will instead be the InstanceState state-management object as-
sociated with the instance.
Returns No return value is supported by this event.
See also:
Persistence Events
before_configured()
Called before a series of mappers have been configured.
Example argument forms:
from sqlalchemy import event
@event.listens_for(mapper, "before_configured")
def go():
# ...
This event is used to emit additional SQL statements on the given connection as well as to perform
application specific bookkeeping related to a deletion event.
The event is often called for a batch of objects of the same class before their DELETE statements are
emitted at once in a later step.
Warning: Mapper-level flush events only allow very limited operations, on attributes local to the
row being operated upon only, as well as allowing any SQL to be emitted on the given Connection.
Please read fully the notes at Mapper-level Events for guidelines on using these methods; gener-
ally, the SessionEvents.before_flush() method should be preferred for general on-flush
changes.
Parameters
• mapper – the Mapper which is the target of this event.
• connection – the Connection being used to emit DELETE statements for this
instance. This provides a handle into the current transaction on the target database
specific to this instance.
• target – the mapped instance being deleted. If the event is configured with
raw=True, this will instead be the InstanceState state-management object as-
sociated with the instance.
Returns No return value is supported by this event.
See also:
Persistence Events
before_insert(mapper, connection, target)
Receive an object instance before an INSERT statement is emitted corresponding to that instance.
Example argument forms:
from sqlalchemy import event
This event is used to modify local, non-object related attributes on the instance before an INSERT occurs,
as well as to emit additional SQL statements on the given connection.
The event is often called for a batch of objects of the same class before their INSERT statements are
emitted at once in a later step. In the extremely rare case that this is not desirable, the mapper() can be
configured with batch=False, which will cause batches of instances to be broken up into individual
(and more poorly performing) event->persist->event steps.
Warning: Mapper-level flush events only allow very limited operations, on attributes local to the
row being operated upon only, as well as allowing any SQL to be emitted on the given Connection.
Please read fully the notes at Mapper-level Events for guidelines on using these methods; gener-
ally, the SessionEvents.before_flush() method should be preferred for general on-flush
changes.
Parameters
• mapper – the Mapper which is the target of this event.
• connection – the Connection being used to emit INSERT statements for this
instance. This provides a handle into the current transaction on the target database
specific to this instance.
• target – the mapped instance being persisted. If the event is configured with
raw=True, this will instead be the InstanceState state-management object as-
sociated with the instance.
Returns No return value is supported by this event.
See also:
Persistence Events
before_update(mapper, connection, target)
Receive an object instance before an UPDATE statement is emitted corresponding to that instance.
Example argument forms:
from sqlalchemy import event
This event is used to modify local, non-object related attributes on the instance before an UPDATE occurs,
as well as to emit additional SQL statements on the given connection.
This method is called for all instances that are marked as “dirty”, even those which have no net changes
to their column-based attributes. An object is marked as dirty when any of its column-based attributes
have a “set attribute” operation called or when any of its collections are modified. If, at update time, no
column-based attributes have any net changes, no UPDATE statement will be issued. This means that an
instance being sent to before_update() is not a guarantee that an UPDATE statement will be issued,
although you can affect the outcome here by modifying attributes so that a net change in value does exist.
To detect if the column-based attributes on the object have net changes, and will therefore gen-
erate an UPDATE statement, use object_session(instance).is_modified(instance,
include_collections=False).
The event is often called for a batch of objects of the same class before their UPDATE statements are
emitted at once in a later step. In the extremely rare case that this is not desirable, the mapper() can be
configured with batch=False, which will cause batches of instances to be broken up into individual
(and more poorly performing) event->persist->event steps.
Warning: Mapper-level flush events only allow very limited operations, on attributes local to the
row being operated upon only, as well as allowing any SQL to be emitted on the given Connection.
Please read fully the notes at Mapper-level Events for guidelines on using these methods; gener-
ally, the SessionEvents.before_flush() method should be preferred for general on-flush
changes.
Parameters
• mapper – the Mapper which is the target of this event.
• connection – the Connection being used to emit UPDATE statements for this
instance. This provides a handle into the current transaction on the target database
specific to this instance.
• target – the mapped instance being persisted. If the event is configured with
raw=True, this will instead be the InstanceState state-management object as-
sociated with the instance.
Returns No return value is supported by this event.
See also:
Persistence Events
instrument_class(mapper, class_)
Receive a class when the mapper is first constructed, before instrumentation is applied to the mapped
class.
Example argument forms:
from sqlalchemy import event
This event is the earliest phase of mapper construction. Most attributes of the mapper are not yet initial-
ized.
This listener can either be applied to the Mapper class overall, or to any un-mapped class which serves
as a base for classes that will be mapped (using the propagate=True flag):
Base = declarative_base()
Parameters
• mapper – the Mapper which is the target of this event.
• class_ – the mapped class.
mapper_configured(mapper, class_)
Called when a specific mapper has completed its own configuration within the scope of the
configure_mappers() call.
Example argument forms:
from sqlalchemy import event
Instance Events
class sqlalchemy.orm.events.InstanceEvents
Bases: sqlalchemy.event.base.Events
Define events specific to object lifecycle.
e.g.:
from sqlalchemy import event
Parameters
• propagate=False – When True, the event listener should be applied to all inheriting
classes as well as the class which is the target of this listener.
• raw=False – When True, the “target” argument passed to applicable event listener
functions will be the instance’s InstanceState management object, rather than the
mapped instance itself.
expire(target, attrs)
Receive an object instance after its attributes or some subset have been expired.
Example argument forms:
from sqlalchemy import event
‘keys’ is a list of attribute names. If None, the entire state was expired.
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• attrs – sequence of attribute names which were expired, or None if all attributes
were expired.
first_init(manager, cls)
Called when the first instance of a particular mapping is called.
Example argument forms:
from sqlalchemy import event
This event is called when the __init__ method of a class is called the first time for that
particular class. The event invokes before __init__ actually proceeds as well as before the
InstanceEvents.init() event is invoked.
init(target, args, kwargs)
Receive an instance when its constructor is called.
Example argument forms:
from sqlalchemy import event
This method is only called during a userland construction of an object, in conjunction with the object’s
constructor, e.g. its __init__ method. It is not called when an object is loaded from the database; see
the InstanceEvents.load() event in order to intercept a database load.
The event is called before the actual __init__ constructor of the object is called. The kwargs dictio-
nary may be modified in-place in order to affect what is passed to __init__.
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• args – positional arguments passed to the __init__ method. This is passed as a
tuple and is currently immutable.
• kwargs – keyword arguments passed to the __init__ method. This structure can
be altered in place.
See also:
InstanceEvents.init_failure()
InstanceEvents.load()
init_failure(target, args, kwargs)
Receive an instance when its constructor has been called, and raised an exception.
Example argument forms:
from sqlalchemy import event
This method is only called during a userland construction of an object, in conjunction with the object’s
constructor, e.g. its __init__ method. It is not called when an object is loaded from the database.
The event is invoked after an exception raised by the __init__ method is caught. After the event is
invoked, the original exception is re-raised outwards, so that the construction of the object still raises an
exception. The actual exception and stack trace raised should be present in sys.exc_info().
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• args – positional arguments that were passed to the __init__ method.
• kwargs – keyword arguments that were passed to the __init__ method.
See also:
InstanceEvents.init()
InstanceEvents.load()
load(target, context)
Receive an object instance after it has been created via __new__, and after initial attribute population
has occurred.
Example argument forms:
from sqlalchemy import event
This typically occurs when the instance is created based on incoming result rows, and is only called once
for that instance’s lifetime.
Note that during a result-row load, this method is called upon the first row received for this instance. Note
that some attributes and collections may or may not be loaded or even initialized, depending on what’s
present in the result rows.
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• context – the QueryContext corresponding to the current Query in progress.
This argument may be None if the load does not correspond to a Query, such as
during Session.merge().
See also:
InstanceEvents.init()
InstanceEvents.refresh()
pickle(target, state_dict)
Receive an object instance when its associated state is being pickled.
Example argument forms:
from sqlalchemy import event
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• state_dict – the dictionary returned by InstanceState.__getstate__,
containing the state to be pickled.
Contrast this to the InstanceEvents.load() method, which is invoked when the object is first
loaded from a query.
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• context – the QueryContext corresponding to the current Query in progress.
• attrs – sequence of attribute names which were populated, or None if all column-
mapped, non-deferred attributes were populated.
See also:
InstanceEvents.load()
refresh_flush(target, flush_context, attrs)
Receive an object instance after one or more attributes have been refreshed within the persistence of the
object.
Example argument forms:
from sqlalchemy import event
This event is the same as InstanceEvents.refresh() except it is invoked within the unit of work
flush process, and the values here typically come from the process of handling an INSERT or UPDATE,
such as via the RETURNING clause or from Python-side default values.
New in version 1.0.5.
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• flush_context – Internal UOWTransaction object which handles the details
of the flush.
• attrs – sequence of attribute names which were populated.
unpickle(target, state_dict)
Receive an object instance after its associated state has been unpickled.
Example argument forms:
from sqlalchemy import event
Parameters
• target – the mapped instance. If the event is configured with raw=True, this
will instead be the InstanceState state-management object associated with the
instance.
• state_dict – the dictionary sent to InstanceState.__setstate__, con-
taining the state dictionary which was pickled.
Session Events
class sqlalchemy.orm.events.SessionEvents
Bases: sqlalchemy.event.base.Events
Define events specific to Session lifecycle.
e.g.:
from sqlalchemy import event
from sqlalchemy.orm import sessionmaker
def my_before_commit(session):
print "before commit!"
Session = sessionmaker()
The listen() function will accept Session objects as well as the return result of sessionmaker() and
scoped_session().
Additionally, it accepts the Session class which will apply listeners to all Session instances globally.
after_attach(session, instance)
Execute after an instance is attached to a session.
Example argument forms:
from sqlalchemy import event
Note: As of 0.8, this event fires off after the item has been fully associated with the session, which
is different than previous releases. For event handlers that require the object not yet be part of session
state (such as handlers which may autoflush while the target object is not yet complete) consider the new
before_attach() event.
See also:
before_attach()
Object Lifecycle Events
after_begin(session, transaction, connection)
Execute after a transaction is begun on a connection
Example argument forms:
from sqlalchemy import event
Parameters
• session – The target Session.
• transaction – The SessionTransaction.
• connection – The Connection object which will be used for SQL statements.
See also:
before_commit()
after_commit()
after_transaction_create()
after_transaction_end()
after_bulk_delete(delete_context)
Execute after a bulk delete operation to the session.
Example argument forms:
from sqlalchemy import event
Changed in version 0.9: The after_bulk_delete event now accepts the arguments
delete_context. Listener functions which accept the previous argument signature(s) listed above
will be automatically adapted to the new signature.
This is called as a result of the Query.delete() method.
Parameters delete_context – a “delete context” object which contains details about the
update, including these attributes:
• session - the Session involved
• query -the Query object that this update operation was called upon.
• context The QueryContext object, corresponding to the invocation of an ORM
query.
• result the ResultProxy returned as a result of the bulk DELETE operation.
after_bulk_update(update_context)
Execute after a bulk update operation to the session.
Example argument forms:
from sqlalchemy import event
Changed in version 0.9: The after_bulk_update event now accepts the arguments
update_context. Listener functions which accept the previous argument signature(s) listed above
will be automatically adapted to the new signature.
This is called as a result of the Query.update() method.
Parameters update_context – an “update context” object which contains details about
the update, including these attributes:
• session - the Session involved
• query -the Query object that this update operation was called upon.
• context The QueryContext object, corresponding to the invocation of an ORM
query.
• result the ResultProxy returned as a result of the bulk UPDATE operation.
after_commit(session)
Execute after a commit has occurred.
Example argument forms:
from sqlalchemy import event
Note: The after_commit() hook is not per-flush, that is, the Session can emit SQL to the
database many times within the scope of a transaction. For interception of these events, use the
before_flush(), after_flush(), or after_flush_postexec() events.
Note: The Session is not in an active transaction when the after_commit() event is in-
voked, and therefore can not emit SQL. To emit SQL corresponding to every transaction, use the
before_commit() event.
See also:
before_commit()
after_begin()
after_transaction_create()
after_transaction_end()
after_flush(session, flush_context)
Execute after flush has completed, but before commit has been called.
Example argument forms:
from sqlalchemy import event
Note that the session’s state is still in pre-flush, i.e. ‘new’, ‘dirty’, and ‘deleted’ lists still show pre-flush
state as well as the history settings on instance attributes.
Parameters
• session – The target Session.
• flush_context – Internal UOWTransaction object which handles the details
of the flush.
See also:
before_flush()
after_flush_postexec()
Persistence Events
after_flush_postexec(session, flush_context)
Execute after flush has completed, and after the post-exec state occurs.
Example argument forms:
from sqlalchemy import event
This will be when the ‘new’, ‘dirty’, and ‘deleted’ lists are in their final state. An actual commit() may or
may not have occurred, depending on whether or not the flush started its own transaction or participated
in a larger transaction.
Parameters
• session – The target Session.
• flush_context – Internal UOWTransaction object which handles the details
of the flush.
See also:
before_flush()
after_flush()
Persistence Events
after_rollback(session)
Execute after a real DBAPI rollback has occurred.
Example argument forms:
from sqlalchemy import event
Note that this event only fires when the actual rollback against the database occurs - it does not fire
each time the Session.rollback() method is called, if the underlying DBAPI transaction has
already been rolled back. In many cases, the Session will not be in an “active” state during this
event, as the current transaction is not valid. To acquire a Session which is active after the outermost
rollback has proceeded, use the SessionEvents.after_soft_rollback() event, checking the
Session.is_active flag.
Parameters session – The target Session.
after_soft_rollback(session, previous_transaction)
Execute after any rollback has occurred, including “soft” rollbacks that don’t actually emit at the DBAPI
level.
Example argument forms:
from sqlalchemy import event
This corresponds to both nested and outer rollbacks, i.e. the innermost rollback that calls the DBAPI’s
rollback() method, as well as the enclosing rollback calls that only pop themselves from the transaction
stack.
The given Session can be used to invoke SQL and Session.query() operations after an outermost
rollback by first checking the Session.is_active flag:
@event.listens_for(Session, "after_soft_rollback")
def do_something(session, previous_transaction):
if session.is_active:
session.execute("select * from some_table")
Parameters
• session – The target Session.
• previous_transaction – The SessionTransaction transactional marker
object which was just closed. The current SessionTransaction for the given
Session is available via the Session.transaction attribute.
This event differs from after_begin() in that it occurs for each SessionTransaction over-
all, as opposed to when transactions are begun on individual database connections. It is also
invoked for nested transactions and subtransactions, and is always matched by a corresponding
after_transaction_end() event (assuming normal operation of the Session).
Parameters
• session – the target Session.
• transaction – the target SessionTransaction.
This event differs from after_commit() in that it corresponds to all SessionTransaction ob-
jects in use, including those for nested transactions and subtransactions, and is always matched by a
corresponding after_transaction_create() event.
Parameters
• session – the target Session.
• transaction – the target SessionTransaction.
New in version 0.8.
See also:
after_transaction_create()
before_attach(session, instance)
Execute before an instance is attached to a session.
Example argument forms:
from sqlalchemy import event
This is called before an add, delete or merge causes the object to be part of the session.
New in version 0.8.: Note that after_attach() now fires off after the item is part of the session.
before_attach() is provided for those cases where the item should not yet be part of the session
state.
See also:
after_attach()
Object Lifecycle Events
before_commit(session)
Execute before commit is called.
Note: The before_commit() hook is not per-flush, that is, the Session can emit SQL to
the database many times within the scope of a transaction. For interception of these events, use the
before_flush(), after_flush(), or after_flush_postexec() events.
See also:
after_commit()
after_begin()
after_transaction_create()
after_transaction_end()
before_flush(session, flush_context, instances)
Execute before flush process has started.
Example argument forms:
from sqlalchemy import event
Parameters
• session – The target Session.
• flush_context – Internal UOWTransaction object which handles the details
of the flush.
• instances – Usually None, this is the collection of objects which can be passed
to the Session.flush() method (note this usage is deprecated).
See also:
after_flush()
after_flush_postexec()
Persistence Events
Query Events
class sqlalchemy.orm.events.QueryEvents
Bases: sqlalchemy.event.base.Events
Represent events within the construction of a Query object.
The events here are intended to be used with an as-yet-unreleased inspection system for Query. Some very
basic operations are possible now, however the inspection system is intended to allow complex query manipula-
tions to be automated.
New in version 1.0.0.
before_compile(query)
Receive the Query object before it is composed into a core Select object.
Example argument forms:
from sqlalchemy import event
The event should normally be listened with the retval=True parameter set, so that the modified query
may be returned.
Instrumentation Events
The Python type builtin is also accepted as a target, which when used has the effect of events being emitted
for all classes.
Note the “propagate” flag here is defaulted to True, unlike the other class level events where it defaults to
False. This means that new subclasses will also be the subject of these events, when a listener is established
on a superclass.
Changed in version 0.8: - events here will emit based on comparing the incoming class to the type of class passed
to event.listen(). Previously, the event would fire for any class unconditionally regardless of what class
was sent for listening, despite documentation which stated the contrary.
attribute_instrument(cls, key, inst)
Example argument forms:
from sqlalchemy import event
Key ORM constructs, not otherwise covered in other sections, are listed here.
insp = inspect(some_mapped_object)
attr_state = insp.attrs.some_attribute
history
Return the current pre-flush change history for this attribute, via the History interface.
This method will not emit loader callables if the value of the attribute is unloaded.
See also:
AttributeState.load_history() - retrieve history using loader callables if the value is not
locally present.
attributes.get_history() - underlying function
load_history()
Return the current pre-flush change history for this attribute, via the History interface.
This method will emit loader callables if the value of the attribute is unloaded.
See also:
AttributeState.history
attributes.get_history() - underlying function
New in version 0.9.0.
loaded_value
The current value of this attribute as loaded from the database.
If the value has not been loaded, or is otherwise not present in the object’s dictionary, returns NO_VALUE.
value
Return the value of this attribute.
This operation is equivalent to accessing the object’s attribute directly or via getattr(), and will fire
off any pending loader callables if needed.
class sqlalchemy.orm.util.CascadeOptions
Bases: __builtin__.frozenset
Keeps track of the options sent to relationship().cascade
class sqlalchemy.orm.instrumentation.ClassManager(class_)
Bases: __builtin__.dict
tracks state information at the class level.
__le__
inherited from the __le__ attribute of dict
x.__le__(y) <==> x<=y
__lt__
inherited from the __lt__ attribute of dict
x.__lt__(y) <==> x<y
__ne__
inherited from the __ne__ attribute of dict
x.__ne__(y) <==> x!=y
clear() → None. Remove all items from D.
inherited from the clear() method of dict
copy() → a shallow copy of D
inherited from the copy() method of dict
dispose()
Dissasociate this manager from its class.
fromkeys(S[, v ]) → New dict with keys from S and values equal to v.
inherited from the fromkeys() method of dict
v defaults to None.
get(k[, d ]) → D[k] if k in D, else d. d defaults to None.
inherited from the get() method of dict
has_key(k) → True if D has a key k, else False
inherited from the has_key() method of dict
has_parent(state, key, optimistic=False)
TODO
items() → list of D’s (key, value) pairs, as 2-tuples
inherited from the items() method of dict
iteritems() → an iterator over the (key, value) items of D
inherited from the iteritems() method of dict
iterkeys() → an iterator over the keys of D
inherited from the iterkeys() method of dict
itervalues() → an iterator over the values of D
inherited from the itervalues() method of dict
keys() → list of D’s keys
inherited from the keys() method of dict
manage()
Mark this instance as the manager for its class.
original_init
x.__init__(...) initializes x; see help(type(x)) for signature
pop(k[, d ]) → v, remove specified key and return the corresponding value.
inherited from the pop() method of dict
If key is not found, d is returned if given, otherwise KeyError is raised
popitem() → (k, v), remove and return some (key, value) pair as a
inherited from the popitem() method of dict
2-tuple; but raise KeyError if D is empty.
setdefault(k[, d ]) → D.get(k,d), also set D[k]=d if k not in D
inherited from the setdefault() method of dict
state_getter()
Return a (instance) -> InstanceState callable.
“state getter” callables should raise either KeyError or AttributeError if no InstanceState could be found
for the instance.
unregister()
remove all instrumentation established by this ClassManager.
update([E ], **F) → None. Update D from dict/iterable E and F.
inherited from the update() method of dict
If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method,
does: for (k, v) in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]
values() → list of D’s values
inherited from the values() method of dict
viewitems() → a set-like object providing a view on D’s items
inherited from the viewitems() method of dict
viewkeys() → a set-like object providing a view on D’s keys
inherited from the viewkeys() method of dict
viewvalues() → an object providing a view on D’s values
inherited from the viewvalues() method of dict
class sqlalchemy.orm.properties.ColumnProperty(*columns, **kwargs)
Bases: sqlalchemy.orm.interfaces.StrategizedProperty
Describes an object attribute that corresponds to a table column.
Public constructor is the orm.column_property() function.
class Comparator(prop, parentmapper, adapt_to_entity=None)
Bases: sqlalchemy.util.langhelpers.MemoizedSlots,
sqlalchemy.orm.interfaces.PropComparator
Produce boolean, comparison, and other operators for ColumnProperty attributes.
See the documentation for PropComparator for a brief overview.
See also:
PropComparator
ColumnOperators
Redefining and Creating New Operators
TypeEngine.comparator_factory
__eq__(other)
inherited from the __eq__() method of ColumnOperators
Implement the == operator.
In a column context, produces the clause a = b. If the target is None, produces a IS NULL.
__le__(other)
inherited from the __le__() method of ColumnOperators
Implement the <= operator.
In a column context, produces the clause a <= b.
__lt__(other)
inherited from the __lt__() method of ColumnOperators
Implement the < operator.
desc()
inherited from the desc() method of ColumnOperators
Produce a desc() clause against the parent object.
distinct()
inherited from the distinct() method of ColumnOperators
Produce a distinct() clause against the parent object.
endswith(other, **kwargs)
inherited from the endswith() method of ColumnOperators
Implement the ‘endswith’ operator.
In a column context, produces the clause LIKE ’%<other>’
has(criterion=None, **kwargs)
inherited from the has() method of PropComparator
Return true if this element references a member which meets the given criterion.
The usual implementation of has() is RelationshipProperty.Comparator.has().
Parameters
• criterion – an optional ClauseElement formulated against the member class’
table or attributes.
• **kwargs – key/value pairs corresponding to member class attribute names which
will be compared via equality to the corresponding values.
ilike(other, escape=None)
inherited from the ilike() method of ColumnOperators
Implement the ilike operator.
In a column context, produces the clause a ILIKE other.
E.g.:
select([sometable]).where(sometable.c.column.ilike("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.ilike("foo/%bar", escape="/")
See also:
ColumnOperators.like()
in_(other)
inherited from the in_() method of ColumnOperators
Implement the in operator.
In a column context, produces the clause a IN other. “other” may be a tuple/list of column
expressions, or a select() construct.
is_(other)
inherited from the is_() method of ColumnOperators
Implement the IS operator.
Normally, IS is generated automatically when comparing to a value of None, which resolves to
NULL. However, explicit usage of IS may be desirable if comparing to boolean values on certain
platforms.
New in version 0.7.9.
See also:
ColumnOperators.isnot()
isnot(other)
inherited from the isnot() method of ColumnOperators
Implement the IS NOT operator.
Normally, IS NOT is generated automatically when comparing to a value of None, which resolves
to NULL. However, explicit usage of IS NOT may be desirable if comparing to boolean values on
certain platforms.
New in version 0.7.9.
See also:
ColumnOperators.is_()
like(other, escape=None)
inherited from the like() method of ColumnOperators
Implement the like operator.
In a column context, produces the clause a LIKE other.
E.g.:
select([sometable]).where(sometable.c.column.like("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.like("foo/%bar", escape="/")
See also:
ColumnOperators.ilike()
match(other, **kwargs)
inherited from the match() method of ColumnOperators
Implements a database-specific ‘match’ operator.
match() attempts to resolve to a MATCH-like function or operator provided by the backend.
Examples include:
•Postgresql - renders x @@ to_tsquery(y)
•MySQL - renders MATCH (x) AGAINST (y IN BOOLEAN MODE)
•Oracle - renders CONTAINS(x, y)
Parameters class_ – a class or mapper indicating that criterion will be against this
specific subclass.
produces:
somecolumn * 5
This function can also be used to make bitwise operators explicit. For example:
somecolumn.op('&')(0xff)
I.e. if this MapperProperty were named addresses, and the class to which it is mapped is User,
this sequence is possible:
>>> from sqlalchemy import inspect
>>> mapper = inspect(User)
>>> addresses_property = mapper.attrs.addresses
>>> addresses_property.class_attribute is User.addresses
True
>>> User.addresses.property is addresses_property
True
ColumnProperty.expression
Return the primary column or expression for this ColumnProperty.
ColumnProperty.extension_type = symbol(‘NOT_EXTENSION’)
ColumnProperty.init()
inherited from the init() method of MapperProperty
Called after all mappers are created to assemble relationships between mappers and perform other post-
mapper-creation initialization steps.
ColumnProperty.set_parent(parent, init)
inherited from the set_parent() method of MapperProperty
Set the parent mapper that references this MapperProperty.
This method is overridden by some subclasses to perform extra setup when the mapper is first known.
class sqlalchemy.orm.properties.ComparableProperty(comparator_factory, descrip-
tor=None, doc=None, info=None)
Bases: sqlalchemy.orm.descriptor_props.DescriptorProperty
Instruments a Python property for use in query expressions.
__init__(comparator_factory, descriptor=None, doc=None, info=None)
Construct a new ComparableProperty object.
This constructor is mirrored as a public API function; see comparable_property() for a full usage
and argument description.
class sqlalchemy.orm.descriptor_props.CompositeProperty(class_, *attrs, **kwargs)
Bases: sqlalchemy.orm.descriptor_props.DescriptorProperty
Defines a “composite” mapped attribute, representing a collection of columns as one attribute.
CompositeProperty is constructed using the composite() function.
See also:
check_modified()
return True if any InstanceStates present have been marked as ‘modified’.
class sqlalchemy.orm.base.InspectionAttr
A base class applied to all ORM objects that can be returned by the inspect() function.
The attributes defined here allow the usage of simple boolean checks to test basic facts about the object returned.
While the boolean checks here are basically the same as using the Python isinstance() function, the flags here
can be used without the need to import all of these classes, and also such that the SQLAlchemy class system
can change while leaving the flags here intact for forwards-compatibility.
extension_type = symbol(‘NOT_EXTENSION’)
The extension type, if any. Defaults to interfaces.NOT_EXTENSION
New in version 0.8.0.
See also:
HYBRID_METHOD
HYBRID_PROPERTY
ASSOCIATION_PROXY
is_aliased_class = False
True if this object is an instance of AliasedClass.
is_attribute = False
True if this object is a Python descriptor.
This can refer to one of many types. Usually a QueryableAttribute which handles attributes events
on behalf of a MapperProperty. But can also be an extension type such as AssociationProxy
or hybrid_property. The InspectionAttr.extension_type will refer to a constant identi-
fying the specific subtype.
See also:
Mapper.all_orm_descriptors
is_clause_element = False
True if this object is an instance of ClauseElement.
is_instance = False
True if this object is an instance of InstanceState.
is_mapper = False
True if this object is an instance of Mapper.
is_property = False
True if this object is an instance of MapperProperty.
is_selectable = False
Return True if this object is an instance of Selectable.
class sqlalchemy.orm.base.InspectionAttrInfo
Bases: sqlalchemy.orm.base.InspectionAttr
Adds the .info attribute to InspectionAttr.
The rationale for InspectionAttr vs. InspectionAttrInfo is that the former is compatible as a mixin
for classes that specify __slots__; this is essentially an implementation artifact.
info
Info dictionary associated with the object, allowing user-defined data to be associated with this
InspectionAttr.
The dictionary is generated when first accessed. Alternatively, it can be specified as a constructor argu-
ment to the column_property(), relationship(), or composite() functions.
New in version 0.8: Added support for .info to all MapperProperty subclasses.
Changed in version 1.0.0: MapperProperty.info is also available on extension types via the
InspectionAttrInfo.info attribute, so that it can apply to a wider variety of ORM and exten-
sion constructs.
See also:
QueryableAttribute.info
SchemaItem.info
class sqlalchemy.orm.state.InstanceState(obj, manager)
Bases: sqlalchemy.orm.base.InspectionAttr
tracks state information at the instance level.
The InstanceState is a key object used by the SQLAlchemy ORM in order to track the state of an object;
it is created the moment an object is instantiated, typically as a result of instrumentation which SQLAlchemy
applies to the __init__() method of the class.
InstanceState is also a semi-public object, available for runtime inspection as to the state of a mapped
instance, including information such as its current status within a particular Session and details about data on
individual attributes. The public API in order to acquire a InstanceState object is to use the inspect()
system:
>>> from sqlalchemy import inspect
>>> insp = inspect(some_mapped_object)
See also:
Runtime Inspection API
attrs
Return a namespace representing each attribute on the mapped object, including its current value and
history.
The returned object is an instance of AttributeState. This object allows inspection of the current
data within an attribute as well as attribute history since the last flush.
callables = ()
A namespace where a per-state loader callable can be associated.
In SQLAlchemy 1.0, this is only used for lazy loaders / deferred loaders that were set up via query option.
Previously, callables was used also to indicate expired attributes by storing a link to the InstanceState
itself in this dictionary. This role is now handled by the expired_attributes set.
detached
Return true if the object is detached.
See also:
Quickie Intro to Object States
dict
Return the instance dict used by the object.
Under normal circumstances, this is always synonymous with the __dict__ attribute of the mapped
object, unless an alternative instrumentation system has been configured.
In the case that the actual object has been garbage collected, this accessor returns a blank dictionary.
expired_attributes = None
The set of keys which are ‘expired’ to be loaded by the manager’s deferred scalar loader, assuming no
pending changes.
see also the unmodified collection which is intersected against this set when a refresh operation occurs.
has_identity
Return True if this object has an identity key.
This should always have the same value as the expression state.persistent or
state.detached.
identity
Return the mapped identity of the mapped object. This is the primary key identity as persisted by the
ORM which can always be passed directly to Query.get().
Returns None if the object has no primary key identity.
Note: An object which is transient or pending does not have a mapped identity until it is flushed, even if
its attributes include primary key values.
identity_key
Return the identity key for the mapped object.
This is the key used to locate the object within the Session.identity_map mapping. It contains the
identity as returned by identity within it.
mapper
Return the Mapper used for this mapepd object.
object
Return the mapped object represented by this InstanceState.
pending
Return true if the object is pending.
See also:
Quickie Intro to Object States
persistent
Return true if the object is persistent.
See also:
Quickie Intro to Object States
session
Return the owning Session for this instance, or None if none available.
Note that the result here can in some cases be different from that of obj in session; an object that’s
been deleted will report as not in session, however if the transaction is still in progress, this attribute
will still refer to that session. Only when the transaction is completed does the object become fully
detached under normal circumstances.
transient
Return true if the object is transient.
See also:
Quickie Intro to Object States
unloaded
Return the set of keys which do not have a loaded value.
This includes expired attributes and any other attribute that was never populated or modified.
unmodified
Return the set of keys which have no uncommitted changes
unmodified_intersection(keys)
Return self.unmodified.intersection(keys).
class sqlalchemy.orm.attributes.InstrumentedAttribute(class_, key, impl=None,
comparator=None, parenten-
tity=None, of_type=None)
Bases: sqlalchemy.orm.attributes.QueryableAttribute
Class bound instrumented attribute which adds basic descriptor methods.
See QueryableAttribute for a description of most features.
__delete__(instance)
__get__(instance, owner)
__set__(instance, value)
sqlalchemy.orm.interfaces.MANYTOONE = symbol(‘MANYTOONE’)
Indicates the many-to-one direction for a relationship().
This symbol is typically used by the internals but may be exposed within certain API features.
sqlalchemy.orm.interfaces.MANYTOMANY = symbol(‘MANYTOMANY’)
Indicates the many-to-many direction for a relationship().
This symbol is typically used by the internals but may be exposed within certain API features.
class sqlalchemy.orm.interfaces.MapperProperty
Bases: sqlalchemy.orm.base._MappedAttribute, sqlalchemy.orm.base.InspectionAttr,
sqlalchemy.util.langhelpers.MemoizedSlots
Represent a particular class attribute mapped by Mapper.
The most common occurrences of MapperProperty are the mapped Column, which is represented in a map-
ping as an instance of ColumnProperty, and a reference to another class produced by relationship(),
represented in the mapping as an instance of RelationshipProperty.
info
Info dictionary associated with the object, allowing user-defined data to be associated with this
InspectionAttr.
The dictionary is generated when first accessed. Alternatively, it can be specified as a constructor argu-
ment to the column_property(), relationship(), or composite() functions.
New in version 0.8: Added support for .info to all MapperProperty subclasses.
Changed in version 1.0.0: InspectionAttr.info moved from MapperProperty so that it can
apply to a wider variety of ORM and extension constructs.
See also:
QueryableAttribute.info
SchemaItem.info
cascade = frozenset([])
The set of ‘cascade’ attribute names.
This collection is checked before the ‘cascade_iterator’ method is called.
The collection typically only applies to a RelationshipProperty.
I.e. if this MapperProperty were named addresses, and the class to which it is mapped is User,
this sequence is possible:
>>> from sqlalchemy import inspect
>>> mapper = inspect(User)
>>> addresses_property = mapper.attrs.addresses
>>> addresses_property.class_attribute is User.addresses
True
>>> User.addresses.property is addresses_property
True
post_instrument_class(mapper)
Perform instrumentation adjustments that need to occur after init() has completed.
The given Mapper is the Mapper invoking the operation, which may not be the same Mapper as self.parent
in an inheritance scenario; however, Mapper will always at least be a sub-mapper of self.parent.
This method is typically used by StrategizedProperty, which delegates it to LoaderStrat-
egy.init_class_attribute() to perform final setup on the class-bound InstrumentedAttribute.
set_parent(parent, init)
Set the parent mapper that references this MapperProperty.
This method is overridden by some subclasses to perform extra setup when the mapper is first known.
setup(context, entity, path, adapter, **kwargs)
Called by Query for the purposes of constructing a SQL statement.
Each MapperProperty associated with the target mapper processes the statement referenced by the query
context, adding columns and/or criterion as appropriate.
sqlalchemy.orm.interfaces.NOT_EXTENSION = symbol(‘NOT_EXTENSION’)
Symbol indicating an InspectionAttr that’s not part of sqlalchemy.ext.
Is assigned to the InspectionAttr.extension_type attibute.
sqlalchemy.orm.interfaces.ONETOMANY = symbol(‘ONETOMANY’)
Indicates the one-to-many direction for a relationship().
This symbol is typically used by the internals but may be exposed within certain API features.
class sqlalchemy.orm.interfaces.PropComparator(prop, parentmapper,
adapt_to_entity=None)
Bases: sqlalchemy.sql.operators.ColumnOperators
Defines SQL operators for MapperProperty objects.
SQLAlchemy allows for operators to be redefined at both the Core and ORM level. PropComparator
is the base class of operator redefinition for ORM-level operations, including those of ColumnProperty,
RelationshipProperty, and CompositeProperty.
Note: With the advent of Hybrid properties introduced in SQLAlchemy 0.7, as well as Core-level operator
redefinition in SQLAlchemy 0.8, the use case for user-defined PropComparator instances is extremely rare.
See Hybrid Attributes as well as Redefining and Creating New Operators.
class MyColumnComparator(ColumnProperty.Comparator):
def __eq__(self, other):
return self.__clause_element__() == other
class MyRelationshipComparator(RelationshipProperty.Comparator):
def any(self, expression):
"define the 'any' operation"
# ...
class MyCompositeComparator(CompositeProperty.Comparator):
def __gt__(self, other):
"redefine the 'greater than' operation"
class SomeMappedClass(Base):
some_column = column_property(Column("some_column", String),
comparator_factory=MyColumnComparator)
some_relationship = relationship(SomeOtherClass,
comparator_factory=MyRelationshipComparator)
some_composite = composite(
Column("a", String), Column("b", String),
comparator_factory=MyCompositeComparator
)
Note that for column-level operator redefinition, it’s usually simpler to define the operators at the Core level,
using the TypeEngine.comparator_factory attribute. See Redefining and Creating New Operators for
more detail.
See also:
ColumnProperty.Comparator
RelationshipProperty.Comparator
CompositeProperty.Comparator
ColumnOperators
Redefining and Creating New Operators
TypeEngine.comparator_factory
__eq__(other)
inherited from the __eq__() method of ColumnOperators
Implement the == operator.
In a column context, produces the clause a = b. If the target is None, produces a IS NULL.
__le__(other)
inherited from the __le__() method of ColumnOperators
Implement the <= operator.
In a column context, produces the clause a <= b.
__lt__(other)
inherited from the __lt__() method of ColumnOperators
Implement the < operator.
In a column context, produces the clause a < b.
__ne__(other)
inherited from the __ne__() method of ColumnOperators
Implement the != operator.
In a column context, produces the clause a != b. If the target is None, produces a IS NOT NULL.
adapt_to_entity(adapt_to_entity)
Return a copy of this PropComparator which will use the given AliasedInsp to produce corresponding
expressions.
adapter
Produce a callable that adapts column expressions to suit an aliased version of this comparator.
any(criterion=None, **kwargs)
Return true if this collection contains any member that meets the given criterion.
The usual implementation of any() is RelationshipProperty.Comparator.any().
Parameters
• criterion – an optional ClauseElement formulated against the member class’ ta-
ble or attributes.
• **kwargs – key/value pairs corresponding to member class attribute names which
will be compared via equality to the corresponding values.
asc()
inherited from the asc() method of ColumnOperators
Produce a asc() clause against the parent object.
between(cleft, cright, symmetric=False)
inherited from the between() method of ColumnOperators
Produce a between() clause against the parent object, given the lower and upper range.
collate(collation)
inherited from the collate() method of ColumnOperators
Produce a collate() clause against the parent object, given the collation string.
concat(other)
inherited from the concat() method of ColumnOperators
Implement the ‘concat’ operator.
In a column context, produces the clause a || b, or uses the concat() operator on MySQL.
contains(other, **kwargs)
inherited from the contains() method of ColumnOperators
Implement the ‘contains’ operator.
In a column context, produces the clause LIKE ’%<other>%’
desc()
inherited from the desc() method of ColumnOperators
Produce a desc() clause against the parent object.
distinct()
inherited from the distinct() method of ColumnOperators
Produce a distinct() clause against the parent object.
endswith(other, **kwargs)
inherited from the endswith() method of ColumnOperators
Implement the ‘endswith’ operator.
In a column context, produces the clause LIKE ’%<other>’
has(criterion=None, **kwargs)
Return true if this element references a member which meets the given criterion.
The usual implementation of has() is RelationshipProperty.Comparator.has().
Parameters
• criterion – an optional ClauseElement formulated against the member class’ ta-
ble or attributes.
• **kwargs – key/value pairs corresponding to member class attribute names which
will be compared via equality to the corresponding values.
ilike(other, escape=None)
inherited from the ilike() method of ColumnOperators
Implement the ilike operator.
In a column context, produces the clause a ILIKE other.
E.g.:
select([sometable]).where(sometable.c.column.ilike("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.ilike("foo/%bar", escape="/")
See also:
ColumnOperators.like()
in_(other)
inherited from the in_() method of ColumnOperators
Implement the in operator.
In a column context, produces the clause a IN other. “other” may be a tuple/list of column expres-
sions, or a select() construct.
is_(other)
inherited from the is_() method of ColumnOperators
Implement the IS operator.
Normally, IS is generated automatically when comparing to a value of None, which resolves to NULL.
However, explicit usage of IS may be desirable if comparing to boolean values on certain platforms.
New in version 0.7.9.
See also:
ColumnOperators.isnot()
isnot(other)
inherited from the isnot() method of ColumnOperators
Implement the IS NOT operator.
Normally, IS NOT is generated automatically when comparing to a value of None, which resolves to
NULL. However, explicit usage of IS NOT may be desirable if comparing to boolean values on certain
platforms.
New in version 0.7.9.
See also:
ColumnOperators.is_()
like(other, escape=None)
inherited from the like() method of ColumnOperators
Implement the like operator.
In a column context, produces the clause a LIKE other.
E.g.:
select([sometable]).where(sometable.c.column.like("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.like("foo/%bar", escape="/")
See also:
ColumnOperators.ilike()
match(other, **kwargs)
inherited from the match() method of ColumnOperators
Implements a database-specific ‘match’ operator.
match() attempts to resolve to a MATCH-like function or operator provided by the backend. Examples
include:
•Postgresql - renders x @@ to_tsquery(y)
•MySQL - renders MATCH (x) AGAINST (y IN BOOLEAN MODE)
•Oracle - renders CONTAINS(x, y)
•other backends may provide special implementations.
•Backends without any special implementation will emit the operator as “MATCH”. This is compat-
ible with SQlite, for example.
notilike(other, escape=None)
inherited from the notilike() method of ColumnOperators
implement the NOT ILIKE operator.
Parameters class_ – a class or mapper indicating that criterion will be against this specific
subclass.
produces:
somecolumn * 5
This function can also be used to make bitwise operators explicit. For example:
somecolumn.op('&')(0xff)
Parameters
• op – Operator callable.
• *other – the ‘other’ side of the operation. Will be a single scalar for most opera-
tions.
• **kwargs – modifiers. These may be passed by special operators such as
ColumnOperators.contains().
__eq__(other)
Implement the == operator.
In a many-to-one context, such as:
MyClass.some_prop == <some object>
•Compared to a scalar one-to-many, will produce a clause that compares the target columns in
the parent to the given target.
•Compared to a scalar many-to-many, an alias of the association table will be rendered as well,
forming a natural join that is part of the main body of the query. This will not work for queries
that go beyond simple AND conjunctions of comparisons, such as those which use OR. Use
explicit joins, outerjoins, or has() in conjunction with not_() for more comprehensive non-
many-to-one scalar membership tests.
•Comparisons against None given in a one-to-many or many-to-many context produce an EX-
ISTS clause.
adapter
inherited from the adapter attribute of PropComparator
Produce a callable that adapts column expressions to suit an aliased version of this comparator.
any(criterion=None, **kwargs)
Produce an expression that tests a collection against particular criterion, using EXISTS.
An expression like:
session.query(MyClass).filter(
MyClass.somereference.any(SomeRelated.x==2)
)
Because any() uses a correlated subquery, its performance is not nearly as good when compared
against large target tables as that of using a join.
any() is particularly useful for testing for empty collections:
session.query(MyClass).filter(
~MyClass.somereference.any()
)
will produce:
SELECT * FROM my_table WHERE
NOT EXISTS (SELECT 1 FROM related WHERE
related.my_id=my_table.id)
any() is only valid for collections, i.e. a relationship() that has uselist=True. For
scalar references, use has().
asc()
inherited from the asc() method of ColumnOperators
Produce a asc() clause against the parent object.
between(cleft, cright, symmetric=False)
inherited from the between() method of ColumnOperators
Produce a between() clause against the parent object, given the lower and upper range.
collate(collation)
inherited from the collate() method of ColumnOperators
Produce a collate() clause against the parent object, given the collation string.
concat(other)
inherited from the concat() method of ColumnOperators
Implement the ‘concat’ operator.
In a column context, produces the clause a || b, or uses the concat() operator on MySQL.
contains(other, **kwargs)
Return a simple expression that tests a collection for containment of a particular item.
contains() is only valid for a collection, i.e. a relationship() that implements one-to-
many or many-to-many with uselist=True.
When used in a simple one-to-many context, an expression like:
MyClass.contains(other)
Where <some id> is the value of the foreign key attribute on other which refers to the primary
key of its parent object. From this it follows that contains() is very useful when used with
simple one-to-many operations.
For many-to-many operations, the behavior of contains() has more caveats. The association
table will be rendered in the statement, producing an “implicit” join, that is, includes multiple tables
in the FROM clause which are equated in the WHERE clause:
query(MyClass).filter(MyClass.contains(other))
Where <some id> would be the primary key of other. From the above, it is clear that
contains() will not work with many-to-many collections when used in queries that move beyond
simple AND conjunctions, such as multiple contains() expressions joined by OR. In such cases
subqueries or explicit “outer joins” will need to be used instead. See any() for a less-performant
alternative using EXISTS, or refer to Query.outerjoin() as well as Querying with Joins for
more details on constructing outer joins.
desc()
inherited from the desc() method of ColumnOperators
Produce a desc() clause against the parent object.
distinct()
inherited from the distinct() method of ColumnOperators
Produce a distinct() clause against the parent object.
endswith(other, **kwargs)
inherited from the endswith() method of ColumnOperators
Implement the ‘endswith’ operator.
In a column context, produces the clause LIKE ’%<other>’
has(criterion=None, **kwargs)
Produce an expression that tests a scalar reference against particular criterion, using EXISTS.
An expression like:
session.query(MyClass).filter(
MyClass.somereference.has(SomeRelated.x==2)
)
Because has() uses a correlated subquery, its performance is not nearly as good when compared
against large target tables as that of using a join.
has() is only valid for scalar references, i.e. a relationship() that has uselist=False.
For collection references, use any().
ilike(other, escape=None)
inherited from the ilike() method of ColumnOperators
Implement the ilike operator.
In a column context, produces the clause a ILIKE other.
E.g.:
select([sometable]).where(sometable.c.column.ilike("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.ilike("foo/%bar", escape="/")
See also:
ColumnOperators.like()
in_(other)
Produce an IN clause - this is not implemented for relationship()-based attributes at this time.
is_(other)
inherited from the is_() method of ColumnOperators
Implement the IS operator.
Normally, IS is generated automatically when comparing to a value of None, which resolves to
NULL. However, explicit usage of IS may be desirable if comparing to boolean values on certain
platforms.
New in version 0.7.9.
See also:
ColumnOperators.isnot()
isnot(other)
inherited from the isnot() method of ColumnOperators
Implement the IS NOT operator.
Normally, IS NOT is generated automatically when comparing to a value of None, which resolves
to NULL. However, explicit usage of IS NOT may be desirable if comparing to boolean values on
certain platforms.
New in version 0.7.9.
See also:
ColumnOperators.is_()
like(other, escape=None)
inherited from the like() method of ColumnOperators
Implement the like operator.
In a column context, produces the clause a LIKE other.
E.g.:
select([sometable]).where(sometable.c.column.like("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.like("foo/%bar", escape="/")
See also:
ColumnOperators.ilike()
mapper
The target Mapper referred to by this RelationshipProperty.Comparator.
This is the “target” or “remote” side of the relationship().
match(other, **kwargs)
inherited from the match() method of ColumnOperators
Implements a database-specific ‘match’ operator.
match() attempts to resolve to a MATCH-like function or operator provided by the backend.
Examples include:
•Postgresql - renders x @@ to_tsquery(y)
•MySQL - renders MATCH (x) AGAINST (y IN BOOLEAN MODE)
•Oracle - renders CONTAINS(x, y)
•other backends may provide special implementations.
•Backends without any special implementation will emit the operator as “MATCH”. This is
compatible with SQlite, for example.
notilike(other, escape=None)
inherited from the notilike() method of ColumnOperators
implement the NOT ILIKE operator.
This is equivalent to using negation with ColumnOperators.ilike(), i.e. ~x.ilike(y).
New in version 0.8.
See also:
ColumnOperators.ilike()
notin_(other)
inherited from the notin_() method of ColumnOperators
implement the NOT IN operator.
This is equivalent to using negation with ColumnOperators.in_(), i.e. ~x.in_(y).
New in version 0.8.
See also:
ColumnOperators.in_()
notlike(other, escape=None)
inherited from the notlike() method of ColumnOperators
implement the NOT LIKE operator.
This is equivalent to using negation with ColumnOperators.like(), i.e. ~x.like(y).
New in version 0.8.
See also:
ColumnOperators.like()
nullsfirst()
inherited from the nullsfirst() method of ColumnOperators
Produce a nullsfirst() clause against the parent object.
nullslast()
inherited from the nullslast() method of ColumnOperators
Produce a nullslast() clause against the parent object.
of_type(cls)
Produce a construct that represents a particular ‘subtype’ of attribute for the parent class.
Currently this is usable in conjunction with Query.join() and Query.outerjoin().
op(opstring, precedence=0, is_comparison=False)
inherited from the op() method of Operators
produce a generic operator function.
e.g.:
somecolumn.op("*")(5)
produces:
somecolumn * 5
This function can also be used to make bitwise operators explicit. For example:
somecolumn.op('&')(0xff)
Parameters
• op – Operator callable.
• *other – the ‘other’ side of the operation. Will be a single scalar for most opera-
tions.
• **kwargs – modifiers. These may be passed by special operators such as
ColumnOperators.contains().
startswith(other, **kwargs)
inherited from the startswith() method of ColumnOperators
Implement the startwith operator.
In a column context, produces the clause LIKE ’<other>%’
RelationshipProperty.__init__(argument, secondary=None, primaryjoin=None, sec-
ondaryjoin=None, foreign_keys=None, uselist=None,
order_by=False, backref=None, back_populates=None,
post_update=False, cascade=False, extension=None,
viewonly=False, lazy=True, collection_class=None,
passive_deletes=False, passive_updates=True,
remote_side=None, enable_typechecks=True,
join_depth=None, comparator_factory=None,
single_parent=False, innerjoin=False, dis-
tinct_target_key=None, doc=None, active_history=False,
cascade_backrefs=True, load_on_pending=False,
bake_queries=True, strategy_class=None, _lo-
cal_remote_pairs=None, query_class=None, info=None)
Construct a new RelationshipProperty object.
This constructor is mirrored as a public API function; see relationship() for a full usage and argu-
ment description.
RelationshipProperty.cascade
Return the current cascade setting for this RelationshipProperty.
RelationshipProperty.class_attribute
inherited from the class_attribute attribute of MapperProperty
Return the class-bound descriptor corresponding to this MapperProperty.
This is basically a getattr() call:
return getattr(self.parent.class_, self.key)
I.e. if this MapperProperty were named addresses, and the class to which it is mapped is User,
this sequence is possible:
>>> from sqlalchemy import inspect
>>> mapper = inspect(User)
>>> addresses_property = mapper.attrs.addresses
>>> addresses_property.class_attribute is User.addresses
True
>>> User.addresses.property is addresses_property
True
RelationshipProperty.extension_type = symbol(‘NOT_EXTENSION’)
RelationshipProperty.init()
inherited from the init() method of MapperProperty
Called after all mappers are created to assemble relationships between mappers and perform other post-
mapper-creation initialization steps.
RelationshipProperty.mapper
Return the targeted Mapper for this RelationshipProperty.
This is a lazy-initializing static attribute.
RelationshipProperty.set_parent(parent, init)
inherited from the set_parent() method of MapperProperty
Set the parent mapper that references this MapperProperty.
This method is overridden by some subclasses to perform extra setup when the mapper is first known.
RelationshipProperty.table
Return the selectable linked to this RelationshipProperty object’s target Mapper.
Deprecated since version 0.7: Use .target
class sqlalchemy.orm.descriptor_props.SynonymProperty(name, map_column=None,
descriptor=None, compara-
tor_factory=None, doc=None,
info=None)
Bases: sqlalchemy.orm.descriptor_props.DescriptorProperty
__init__(name, map_column=None, descriptor=None, comparator_factory=None, doc=None,
info=None)
Construct a new SynonymProperty object.
This constructor is mirrored as a public API function; see synonym() for a full usage and argument
description.
cascade_iterator(type_, state, visited_instances=None, halt_on=None)
inherited from the cascade_iterator() method of MapperProperty
Iterate through instances related to the given instance for a particular ‘cascade’, starting with this Map-
perProperty.
Return an iterator3-tuples (instance, mapper, state).
Note that the ‘cascade’ collection on this MapperProperty is checked first for the given type before cas-
cade_iterator is called.
This method typically only applies to RelationshipProperty.
class_attribute
inherited from the class_attribute attribute of MapperProperty
Return the class-bound descriptor corresponding to this MapperProperty.
This is basically a getattr() call:
return getattr(self.parent.class_, self.key)
I.e. if this MapperProperty were named addresses, and the class to which it is mapped is User,
this sequence is possible:
>>> from sqlalchemy import inspect
>>> mapper = inspect(User)
>>> addresses_property = mapper.attrs.addresses
>>> addresses_property.class_attribute is User.addresses
True
>>> User.addresses.property is addresses_property
True
do_init()
inherited from the do_init() method of MapperProperty
Perform subclass-specific initialization post-mapper-creation steps.
This is a template method called by the MapperProperty object’s init() method.
extension_type = symbol(‘NOT_EXTENSION’)
init()
inherited from the init() method of MapperProperty
Called after all mappers are created to assemble relationships between mappers and perform other post-
mapper-creation initialization steps.
merge(session, source_state, source_dict, dest_state, dest_dict, load, _recursive)
inherited from the merge() method of MapperProperty
Merge the attribute represented by this MapperProperty from source to destination object.
post_instrument_class(mapper)
inherited from the post_instrument_class() method of MapperProperty
Perform instrumentation adjustments that need to occur after init() has completed.
The given Mapper is the Mapper invoking the operation, which may not be the same Mapper as self.parent
in an inheritance scenario; however, Mapper will always at least be a sub-mapper of self.parent.
This method is typically used by StrategizedProperty, which delegates it to LoaderStrat-
egy.init_class_attribute() to perform final setup on the class-bound InstrumentedAttribute.
setup(context, entity, path, adapter, **kwargs)
inherited from the setup() method of MapperProperty
Called by Query for the purposes of constructing a SQL statement.
Each MapperProperty associated with the target mapper processes the statement referenced by the query
context, adding columns and/or criterion as appropriate.
class sqlalchemy.orm.query.QueryContext(query)
class sqlalchemy.orm.attributes.QueryableAttribute(class_, key, impl=None, compara-
tor=None, parententity=None,
of_type=None)
Bases: sqlalchemy.orm.base._MappedAttribute, sqlalchemy.orm.base.InspectionAttr,
sqlalchemy.orm.interfaces.PropComparator
Base class for descriptor objects that intercept attribute events on behalf of a MapperProperty object. The
actual MapperProperty is accessible via the QueryableAttribute.property attribute.
See also:
InstrumentedAttribute
MapperProperty
Mapper.all_orm_descriptors
Mapper.attrs
__eq__(other)
inherited from the __eq__() method of ColumnOperators
Implement the == operator.
In a column context, produces the clause a = b. If the target is None, produces a IS NULL.
__le__(other)
inherited from the __le__() method of ColumnOperators
Implement the <= operator.
In a column context, produces the clause a <= b.
__lt__(other)
inherited from the __lt__() method of ColumnOperators
Implement the < operator.
In a column context, produces the clause a < b.
__ne__(other)
inherited from the __ne__() method of ColumnOperators
Implement the != operator.
In a column context, produces the clause a != b. If the target is None, produces a IS NOT NULL.
adapter
inherited from the adapter attribute of PropComparator
Produce a callable that adapts column expressions to suit an aliased version of this comparator.
any(criterion=None, **kwargs)
inherited from the any() method of PropComparator
Return true if this collection contains any member that meets the given criterion.
The usual implementation of any() is RelationshipProperty.Comparator.any().
Parameters
• criterion – an optional ClauseElement formulated against the member class’ ta-
ble or attributes.
• **kwargs – key/value pairs corresponding to member class attribute names which
will be compared via equality to the corresponding values.
asc()
inherited from the asc() method of ColumnOperators
Produce a asc() clause against the parent object.
between(cleft, cright, symmetric=False)
inherited from the between() method of ColumnOperators
Produce a between() clause against the parent object, given the lower and upper range.
collate(collation)
inherited from the collate() method of ColumnOperators
Produce a collate() clause against the parent object, given the collation string.
concat(other)
inherited from the concat() method of ColumnOperators
Implement the ‘concat’ operator.
In a column context, produces the clause a || b, or uses the concat() operator on MySQL.
contains(other, **kwargs)
inherited from the contains() method of ColumnOperators
Implement the ‘contains’ operator.
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.ilike("foo/%bar", escape="/")
See also:
ColumnOperators.like()
in_(other)
inherited from the in_() method of ColumnOperators
Implement the in operator.
In a column context, produces the clause a IN other. “other” may be a tuple/list of column expres-
sions, or a select() construct.
info
Return the ‘info’ dictionary for the underlying SQL element.
The behavior here is as follows:
•If the attribute is a column-mapped property, i.e. ColumnProperty, which is mapped directly
to a schema-level Column object, this attribute will return the SchemaItem.info dictionary
associated with the core-level Column object.
•If the attribute is a ColumnProperty but is mapped to any other kind of SQL expression other
than a Column, the attribute will refer to the MapperProperty.info dictionary associated
directly with the ColumnProperty, assuming the SQL expression itself does not have its own
.info attribute (which should be the case, unless a user-defined SQL construct has defined one).
•If the attribute refers to any other kind of MapperProperty, including
RelationshipProperty, the attribute will refer to the MapperProperty.info dic-
tionary associated with that MapperProperty.
•To access the MapperProperty.info dictionary of the MapperProperty uncondition-
ally, including for a ColumnProperty that’s associated directly with a schema.Column,
the attribute can be referred to using QueryableAttribute.property attribute, as
MyClass.someattribute.property.info.
New in version 0.8.0.
See also:
SchemaItem.info
MapperProperty.info
is_(other)
inherited from the is_() method of ColumnOperators
Implement the IS operator.
Normally, IS is generated automatically when comparing to a value of None, which resolves to NULL.
However, explicit usage of IS may be desirable if comparing to boolean values on certain platforms.
New in version 0.7.9.
See also:
ColumnOperators.isnot()
isnot(other)
inherited from the isnot() method of ColumnOperators
Implement the IS NOT operator.
Normally, IS NOT is generated automatically when comparing to a value of None, which resolves to
NULL. However, explicit usage of IS NOT may be desirable if comparing to boolean values on certain
platforms.
New in version 0.7.9.
See also:
ColumnOperators.is_()
like(other, escape=None)
inherited from the like() method of ColumnOperators
Implement the like operator.
In a column context, produces the clause a LIKE other.
E.g.:
select([sometable]).where(sometable.c.column.like("%foobar%"))
Parameters
• other – expression to be compared
• escape – optional escape character, renders the ESCAPE keyword, e.g.:
somecolumn.like("foo/%bar", escape="/")
See also:
ColumnOperators.ilike()
match(other, **kwargs)
inherited from the match() method of ColumnOperators
Implements a database-specific ‘match’ operator.
match() attempts to resolve to a MATCH-like function or operator provided by the backend. Examples
include:
•Postgresql - renders x @@ to_tsquery(y)
•MySQL - renders MATCH (x) AGAINST (y IN BOOLEAN MODE)
•Oracle - renders CONTAINS(x, y)
•other backends may provide special implementations.
•Backends without any special implementation will emit the operator as “MATCH”. This is compat-
ible with SQlite, for example.
notilike(other, escape=None)
inherited from the notilike() method of ColumnOperators
implement the NOT ILIKE operator.
This is equivalent to using negation with ColumnOperators.ilike(), i.e. ~x.ilike(y).
New in version 0.8.
See also:
ColumnOperators.ilike()
notin_(other)
inherited from the notin_() method of ColumnOperators
implement the NOT IN operator.
This is equivalent to using negation with ColumnOperators.in_(), i.e. ~x.in_(y).
New in version 0.8.
See also:
ColumnOperators.in_()
notlike(other, escape=None)
inherited from the notlike() method of ColumnOperators
implement the NOT LIKE operator.
This is equivalent to using negation with ColumnOperators.like(), i.e. ~x.like(y).
produces:
somecolumn * 5
This function can also be used to make bitwise operators explicit. For example:
somecolumn.op('&')(0xff)
property
Return the MapperProperty associated with this QueryableAttribute.
Return values here will commonly be instances of ColumnProperty or RelationshipProperty.
startswith(other, **kwargs)
inherited from the startswith() method of ColumnOperators
Implement the startwith operator.
In a column context, produces the clause LIKE ’<other>%’
class sqlalchemy.orm.session.UOWTransaction(session)
filter_states_for_dep(dep, states)
Filter the given list of InstanceStates to those relevant to the given DependencyProcessor.
finalize_flush_changes()
mark processed objects as clean / deleted after a successful flush().
this method is called within the flush() method after the execute() method has succeeded and the transac-
tion has been committed.
get_attribute_history(state, key, passive=symbol(‘PASSIVE_NO_INITIALIZE’))
facade to attributes.get_state_history(), including caching of results.
is_deleted(state)
return true if the given state is marked as deleted within this uowtransaction.
remove_state_actions(state)
remove pending actions for a state from the uowtransaction.
The true meaning of this exception is simply that no row exists for the primary key identifier associated with
a persistent object. The row may have been deleted, or in some cases the primary key updated to a new value,
outside of the ORM’s management of the target object.
exception sqlalchemy.orm.exc.ObjectDereferencedError
An operation cannot complete due to an object being garbage collected.
exception sqlalchemy.orm.exc.StaleDataError
An operation encountered database state that is unaccounted for.
Conditions which cause this to happen include:
•A flush may have attempted to update or delete rows and an unexpected number of rows were matched
during the UPDATE or DELETE statement. Note that when version_id_col is used, rows in UPDATE or
DELETE statements are also matched against the current known version identifier.
•A mapped object with version_id_col was refreshed, and the version number coming back from the
database does not match that of the object itself.
•A object is detached from its parent object, however the object was previously attached to a different
parent identity which was garbage collected, and a decision cannot be made if the new parent was really
the most recent “parent”.
New in version 0.7.4.
exception sqlalchemy.orm.exc.UnmappedClassError(cls, msg=None)
An mapping operation was requested for an unknown class.
exception sqlalchemy.orm.exc.UnmappedColumnError
Mapping operation was requested on an unknown column.
exception sqlalchemy.orm.exc.UnmappedError
Base for exceptions that involve expected mappings not present.
exception sqlalchemy.orm.exc.UnmappedInstanceError(obj, msg=None)
An mapping operation was requested for an unknown instance.
This section describes the class-based ORM event interface which first existed in SQLAlchemy 0.1, which progressed
with more kinds of events up until SQLAlchemy 0.5. The non-ORM analogue is described at Deprecated Event
Interfaces.
Deprecated since version 0.7: As of SQLAlchemy 0.7, the new event system described in Events replaces the exten-
sion/proxy/listener system, providing a consistent interface to all events without the need for subclassing.
Mapper Events
class sqlalchemy.orm.interfaces.MapperExtension
Base implementation for Mapper event hooks.
New extension classes subclass MapperExtension and are specified using the extension mapper() argu-
ment, which is a single MapperExtension or a list of such:
class MyExtension(MapperExtension):
def before_insert(self, mapper, connection, instance):
print "instance %s before insert !" % instance
A single mapper can maintain a chain of MapperExtension objects. When a particular mapping event
occurs, the corresponding method on each MapperExtension is invoked serially, and each method has the
ability to halt the chain from proceeding further:
m = mapper(User, users_table, extension=[ext1, ext2, ext3])
Each MapperExtension method returns the symbol EXT_CONTINUE by default. This symbol generally
means “move to the next MapperExtension for processing”. For methods that return objects like translated
rows or new object instances, EXT_CONTINUE means the result of the method should be ignored. In some
cases it’s required for a default mapper activity to be performed, such as adding a new instance to a result list.
The symbol EXT_STOP has significance within a chain of MapperExtension objects that the chain will be
stopped when this symbol is returned. Like EXT_CONTINUE, it also has additional significance in some cases
that a default mapper activity will not be performed.
after_delete(mapper, connection, instance)
Receive an object instance after that instance is deleted.
The return value is only significant within the MapperExtension chain; the parent mapper’s behavior
isn’t modified by this method.
after_insert(mapper, connection, instance)
Receive an object instance after that instance is inserted.
The return value is only significant within the MapperExtension chain; the parent mapper’s behavior
isn’t modified by this method.
after_update(mapper, connection, instance)
Receive an object instance after that instance is updated.
The return value is only significant within the MapperExtension chain; the parent mapper’s behavior
isn’t modified by this method.
before_delete(mapper, connection, instance)
Receive an object instance before that instance is deleted.
Note that no changes to the overall flush plan can be made here; and manipulation of the Session will
not have the desired effect. To manipulate the Session within an extension, use SessionExtension.
The return value is only significant within the MapperExtension chain; the parent mapper’s behavior
isn’t modified by this method.
before_insert(mapper, connection, instance)
Receive an object instance before that instance is inserted into its table.
This is a good place to set up primary key values and such that aren’t handled otherwise.
Column-based attributes can be modified within this method which will result in the new value being in-
serted. However no changes to the overall flush plan can be made, and manipulation of the Session will
not have the desired effect. To manipulate the Session within an extension, use SessionExtension.
The return value is only significant within the MapperExtension chain; the parent mapper’s behavior
isn’t modified by this method.
Session Events
class sqlalchemy.orm.interfaces.SessionExtension
Base implementation for Session event hooks.
Subclasses may be installed into a Session (or sessionmaker) using the extension keyword argument:
from sqlalchemy.orm.interfaces import SessionExtension
class MySessionExtension(SessionExtension):
def before_commit(self, session):
print "before commit!"
Session = sessionmaker(extension=MySessionExtension())
The same SessionExtension instance can be used with any number of sessions.
after_attach(session, instance)
Execute after an instance is attached to a session.
This is called after an add, delete or merge.
after_begin(session, transaction, connection)
Execute after a transaction is begun on a connection
transaction is the SessionTransaction. This method is called after an engine level transaction is begun on
a connection.
after_bulk_delete(session, query, query_context, result)
Execute after a bulk delete operation to the session.
This is called after a session.query(...).delete()
query is the query object that this delete operation was called on. query_context was the query context
object. result is the result object returned from the bulk operation.
after_bulk_update(session, query, query_context, result)
Execute after a bulk update operation to the session.
This is called after a session.query(...).update()
query is the query object that this update operation was called on. query_context was the query context
object. result is the result object returned from the bulk operation.
after_commit(session)
Execute after a commit has occurred.
Note that this may not be per-flush if a longer running transaction is ongoing.
after_flush(session, flush_context)
Execute after flush has completed, but before commit has been called.
Note that the session’s state is still in pre-flush, i.e. ‘new’, ‘dirty’, and ‘deleted’ lists still show pre-flush
state as well as the history settings on instance attributes.
after_flush_postexec(session, flush_context)
Execute after flush has completed, and after the post-exec state occurs.
This will be when the ‘new’, ‘dirty’, and ‘deleted’ lists are in their final state. An actual commit() may or
may not have occurred, depending on whether or not the flush started its own transaction or participated
in a larger transaction.
after_rollback(session)
Execute after a rollback has occurred.
Note that this may not be per-flush if a longer running transaction is ongoing.
before_commit(session)
Execute right before commit is called.
Note that this may not be per-flush if a longer running transaction is ongoing.
before_flush(session, flush_context, instances)
Execute before flush process has started.
instances is an optional list of objects which were passed to the flush() method.
Attribute Events
class sqlalchemy.orm.interfaces.AttributeExtension
Base implementation for AttributeImpl event hooks, events that fire upon attribute mutations in user code.
AttributeExtension is used to listen for set, remove, and append events on individual mapped at-
tributes. It is established on an individual mapped attribute using the extension argument, available on
column_property(), relationship(), and others:
from sqlalchemy.orm.interfaces import AttributeExtension
from sqlalchemy.orm import mapper, relationship, column_property
class MyAttrExt(AttributeExtension):
def append(self, state, value, initiator):
print "append event !"
return value
Note that the AttributeExtension methods append() and set() need to return the value parameter.
The returned value is used as the effective value, and allows the extension to change what is ultimately persisted.
AttributeExtension is assembled within the descriptors associated with a mapped class.
active_history = True
indicates that the set() method would like to receive the ‘old’ value, even if it means firing lazy callables.
Note that active_history can also be set directly via column_property() and
relationship().
SQLAlchemy has a variety of ORM extensions available, which add additional functionality to the core behavior.
The extensions build almost entirely on public core and ORM APIs and users should be encouraged to read their source
code to further their understanding of their behavior. In particular the “Horizontal Sharding”, “Hybrid Attributes”, and
“Mutation Tracking” extensions are very succinct.
associationproxy is used to create a read/write view of a target attribute across a relationship. It essentially con-
ceals the usage of a “middle” attribute between two endpoints, and can be used to cherry-pick fields from a collection
of related objects or to reduce the verbosity of using the association object pattern. Applied creatively, the association
proxy allows the construction of sophisticated collections and dictionary views of virtually any geometry, persisted to
the database using standard, transparently configured relational patterns.
Consider a many-to-many mapping between two classes, User and Keyword. Each User can have any number of
Keyword objects, and vice-versa (the many-to-many pattern is described at Many To Many):
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
kw = relationship("Keyword", secondary=lambda: userkeywords_table)
class Keyword(Base):
__tablename__ = 'keyword'
id = Column(Integer, primary_key=True)
keyword = Column('keyword', String(64))
Reading and manipulating the collection of “keyword” strings associated with User requires traversal from each
collection element to the .keyword attribute, which can be awkward:
The association_proxy is applied to the User class to produce a “view” of the kw relationship, which only
exposes the string value of .keyword associated with each Keyword object:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
kw = relationship("Keyword", secondary=lambda: userkeywords_table)
We can now reference the .keywords collection as a listing of strings, which is both readable and writable. New
Keyword objects are created for us transparently:
The proxy functions by operating upon the underlying mapped attribute or collection in response to operations, and
changes made via the proxy are immediately apparent in the mapped attribute, as well as vice versa. The underlying
attribute remains fully accessible.
When first accessed, the association proxy performs introspection operations on the target collection so that its be-
havior corresponds correctly. Details such as if the locally proxied attribute is a collection (as is typical) or a scalar
reference, as well as if the collection acts like a set, list, or dictionary is taken into account, so that the proxy should
act just like the underlying collection or attribute does.
When a list append() event (or set add(), dictionary __setitem__(), or scalar assignment event) is intercepted by the
association proxy, it instantiates a new instance of the “intermediary” object using its constructor, passing as a single
argument the given value. In our example above, an operation like:
user.keywords.append('cheese inspector')
user.kw.append(Keyword('cheese inspector'))
The example works here because we have designed the constructor for Keyword to accept a single positional argu-
ment, keyword. For those cases where a single-argument constructor isn’t feasible, the association proxy’s creational
behavior can be customized using the creator argument, which references a callable (i.e. Python function) that will
produce a new object instance given the singular argument. Below we illustrate this using a lambda as is typical:
class User(Base):
# ...
The creator function accepts a single argument in the case of a list- or set- based collection, or a scalar attribute. In
the case of a dictionary-based collection, it accepts two arguments, “key” and “value”. An example of this is below in
Proxying to Dictionary Based Collections.
The “association object” pattern is an extended form of a many-to-many relationship, and is described at Association
Object. Association proxies are useful for keeping “association objects” out the way during regular use.
Suppose our userkeywords table above had additional columns which we’d like to map explicitly, but in most
cases we don’t require direct access to these attributes. Below, we illustrate a new mapping which introduces the
UserKeyword class, which is mapped to the userkeywords table illustrated earlier. This class adds an additional
column special_key, a value which we occasionally want to access, but not in the usual case. We create an
association proxy on the User class called keywords, which will bridge the gap from the user_keywords
collection of User to the .keyword attribute present on each UserKeyword:
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
class UserKeyword(Base):
__tablename__ = 'user_keyword'
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)
special_key = Column(String(50))
class Keyword(Base):
__tablename__ = 'keyword'
id = Column(Integer, primary_key=True)
keyword = Column('keyword', String(64))
def __repr__(self):
return 'Keyword(%s)' % repr(self.keyword)
With the above configuration, we can operate upon the .keywords collection of each User object, and the usage of
UserKeyword is concealed:
>>> user.user_keywords.append(UserKeyword(Keyword('its_heavy')))
The UserKeyword association object has two attributes here which are populated; the .keyword attribute is pop-
ulated directly as a result of passing the Keyword object as the first argument. The .user argument is then assigned
as the UserKeyword object is appended to the User.user_keywords collection, where the bidirectional re-
lationship configured between User.user_keywords and UserKeyword.user results in a population of the
UserKeyword.user attribute. The special_key argument above is left at its default value of None.
For those cases where we do want special_key to have a value, we create the UserKeyword object explicitly.
Below we assign all three attributes, where the assignment of .user has the effect of the UserKeyword being
appended to the User.user_keywords collection:
The association proxy returns to us a collection of Keyword objects represented by all these operations:
>>> user.keywords
[Keyword('new_from_blammo'), Keyword('its_big'), Keyword('its_heavy'), Keyword('its_wood')]
The association proxy can proxy to dictionary based collections as well. SQLAlchemy mappings usually use the
attribute_mapped_collection() collection type to create dictionary collections, as well as the extended
techniques described in Custom Dictionary-Based Collections.
The association proxy adjusts its behavior when it detects the usage of a dictionary-based collection. When new values
are added to the dictionary, the association proxy instantiates the intermediary object by passing two arguments to the
creation function instead of one, the key and the value. As always, this creation function defaults to the constructor of
the intermediary class, and can be customized using the creator argument.
Below, we modify our UserKeyword example such that the User.user_keywords collection will now be
mapped using a dictionary, where the UserKeyword.special_key argument will be used as the key for the
dictionary. We then apply a creator argument to the User.keywords proxy so that these values are assigned
appropriately when new elements are added to the dictionary:
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
UserKeyword(special_key=k, keyword=v)
)
class UserKeyword(Base):
__tablename__ = 'user_keyword'
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)
special_key = Column(String)
class Keyword(Base):
__tablename__ = 'keyword'
id = Column(Integer, primary_key=True)
keyword = Column('keyword', String(64))
def __repr__(self):
return 'Keyword(%s)' % repr(self.keyword)
>>> print(user.keywords)
{'sk1': Keyword('kw1'), 'sk2': Keyword('kw2')}
Given our previous examples of proxying from relationship to scalar attribute, proxying across an association object,
and proxying dictionaries, we can combine all three techniques together to give User a keywords dictionary that
deals strictly with the string value of special_key mapped to the string keyword. Both the UserKeyword and
Keyword classes are entirely concealed. This is achieved by building an association proxy on User that refers to an
association proxy present on UserKeyword:
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
class UserKeyword(Base):
__tablename__ = 'user_keyword'
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
keyword_id = Column(Integer, ForeignKey('keyword.id'),
primary_key=True)
special_key = Column(String)
user = relationship(User, backref=backref(
"user_keywords",
collection_class=attribute_mapped_collection("special_key"),
cascade="all, delete-orphan"
)
)
class Keyword(Base):
__tablename__ = 'keyword'
id = Column(Integer, primary_key=True)
keyword = Column('keyword', String(64))
User.keywords is now a dictionary of string to string, where UserKeyword and Keyword objects are created
and removed for us transparently using the association proxy. In the example below, we illustrate usage of the as-
signment operator, also appropriately handled by the association proxy, to apply a dictionary value to the collection at
once:
One caveat with our example above is that because Keyword objects are created for each dictionary set operation, the
example fails to maintain uniqueness for the Keyword objects on their string name, which is a typical requirement
for a tagging scenario such as this one. For this use case the recipe UniqueObject, or a comparable creational strategy,
is recommended, which will apply a “lookup first, then create” strategy to the constructor of the Keyword class, so
that an already existing Keyword is returned if the given name is already present.
The AssociationProxy features simple SQL construction capabilities which relate down to
the underlying relationship() in use as well as the target attribute. For example, the
RelationshipProperty.Comparator.any() and RelationshipProperty.Comparator.has()
operations are available, and will produce a “nested” EXISTS clause, such as in our basic association object example:
>>> print(session.query(User).filter(User.keywords.any(keyword='jek')))
SELECT user.id AS user_id, user.name AS user_name
FROM user
WHERE EXISTS (SELECT 1
FROM user_keyword
WHERE user.id = user_keyword.user_id AND (EXISTS (SELECT 1
FROM keyword
WHERE keyword.id = user_keyword.keyword_id AND keyword.keyword = :keyword_1)))
>>> print(session.query(User).filter(User.keywords.contains('jek')))
SELECT user.*
FROM user
WHERE EXISTS (SELECT 1
AssociationProxy can be used with Query.join() somewhat manually using the attr attribute in a star-
args context:
q = session.query(User).join(*User.keywords.attr)
uka = aliased(UserKeyword)
ka = aliased(Keyword)
q = session.query(User).\
join(uka, User.keywords.local_attr).\
join(ka, User.keywords.remote_attr)
API Documentation
For scalar relationships, creator() will be called if the target is None. If the target is
present, set operations are proxied to setattr() on the associated object.
If you have an associated object with multiple attributes, you may set up multiple as-
sociation proxies mapping to different attributes. See the unit tests for examples, and
for examples of how creator() functions can be used to construct the scalar relationship
on-demand in this situation.
• **kw – Passes along any other keyword arguments to AssociationProxy.
class sqlalchemy.ext.associationproxy.AssociationProxy(target_collection, attr,
creator=None, get-
set_factory=None,
proxy_factory=None,
proxy_bulk_set=None,
info=None)
Bases: sqlalchemy.orm.base.InspectionAttrInfo
A descriptor that presents a read/write view of an object attribute.
__init__(target_collection, attr, creator=None, getset_factory=None, proxy_factory=None,
proxy_bulk_set=None, info=None)
Construct a new AssociationProxy.
The association_proxy() function is provided as the usual entrypoint here, though
AssociationProxy can be instantiated and/or subclassed directly.
Parameters
• target_collection – Name of the collection we’ll proxy to, usually created
with relationship().
• attr – Attribute on the collected instances we’ll proxy for. For example, given a
target collection of [obj1, obj2], a list created by this proxy property would look like
[getattr(obj1, attr), getattr(obj2, attr)]
• creator – Optional. When new items are added to this proxied collection, new
instances of the class collected by the target collection will be created. For list and
set collections, the target class constructor will be called with the ‘value’ for the new
instance. For dict types, two arguments are passed: key and value.
If you want to construct instances differently, supply a ‘creator’ function that takes
arguments as above and returns instances.
• getset_factory – Optional. Proxied attribute access is automatically handled by
routines that get and set values based on the attr argument for this proxy.
If you would like to customize this behavior, you may supply a getset_factory callable
that produces a tuple of getter and setter functions. The factory is called with two
arguments, the abstract type of the underlying collection and this proxy instance.
• proxy_factory – Optional. The type of collection to emulate is determined by
sniffing the target collection. If your collection type can’t be determined by duck
typing or you’d like to use a different collection implementation, you may supply a
factory function to produce those collections. Only applicable to non-scalar relation-
ships.
• proxy_bulk_set – Optional, use with proxy_factory. See the _set() method for
details.
• info – optional, will be assigned to AssociationProxy.info if present.
New in version 1.0.9.
any(criterion=None, **kwargs)
Produce a proxied ‘any’ expression using EXISTS.
This expression will be a composed product using the RelationshipProperty.Comparator.any()
and/or RelationshipProperty.Comparator.has() operators of the underlying proxied at-
tributes.
attr
Return a tuple of (local_attr, remote_attr).
This attribute is convenient when specifying a join using Query.join() across two relationships:
sess.query(Parent).join(*Parent.proxied.attr)
is_mapper = False
is_property = False
is_selectable = False
local_attr
The ‘local’ MapperProperty referenced by this AssociationProxy.
New in version 0.7.3.
See also:
AssociationProxy.attr
AssociationProxy.remote_attr
remote_attr
The ‘remote’ MapperProperty referenced by this AssociationProxy.
New in version 0.7.3.
See also:
AssociationProxy.attr
AssociationProxy.local_attr
scalar
Return True if this AssociationProxy proxies a scalar relationship on the local side.
target_class
The intermediary class handled by this AssociationProxy.
Intercepted append/set/assignment events will result in the generation of new instances of this class.
sqlalchemy.ext.associationproxy.ASSOCIATION_PROXY = symbol(‘ASSOCIATION_PROXY’)
2.7.2 Automap
Basic Use
The simplest usage is to reflect an existing database into a new model. We create a new AutomapBase class
in a similar manner as to how we create a declarative base class, using automap_base(). We then call
AutomapBase.prepare() on the resulting base class, asking it to reflect the schema and produce mappings:
Base = automap_base()
session = Session(engine)
Note: By viable, we mean that for a table to be mapped, it must specify a primary key. Additionally, if the table is
detected as being a pure association table between two other tables, it will not be directly mapped and will instead be
configured as a many-to-many table between the mappings for the two referring tables.
We can pass a pre-declared MetaData object to automap_base(). This object can be constructed in any way,
including programmatically, from a serialized file, or from itself being reflected using MetaData.reflect().
Below we illustrate a combination of reflection and explicit table declaration:
# ... or just define our own Table objects with it (or combine both)
Table('user_order', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', ForeignKey('user.id'))
)
The sqlalchemy.ext.automap extension allows classes to be defined explicitly, in a way similar to that
of the DeferredReflection class. Classes that extend from AutomapBase act like regular declara-
tive classes, but are not immediately mapped after their construction, and are instead mapped when we call
AutomapBase.prepare(). The AutomapBase.prepare() method will make use of the classes we’ve es-
tablished based on the table name we use. If our schema contains tables user and address, we can define one or
both of the classes to be used:
# automap base
Base = automap_base()
# reflect
engine = create_engine("sqlite:///mydatabase.db")
Base.prepare(engine, reflect=True)
Address = Base.classes.address
u1 = session.query(User).first()
print (u1.address_collection)
Above, one of the more intricate details is that we illustrated overriding one of the relationship() objects that
automap would have created. To do this, we needed to make sure the names match up with what automap would
normally generate, in that the relationship name would be User.address_collection and the name of the
class referred to, from automap’s perspective, is called address, even though we are referring to it as Address
within our usage of this class.
sqlalchemy.ext.automap is tasked with producing mapped classes and relationship names based on
a schema, which means it has decision points in how these names are determined. These three de-
cision points are provided using functions which can be passed to the AutomapBase.prepare()
method, and are known as classname_for_table(), name_for_scalar_relationship(), and
name_for_collection_relationship(). Any or all of these functions are provided as in the example be-
low, where we use a “camel case” scheme for class names and a “pluralizer” for collection names using the Inflect
package:
import re
import inflect
return str(tablename[0].upper() + \
re.sub(r'_([a-z])', lambda m: m.group(1).upper(), tablename[1:]))
_pluralizer = inflect.engine()
def pluralize_collection(base, local_cls, referred_cls, constraint):
"Produce an 'uncamelized', 'pluralized' class name, e.g. "
"'SomeTerm' -> 'some_terms'"
referred_name = referred_cls.__name__
uncamelized = re.sub(r'[A-Z]',
lambda m: "_%s" % m.group(0).lower(),
referred_name)[1:]
pluralized = _pluralizer.plural(uncamelized)
return pluralized
Base = automap_base()
engine = create_engine("sqlite:///mydatabase.db")
Base.prepare(engine, reflect=True,
classname_for_table=camelize_classname,
name_for_collection_relationship=pluralize_collection
)
From the above mapping, we would now have classes User and Address, where the collection from User to
Address is called User.addresses:
u1 = User(addresses=[Address(email="[email protected]")])
Relationship Detection
The vast majority of what automap accomplishes is the generation of relationship() structures based on foreign
keys. The mechanism by which this works for many-to-one and one-to-many relationships is as follows:
1. A given Table, known to be mapped to a particular class, is examined for ForeignKeyConstraint ob-
jects.
2. From each ForeignKeyConstraint, the remote Table object present is matched up to the class to which
it is to be mapped, if any, else it is skipped.
3. As the ForeignKeyConstraint we are examining corresponds to a reference from the immediate mapped
class, the relationship will be set up as a many-to-one referring to the referred class; a corresponding one-to-
many backref will be created on the referred class referring to this class.
4. If any of the columns that are part of the ForeignKeyConstraint are not nullable (e.g.
nullable=False), a cascade keyword argument of all, delete-orphan will be added to the key-
word arguments to be passed to the relationship or backref. If the ForeignKeyConstraint reports that
ForeignKeyConstraint.ondelete is set to CASCADE for a not null or SET NULL for a nullable set
of columns, the option passive_deletes flag is set to True in the set of relationship keyword arguments.
Note that not all backends support reflection of ON DELETE.
New in version 1.0.0: - automap will detect non-nullable foreign key constraints when producing a one-to-many
relationship and establish a default cascade of all, delete-orphan if so; additionally, if the constraint
specifies ForeignKeyConstraint.ondelete of CASCADE for non-nullable or SET NULL for nullable
columns, the passive_deletes=True option is also added.
5. The names of the relationships are determined using the AutomapBase.prepare.name_for_scalar_relationship
and AutomapBase.prepare.name_for_collection_relationship callable functions. It is im-
portant to note that the default relationship naming derives the name from the the actual class name. If you’ve
given a particular class an explicit name by declaring it, or specified an alternate class naming scheme, that’s
the name from which the relationship name will be derived.
6. The classes are inspected for an existing mapped property matching these names. If one is detected on one side,
but none on the other side, AutomapBase attempts to create a relationship on the missing side, then uses the
relationship.back_populates parameter in order to point the new relationship to the other side.
7. In the usual case where no relationship is on either side, AutomapBase.prepare() pro-
duces a relationship() on the “many-to-one” side and matches it to the other using the
relationship.backref parameter.
8. Production of the relationship() and optionally the backref() is handed off to the
AutomapBase.prepare.generate_relationship function, which can be supplied by the end-user
in order to augment the arguments passed to relationship() or backref() or to make use of custom
implementations of these functions.
# automap base
Base = automap_base()
engine = create_engine("sqlite:///mydatabase.db")
Base.prepare(engine, reflect=True,
generate_relationship=_gen_relationship)
Many-to-Many relationships
sqlalchemy.ext.automap will generate many-to-many relationships, e.g. those which contain a secondary
argument. The process for producing these is as follows:
1. A given Table is examined for ForeignKeyConstraint objects, before any mapped class has been as-
signed to it.
2. If the table contains two and exactly two ForeignKeyConstraint objects, and all columns within this table
are members of these two ForeignKeyConstraint objects, the table is assumed to be a “secondary” table,
and will not be mapped directly.
3. The two (or one, for self-referential) external tables to which the Table refers to are matched to the classes to
which they will be mapped, if any.
4. If mapped classes for both sides are located, a many-to-many bi-directional relationship() / backref()
pair is created between the two classes.
5. The override logic for many-to-many works the same as that of one-to-many/ many-to-one; the
generate_relationship() function is called upon to generate the strucures and existing attributes will
be maintained.
sqlalchemy.ext.automap will not generate any relationships between two classes that are in an inheritance
relationship. That is, with two classes given as follows:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee', 'polymorphic_on': type
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity':'engineer',
}
The foreign key from Engineer to Employee is used not for a relationship, but to establish joined inheritance
between the two classes.
Note that this means automap will not generate any relationships for foreign keys that link from a subclass to a
superclass. If a mapping has actual relationships from subclass to superclass as well, those need to be explicit. Below,
as we have two separate foreign keys from Engineer to Employee, we need to set up both the relationship we
want as well as the inherit_condition, as these are not things SQLAlchemy can guess:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee', 'polymorphic_on':type
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
favorite_employee_id = Column(Integer, ForeignKey('employee.id'))
favorite_employee = relationship(Employee,
foreign_keys=favorite_employee_id)
__mapper_args__ = {
'polymorphic_identity':'engineer',
'inherit_condition': id == Employee.id
}
The above schema will first automap the table_a table as a class named table_a; it will then automap a relation-
ship onto the class for table_b with the same name as this related class, e.g. table_a. This relationship name
conflicts with the mapping column table_b.table_a, and will emit an error on mapping.
We can resolve this conflict by using an underscore as follows:
Base.prepare(engine, reflect=True,
name_for_scalar_relationship=name_for_scalar_relationship)
Alternatively, we can change the name on the column side. The columns that are mapped can be modified using the
technique described at Naming Columns Distinctly from Attribute Names, by assigning the column explicitly to a new
name:
Base = automap_base()
class TableB(Base):
__tablename__ = 'table_b'
_table_a = Column('table_a', ForeignKey('table_a.id'))
Base.prepare(engine, reflect=True)
As noted previously, automap has no dependency on reflection, and can make use of any collection of Table objects
within a MetaData collection. From this, it follows that automap can also be used generate missing relationships
given an otherwise complete model that fully defines table metadata:
Base = automap_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(ForeignKey('user.id'))
# produce relationships
Base.prepare()
Above, given mostly complete User and Address mappings, the ForeignKey which we de-
fined on Address.user_id allowed a bidirectional relationship pair Address.user and
User.address_collection to be generated on the mapped classes.
Note that when subclassing AutomapBase, the AutomapBase.prepare() method is required; if not called, the
classes we’ve declared are in an un-mapped state.
API Reference
sqlalchemy.ext.automap.automap_base(declarative_base=None, **kw)
Produce a declarative automap base.
This function produces a new base class that is a product of the AutomapBase class as well a declarative base
produced by declarative.declarative_base().
All parameters other than declarative_base are keyword arguments that are passed directly to the
declarative.declarative_base() function.
Parameters
• declarative_base – an existing class produced by
declarative.declarative_base(). When this is passed, the function no
longer invokes declarative.declarative_base() itself, and all other keyword
arguments are ignored.
• **kw – keyword arguments are passed along to
declarative.declarative_base().
class sqlalchemy.ext.automap.AutomapBase
Base class for an “automap” schema.
The AutomapBase class can be compared to the “declarative base” class that is produced by the
declarative.declarative_base() function. In practice, the AutomapBase class is always used
as a mixin along with an actual declarative base.
A new subclassable AutomapBase is typically instantated using the automap_base() function.
See also:
Automap
classes = None
An instance of util.Properties containing classes.
This object behaves much like the .c collection on a table. Classes are present under the name they were
given, e.g.:
Base = automap_base()
Base.prepare(engine=some_engine, reflect=True)
Returns
a string class name.
Note: In Python 2, the string used for the class name must be a non-Unicode object, e.g.
a str() object. The .name attribute of Table is typically a Python unicode subclass,
so the str() function should be applied to this name, after accounting for any non-ASCII
characters.
if return_fn is backref:
return return_fn(attrname, **kw)
elif return_fn is relationship:
return return_fn(referred_cls, **kw)
else:
raise TypeError("Unknown relationship function: %s" % return_fn)
Parameters
• base – the AutomapBase class doing the prepare.
• direction – indicate the “direction” of the relationship; this will be one of
ONETOMANY, MANYTOONE, MANYTOMANY.
• return_fn – the function that is used by default to create the relationship. This will
be either relationship() or backref(). The backref() function’s result will
be used to produce a new relationship() in a second step, so it is critical that user-
defined implementations correctly differentiate between the two functions, if a custom
relationship function is being used.
• local_cls – the “local” class to which this relationship or backref will be locally
present.
• referred_cls – the “referred” class to which the relationship or backref refers to.
• **kw – all additional keyword arguments are passed along to the function.
Attrname the attribute name to which this relationship is being assigned. If the value of
generate_relationship.return_fn is the backref() function, then this name
is the name that is being assigned to the backref.
Returns a relationship() or backref() construct, as dictated by the
generate_relationship.return_fn parameter.
baked provides an alternative creational pattern for Query objects, which allows for caching of the object’s con-
struction and string-compilation steps. This means that for a particular Query building scenario that is used more
than once, all of the Python function invocation involved in building the query from its initial construction up through
generating a SQL string will only occur once, rather than for each time that query is built up and executed.
The rationale for this system is to greatly reduce Python interpreter overhead for everything that occurs before the
SQL is emitted. The caching of the “baked” system does not in any way reduce SQL calls or cache the return results
from the database. A technique that demonstates the caching of the SQL calls and result sets themselves is available
in Dogpile Caching.
New in version 1.0.0.
Synopsis
Usage of the baked system starts by producing a so-called “bakery”, which represents storage for a particular series of
query objects:
bakery = baked.bakery()
The above “bakery” will store cached data in an LRU cache that defaults to 200 elements, noting that an ORM query
will typically contain one entry for the ORM query as invoked, as well as one entry per database dialect for the SQL
string.
The bakery allows us to build up a Query object by specifying its construction as a series of Python callables, which
are typically lambdas. For succinct usage, it overrides the += operator so that a typical query build-up looks like the
following:
if email:
baked_query += lambda q: q.filter(User.email == bindparam('email'))
return result
Performance
The baked query probably looks a little odd, a little bit awkward and a little bit verbose. However, the savings in
Python performance for a query which is invoked lots of times in an application are very dramatic. The example suite
short_selects demonstrated in Performance illustrates a comparison of queries which each return only one row,
such as the following regular query:
session = Session(bind=engine)
for id_ in random.sample(ids, n):
session.query(Customer).filter(Customer.id == id_).one()
bakery = baked.bakery()
s = Session(bind=engine)
for id_ in random.sample(ids, n):
q = bakery(lambda s: s.query(Customer))
q += lambda q: q.filter(Customer.id == bindparam('id'))
q(s).params(id=id_).one()
The difference in Python function call count for an iteration of 10000 calls to each block are:
Note that this test very intentionally features queries that only return one row. For queries that return many rows, the
performance advantage of the baked query will have less and less of an impact, proportional to the time spent fetching
rows. It is critical to keep in mind that the baked query feature only applies to building the query itself, not the
fetching of results. Using the baked feature is by no means a guarantee to a much faster application; it is only a
potentially useful feature for those applications that have been measured as being impacted by this particular form of
overhead.
Rationale
The “lambda” approach above is a superset of what would be a more traditional “parameterized” approach. Suppose
we wished to build a simple system where we build a Query just once, then store it in a dictionary for re-use. This
is possible right now by just building up the query, and removing its Session by calling my_cached_query =
query.with_session(None):
my_simple_cache = {}
return query.params(id=id_argument).all()
The above approach gets us a very minimal performance benefit. By re-using a Query, we save on the
Python work within the session.query(Model) constructor as well as calling upon filter(Model.id
== bindparam(’id’)), which will skip for us the building up of the Core expression as well as sending
it to Query.filter(). However, the approach still regenerates the full Select object every time when
Query.all() is called and additionally this brand new Select is sent off to the string compilation step every
time, which for a simple case like the above is probably about 70% of the overhead.
To reduce the additional overhead, we need some more specialized logic, some way to memoize the construction of
the select object and the construction of the SQL. There is an example of this on the wiki in the section BakedQuery,
a precursor to this feature, however in that system, we aren’t caching the construction of the query. In order to remove
all the overhead, we need to cache both the construction of the query as well as the SQL compilation. Let’s assume
we adapted the recipe in this way and made ourselves a method .bake() that pre-compiles the SQL for the query,
producing a new object that can be invoked with minimal overhead. Our example becomes:
my_simple_cache = {}
return query.params(id=id_argument).all()
Above, we’ve fixed the performance situation, but we still have this string cache key to deal with.
We can use the “bakery” approach to re-frame the above in a way that looks less unusual than the “building up
lambdas” approach, and more like a simple improvement upon the simple “reuse a query” approach:
bakery = baked.bakery()
parameterized_query = bakery.bake(create_model_query)
return parameterized_query(session).params(id=id_argument).all()
Above, we use the “baked” system in a manner that is very similar to the simplistic “cache a query” system. However,
it uses two fewer lines of code, does not need to manufacture a cache key of “my_key”, and also includes the same
feature as our custom “bake” function that caches 100% of the Python invocation work from the constructor of the
query, to the filter call, to the production of the Select object, to the string compilation step.
From the above, if we ask ourselves, “what if lookup needs to make conditional decisions as to the structure of the
query?”, this is where hopefully it becomes apparent why “baked” is the way it is. Instead of a parameterized query
building off from exactly one function (which is how we thought baked might work originally), we can build it from
any number of functions. Consider our naive example, if we needed to have an additional clause in our query on a
conditional basis:
my_simple_cache = {}
my_simple_cache[cache_key] = query.with_session(None).bake()
else:
query = my_simple_cache[cache_key].with_session(session)
return query.params(id=id_argument).all()
Our “simple” parameterized system must now be tasked with generating cache keys which take into account whether
or not the “include_frobnizzle” flag was passed, as the presence of this flag means that the generated SQL would be
entirely different. It should be apparent that as the complexity of query building goes up, the task of caching these
queries becomes burdensome very quickly. We can convert the above example into a direct use of “bakery” as follows:
bakery = baked.bakery()
parameterized_query = bakery.bake(create_model_query)
if include_frobnizzle:
def include_frobnizzle_in_query(query):
return query.filter(Model.frobnizzle == True)
parameterized_query = parameterized_query.with_criteria(
include_frobnizzle_in_query)
return parameterized_query(session).params(id=id_argument).all()
Above, we again cache not just the query object but all the work it needs to do in order to generate SQL. We also no
longer need to deal with making sure we generate a cache key that accurately takes into account all of the structural
modifications we’ve made; this is now handled automatically and without the chance of mistakes.
This code sample is a few lines shorter than the naive example, removes the need to deal with cache keys, and has the
vast performance benefits of the full so-called “baked” feature. But still a little verbose! Hence we take methods like
bakery = baked.bakery()
if include_frobnizzle:
parameterized_query += lambda q: q.filter(Model.frobnizzle == True)
return parameterized_query(session).params(id=id_argument).all()
Where above, the approach is simpler to implement and much more similar in code flow to what a non-cached querying
function would look like, hence making code easier to port.
The above description is essentially a summary of the design process used to arrive at the current “baked” approach.
Starting from the “normal” approaches, the additional issues of cache key construction and management, removal of
all redundant Python execution, and queries built up with conditionals needed to be addressed, leading to the final
approach.
The baked query can be integrated with SQLAlchemy’s lazy loader feature transparently. A future release of
SQLAlchemy may enable this by default, as its use within lazy loading is completely transparent. For now, to en-
able baked lazyloading for all lazyloaders systemwide, call upon the bake_lazy_loaders() function. This will
impact all relationships that use the lazy=’select’ strategy as well as all use of the lazyload() per-query
strategy.
“Baked” lazy loading may be enabled on a per-relationship() basis using the baked_select loader strategy:
class MyClass(Base):
# ...
The baked_select strategy is available once any part of the application has imported the
sqlalchemy.ext.baked module. The “bakery” used by this feature is local to the mapper for MyClass.
For per-query use, the baked_lazyload() strategy may be used, which works like any other loader option.
The relationship() construct includes a flag relationship.bake_queries which when set to False will
cause that relationship to opt out of the baked query system, when the application-wide bake_lazy_loaders()
function has been called to enable baked query loaders by default.
API Documentation
sqlalchemy.ext.baked.bakery(cls, size=200)
Construct a new bakery.
Equivalent to Query.one_or_none().
New in version 1.0.9.
params(*args, **kw)
Specify parameters to be replaced into the string SQL statement.
sqlalchemy.ext.baked.bake_lazy_loaders()
Enable the use of baked queries for all lazyloaders systemwide.
This operation should be safe for all lazy loaders, and will reduce Python overhead for these operations.
sqlalchemy.ext.baked.unbake_lazy_loaders()
Disable the use of baked queries for all lazyloaders systemwide.
This operation reverts the changes produced by bake_lazy_loaders().
sqlalchemy.ext.baked.baked_lazyload(*keys)
Indicate that the given attribute should be loaded using “lazy” loading with a “baked” query used in the load.
sqlalchemy.ext.baked.baked_lazyload_all(*keys)
Produce a standalone “all” option for orm.baked_lazyload().
Deprecated since version 0.9.0: The “_all()” style is replaced by method chaining, e.g.:
session.query(MyClass).options(
baked_lazyload("someattribute").baked_lazyload("anotherattribute")
)
2.7.4 Declarative
The Declarative system is the typically used system provided by the SQLAlchemy ORM in order to define classes
mapped to relational database tables. However, as noted in Classical Mappings, Declarative is in fact a series of
extensions that ride on top of the SQLAlchemy mapper() construct.
While the documentation typically refers to Declarative for most examples, the following sections will provide detailed
information on how the Declarative API interacts with the basic mapper() and Core Table systems, as well as how
sophisticated patterns can be built using systems such as mixins.
Basic Use
SQLAlchemy object-relational configuration involves the combination of Table, mapper(), and class objects to
define a mapped class. declarative allows all three to be expressed at once within the class declaration. As
much as possible, regular SQLAlchemy schema and ORM constructs are used directly, so that configuration between
“classical” ORM usage and declarative remain highly similar.
As a simple example:
Base = declarative_base()
class SomeClass(Base):
__tablename__ = 'some_table'
id = Column(Integer, primary_key=True)
name = Column(String(50))
Above, the declarative_base() callable returns a new base class from which all mapped classes should inherit.
When the class definition is completed, a new Table and mapper() will have been generated.
The resulting table and mapper are accessible via __table__ and __mapper__ attributes on the SomeClass
class:
Defining Attributes
In the previous example, the Column objects are automatically named with the name of the attribute to which they
are assigned.
To name columns explicitly with a name distinct from their mapped attribute, just give the column a name. Below, col-
umn “some_table_id” is mapped to the “id” attribute of SomeClass, but in SQL will be represented as “some_table_id”:
class SomeClass(Base):
__tablename__ = 'some_table'
id = Column("some_table_id", Integer, primary_key=True)
Attributes may be added to the class after its construction, and they will be added to the underlying Table and
mapper() definitions as appropriate:
Classes which are constructed using declarative can interact freely with classes that are mapped explicitly with
mapper().
It is recommended, though not required, that all tables share the same underlying MetaData object, so that string-
configured ForeignKey references can be resolved without issue.
The declarative_base() base class contains a MetaData object where newly defined Table objects are col-
lected. This object is intended to be accessed directly for MetaData-specific operations. Such as, to issue CREATE
statements for all tables:
engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
declarative_base() can also receive a pre-existing MetaData object, which allows a declarative setup to be
associated with an already existing traditional collection of Table objects:
mymetadata = MetaData()
Base = declarative_base(metadata=mymetadata)
Class Constructor
As a convenience feature, the declarative_base() sets a default constructor on classes which takes keyword
arguments, and assigns them to the named attributes:
e = Engineer(primary_language='python')
Mapper Configuration
Declarative makes use of the mapper() function internally when it creates the mapping to the declared table. The
options for mapper() are passed directly through via the __mapper_args__ class attribute. As always, arguments
which reference locally mapped columns can reference them directly from within the class declaration:
class Widget(Base):
__tablename__ = 'widgets'
id = Column(Integer, primary_key=True)
timestamp = Column(DateTime, nullable=False)
__mapper_args__ = {
'version_id_col': timestamp,
'version_id_generator': lambda v:datetime.now()
}
See SQL Expressions as Mapped Attributes for examples on declaratively mapping attributes to SQL expressions.
Configuring Relationships
Relationships to other classes are done in the usual way, with the added feature that the class specified to
relationship() may be a string name. The “class registry” associated with Base is used at mapper compi-
lation time to resolve the name into the actual class object, which is expected to have been defined once the mapper
configuration is used:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
addresses = relationship("Address", backref="user")
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email = Column(String(50))
user_id = Column(Integer, ForeignKey('users.id'))
Column constructs, since they are just that, are immediately usable, as below where we define a primary join condition
on the Address class using them:
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email = Column(String(50))
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship(User, primaryjoin=user_id == User.id)
In addition to the main argument for relationship(), other arguments which depend upon the columns present
on an as-yet undefined class may also be specified as strings. These strings are evaluated as Python expressions. The
full namespace available within this evaluation includes all classes mapped for this declarative base, as well as the
contents of the sqlalchemy package, including expression functions like desc() and func:
class User(Base):
# ....
addresses = relationship("Address",
order_by="desc(Address.email)",
primaryjoin="Address.user_id==User.id")
For the case where more than one module contains a class of the same name, string class names can also be specified
as module-qualified paths within any of these string expressions:
class User(Base):
# ....
addresses = relationship("myapp.model.address.Address",
order_by="desc(myapp.model.address.Address.email)",
primaryjoin="myapp.model.address.Address.user_id=="
"myapp.model.user.User.id")
The qualified path can be any partial path that removes ambiguity between the names. For example, to disam-
biguate between myapp.model.address.Address and myapp.model.lookup.Address, we can specify
address.Address or lookup.Address:
class User(Base):
# ....
addresses = relationship("address.Address",
order_by="desc(address.Address.email)",
primaryjoin="address.Address.user_id=="
"User.id")
New in version 0.8: module-qualified paths can be used when specifying string arguments with Declarative, in order
to specify specific modules.
Two alternatives also exist to using string-based attributes. A lambda can also be used, which will be evaluated after
all mappers have been configured:
class User(Base):
# ...
addresses = relationship(lambda: Address,
order_by=lambda: desc(Address.email),
primaryjoin=lambda: Address.user_id==User.id)
Or, the relationship can be added to the class explicitly after the classes are available:
User.addresses = relationship(Address,
primaryjoin=Address.user_id==User.id)
Many-to-many relationships are also declared in the same way with declarative as with traditional mappings. The
secondary argument to relationship() is as usual passed a Table object, which is typically declared in the
traditional way. The Table usually shares the MetaData object used by the declarative base:
keywords = Table(
'keywords', Base.metadata,
Column('author_id', Integer, ForeignKey('authors.id')),
Column('keyword_id', Integer, ForeignKey('keywords.id'))
)
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
keywords = relationship("Keyword", secondary=keywords)
Like other relationship() arguments, a string is accepted as well, passing the string name of the table as defined
in the Base.metadata.tables collection:
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
keywords = relationship("Keyword", secondary="keywords")
As with traditional mapping, its generally not a good idea to use a Table as the “secondary” argument which is also
mapped to a class, unless the relationship() is declared with viewonly=True. Otherwise, the unit-of-work
system may attempt duplicate INSERT and DELETE statements against the underlying table.
Table Configuration
Table arguments other than the name, metadata, and mapped Column arguments are specified using the
__table_args__ class attribute. This attribute accommodates both positional as well as keyword arguments that
are normally sent to the Table constructor. The attribute can be specified in one of two forms. One is as a dictionary:
class MyClass(Base):
__tablename__ = 'sometable'
__table_args__ = {'mysql_engine':'InnoDB'}
class MyClass(Base):
__tablename__ = 'sometable'
__table_args__ = (
ForeignKeyConstraint(['id'], ['remote_table.id']),
UniqueConstraint('foo'),
)
Keyword arguments can be specified with the above form by specifying the last argument as a dictionary:
class MyClass(Base):
__tablename__ = 'sometable'
__table_args__ = (
ForeignKeyConstraint(['id'], ['remote_table.id']),
UniqueConstraint('foo'),
{'autoload':True}
)
As an alternative to __tablename__, a direct Table construct may be used. The Column objects, which in this
case require their names, will be added to the mapping just like a regular mapping to a table:
class MyClass(Base):
__table__ = Table('my_table', Base.metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50))
)
__table__ provides a more focused point of control for establishing table metadata, while still getting most of the
benefits of using declarative. An application that uses reflection might want to load table metadata elsewhere and pass
it to declarative classes:
Base = declarative_base()
Base.metadata.reflect(some_engine)
class User(Base):
__table__ = metadata.tables['user']
class Address(Base):
__table__ = metadata.tables['address']
Some configuration schemes may find it more appropriate to use __table__, such as those which already take
advantage of the data-driven nature of Table to customize and/or automate schema definition.
Note that when the __table__ approach is used, the object is immediately usable as a plain Table within the class
declaration body itself, as a Python class is only another syntactical block. Below this is illustrated by using the id
column in the primaryjoin condition of a relationship():
class MyClass(Base):
__table__ = Table('my_table', Base.metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50))
)
widgets = relationship(Widget,
primaryjoin=Widget.myclass_id==__table__.c.id)
Similarly, mapped attributes which refer to __table__ can be placed inline, as below where we assign the name
column to the attribute _name, generating a synonym for name:
class MyClass(Base):
__table__ = Table('my_table', Base.metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50))
)
_name = __table__.c.name
@synonym_for("_name")
def name(self):
return "Name: %s" % _name
It’s easy to set up a Table that uses autoload=True in conjunction with a mapped class:
class MyClass(Base):
__table__ = Table('mytable', Base.metadata,
autoload=True, autoload_with=some_engine)
However, one improvement that can be made here is to not require the Engine to be available when classes are being
first declared. To achieve this, use the DeferredReflection mixin, which sets up mappings only after a special
prepare(engine) step is called:
Base = declarative_base(cls=DeferredReflection)
class Foo(Base):
__tablename__ = 'foo'
bars = relationship("Bar")
class Bar(Base):
__tablename__ = 'bar'
Base.prepare(e)
Inheritance Configuration
Declarative supports all three forms of inheritance as intuitively as possible. The inherits mapper keyword ar-
gument is not needed as declarative will determine this from the class itself. The various “polymorphic” keyword
arguments are specified using __mapper_args__.
See also:
Mapping Class Inheritance Hierarchies - general introduction to inheritance mapping with Declarative.
Joined table inheritance is defined as a subclass that defines its own table:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__tablename__ = 'engineers'
__mapper_args__ = {'polymorphic_identity': 'engineer'}
id = Column(Integer, ForeignKey('people.id'), primary_key=True)
primary_language = Column(String(50))
Note that above, the Engineer.id attribute, since it shares the same attribute name as the Person.id attribute,
will in fact represent the people.id and engineers.id columns together, with the “Engineer.id” column
taking precedence if queried directly. To provide the Engineer class with an attribute that represents only the
engineers.id column, give it a different attribute name:
class Engineer(Person):
__tablename__ = 'engineers'
__mapper_args__ = {'polymorphic_identity': 'engineer'}
engineer_id = Column('id', Integer, ForeignKey('people.id'),
primary_key=True)
primary_language = Column(String(50))
Single table inheritance is defined as a subclass that does not have its own table; you just leave out the __table__
and __tablename__ attributes:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
primary_language = Column(String(50))
When the above mappers are configured, the Person class is mapped to the people table before the
primary_language column is defined, and this column will not be included in its own mapping. When
Engineer then defines the primary_language column, the column is added to the people table so that
it is included in the mapping for Engineer and is also part of the table’s full set of columns. Columns
which are not mapped to Person are also excluded from any other single or joined inheriting classes using the
exclude_properties mapper argument. Below, Manager will have all the attributes of Person and Manager
but not the primary_language attribute of Engineer:
class Manager(Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
golf_swing = Column(String(50))
The attribute exclusion logic is provided by the exclude_properties mapper argument, and declarative’s default
behavior can be disabled by passing an explicit exclude_properties collection (empty or otherwise) to the
__mapper_args__.
Resolving Column Conflicts Note above that the primary_language and golf_swing columns are “moved
up” to be applied to Person.__table__, as a result of their declaration on a subclass that has no table of its own.
A tricky case comes up when two subclasses want to specify the same column, as below:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
start_date = Column(DateTime)
class Manager(Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
start_date = Column(DateTime)
Above, the start_date column declared on both Engineer and Manager will result in an error:
In a situation like this, Declarative can’t be sure of the intent, especially if the start_date columns had, for
example, different types. A situation like this can be resolved by using declared_attr to define the Column
conditionally, taking care to return the existing column via the parent __table__ if it already exists:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
@declared_attr
def start_date(cls):
"Start date column, if not present already."
return Person.__table__.c.get('start_date', Column(DateTime))
class Manager(Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
@declared_attr
def start_date(cls):
"Start date column, if not present already."
return Person.__table__.c.get('start_date', Column(DateTime))
Above, when Manager is mapped, the start_date column is already present on the Person class. Declarative
lets us return that Column as a result in this case, where it knows to skip re-assigning the same column. If the
mapping is mis-configured such that the start_date column is accidentally re-assigned to a different table (such
as, if we changed Manager to be joined inheritance without fixing start_date), an error is raised which indicates
an existing Column is trying to be re-assigned to a different owning Table.
New in version 0.8: declared_attr can be used on a non-mixin class, and the returned Column or other mapped
attribute will be applied to the mapping as any other attribute. Previously, the resulting attribute would be ignored, and
also result in a warning being emitted when a subclass was created.
New in version 0.8: declared_attr, when used either with a mixin or non-mixin declarative class, can return an
existing Column already assigned to the parent Table, to indicate that the re-assignment of the Column should be
skipped, however should still be mapped on the target class, in order to resolve duplicate column conflicts.
The same concept can be used with mixin classes (see Mixin and Custom Base Classes):
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class HasStartDate(object):
@declared_attr
def start_date(cls):
return cls.__table__.c.get('start_date', Column(DateTime))
The above mixin checks the local __table__ attribute for the column. Because we’re using single table inheritance,
we’re sure that in this case, cls.__table__ refers to Person.__table__. If we were mixing joined- and
single-table inheritance, we might want our mixin to check more carefully if cls.__table__ is really the Table
we’re looking for.
Concrete is defined as a subclass which has its own table and sets the concrete keyword argument to True:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
name = Column(String(50))
class Engineer(Person):
__tablename__ = 'engineers'
__mapper_args__ = {'concrete':True}
id = Column(Integer, primary_key=True)
primary_language = Column(String(50))
name = Column(String(50))
Usage of an abstract base class is a little less straightforward as it requires usage of polymorphic_union(), which
needs to be created with the Table objects before the class is built:
punion = polymorphic_union({
'engineer':engineers,
'manager':managers
}, 'type', 'punion')
class Person(Base):
__table__ = punion
__mapper_args__ = {'polymorphic_on':punion.c.type}
class Engineer(Person):
__table__ = engineers
__mapper_args__ = {'polymorphic_identity':'engineer', 'concrete':True}
class Manager(Person):
__table__ = managers
__mapper_args__ = {'polymorphic_identity':'manager', 'concrete':True}
The helper classes AbstractConcreteBase and ConcreteBase provide automation for the above system of
creating a polymorphic union. See the documentation for these helpers as well as the main ORM documentation on
concrete inheritance for details.
See also:
Concrete Table Inheritance
Using the Declarative Helper Classes
A common need when using declarative is to share some functionality, such as a set of common columns, some
common table options, or other mapped properties, across many classes. The standard Python idioms for this is to
have the classes inherit from a base which includes these common features.
When using declarative, this idiom is allowed via the usage of a custom declarative base class, as well as a
“mixin” class which is inherited from in addition to the primary base. Declarative includes several helper features to
make this work in terms of how mappings are declared. An example of some commonly mixed-in idioms is below:
class MyMixin(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
id = Column(Integer, primary_key=True)
Where above, the class MyModel will contain an “id” column as the primary key, a __tablename__ attribute that
derives from the name of the class itself, as well as __table_args__ and __mapper_args__ defined by the
MyMixin mixin class.
There’s no fixed convention over whether MyMixin precedes Base or not. Normal Python method resolution rules
apply, and the above example would work just as well with:
This works because Base here doesn’t define any of the variables that MyMixin defines, i.e. __tablename__,
__table_args__, id, etc. If the Base did define an attribute of the same name, the class placed first in the inherits
list would determine which attribute is used on the newly defined class.
In addition to using a pure mixin, most of the techniques in this section can also be applied to the base class itself, for
patterns that should apply to all classes derived from a particular base. This is achieved using the cls argument of the
declarative_base() function:
class Base(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
id = Column(Integer, primary_key=True)
Base = declarative_base(cls=Base)
class MyModel(Base):
name = Column(String(1000))
Where above, MyModel and all other classes that derive from Base will have a table name derived from the class
name, an id primary key column, as well as the “InnoDB” engine for MySQL.
Mixing in Columns
class TimestampMixin(object):
created_at = Column(DateTime, default=func.now())
id = Column(Integer, primary_key=True)
name = Column(String(1000))
Where above, all declarative classes that include TimestampMixin will also have a column created_at that
applies a timestamp to all row insertions.
Those familiar with the SQLAlchemy expression language know that the object identity of clause elements defines
their role in a schema. Two Table objects a and b may both have a column called id, but the way these are
differentiated is that a.c.id and b.c.id are two distinct Python objects, referencing their parent tables a and b
respectively.
In the case of the mixin column, it seems that only one Column object is explicitly created, yet the ultimate
created_at column above must exist as a distinct Python object for each separate destination class. To accom-
plish this, the declarative extension creates a copy of each Column object encountered on a class that is detected as a
mixin.
This copy mechanism is limited to simple columns that have no foreign keys, as a ForeignKey itself contains
references to columns which can’t be properly recreated at this level. For columns that have foreign keys, as well as
for the variety of mapper-level constructs that require destination-explicit context, the declared_attr decorator is
provided so that patterns common to many classes can be defined as callables:
class ReferenceAddressMixin(object):
@declared_attr
def address_id(cls):
return Column(Integer, ForeignKey('address.id'))
Where above, the address_id class-level callable is executed at the point at which the User class is constructed,
and the declarative extension can use the resulting Column object as returned by the method without the need to copy
it.
Changed in version 0.6.5: Rename sqlalchemy.util.classproperty into declared_attr.
Columns generated by declared_attr can also be referenced by __mapper_args__ to a limited degree, cur-
rently by polymorphic_on and version_id_col; the declarative extension will resolve them at class construc-
tion time:
class MyMixin:
@declared_attr
def type_(cls):
return Column(String(50))
__mapper_args__= {'polymorphic_on':type_}
Mixing in Relationships
Relationships created by relationship() are provided with declarative mixin classes exclusively using the
declared_attr approach, eliminating any ambiguity which could arise when copying a relationship and its pos-
sibly column-bound contents. Below is an example which combines a foreign key column and a relationship so that
two classes Foo and Bar can both be configured to reference a common target class via many-to-one:
class RefTargetMixin(object):
@declared_attr
def target_id(cls):
return Column('target_id', ForeignKey('target.id'))
@declared_attr
def target(cls):
return relationship("Target")
class Target(Base):
__tablename__ = 'target'
id = Column(Integer, primary_key=True)
Using Advanced Relationship Arguments (e.g. primaryjoin, etc.) relationship() definitions which re-
quire explicit primaryjoin, order_by etc. expressions should in all but the most simplistic cases use late bound forms
for these arguments, meaning, using either the string form or a lambda. The reason for this is that the related Column
objects which are to be configured using @declared_attr are not available to another @declared_attr at-
tribute; while the methods will work and return new Column objects, those are not the Column objects that Declar-
ative will be using as it calls the methods on its own, thus using different Column objects.
The canonical example is the primaryjoin condition that depends upon another mixed-in column:
class RefTargetMixin(object):
@declared_attr
def target_id(cls):
return Column('target_id', ForeignKey('target.id'))
@declared_attr
def target(cls):
return relationship(Target,
primaryjoin=Target.id==cls.target_id # this is *incorrect*
)
Mapping a class using the above mixin, we will get an error like:
This is because the target_id Column we’ve called upon in our target() method is not the same Column that
declarative is actually going to map to our table.
The condition above is resolved using a lambda:
class RefTargetMixin(object):
@declared_attr
def target_id(cls):
return Column('target_id', ForeignKey('target.id'))
@declared_attr
def target(cls):
return relationship(Target,
primaryjoin=lambda: Target.id==cls.target_id
)
class RefTargetMixin(object):
@declared_attr
def target_id(cls):
return Column('target_id', ForeignKey('target.id'))
@declared_attr
def target(cls):
return relationship("Target",
primaryjoin="Target.id==%s.target_id" % cls.__name__
)
class SomethingMixin(object):
@declared_attr
def dprop(cls):
return deferred(Column(Integer))
The column_property() or other construct may refer to other columns from the mixin. These are copied ahead
of time before the declared_attr is invoked:
class SomethingMixin(object):
x = Column(Integer)
y = Column(Integer)
@declared_attr
def x_plus_y(cls):
return column_property(cls.x + cls.y)
Changed in version 1.0.0: mixin columns are copied to the final mapped class so that declared_attr methods can
access the actual column that will be mapped.
Mixins can specify user-defined attributes as well as other extension units such as association_proxy(). The
usage of declared_attr is required in those cases where the attribute must be tailored specifically to the target
subclass. An example is when constructing multiple association_proxy() attributes which each target a dif-
ferent type of child object. Below is an association_proxy() / mixin example which provides a scalar list of
string values to an implementing class:
Base = declarative_base()
class HasStringCollection(object):
@declared_attr
def _strings(cls):
class StringAttribute(Base):
__tablename__ = cls.string_table_name
id = Column(Integer, primary_key=True)
value = Column(String(50), nullable=False)
parent_id = Column(Integer,
ForeignKey('%s.id' % cls.__tablename__),
nullable=False)
def __init__(self, value):
self.value = value
return relationship(StringAttribute)
@declared_attr
def strings(cls):
return association_proxy('_strings', 'value')
string_table_name = 'type_b_strings'
id = Column(Integer(), primary_key=True)
Above, the HasStringCollection mixin produces a relationship() which refers to a newly generated
class called StringAttribute. The StringAttribute class is generated with its own Table definition
which is local to the parent class making usage of the HasStringCollection mixin. It also produces an
association_proxy() object which proxies references to the strings attribute onto the value attribute of
each StringAttribute instance.
TypeA or TypeB can be instantiated given the constructor argument strings, a list of strings:
ta = TypeA(strings=['foo', 'bar'])
tb = TypeA(strings=['bat', 'bar'])
This list will generate a collection of StringAttribute objects, which are persisted into a table that’s local to
either the type_a_strings or type_b_strings table:
When constructing the association_proxy(), the declared_attr decorator must be used so that a distinct
association_proxy() object is created for each of the TypeA and TypeB classes.
New in version 0.8: declared_attr is usable with non-mapped attributes, including user-defined attributes as well
as association_proxy().
The __tablename__ attribute may be used to provide a function that will determine the name of the table used for
each class in an inheritance hierarchy, as well as whether a class has its own distinct table.
This is achieved using the declared_attr indicator in conjunction with a method named __tablename__().
Declarative will always invoke declared_attr for the special names __tablename__, __mapper_args__
and __table_args__ function for each mapped class in the hierarchy. The function therefore needs to expect
to receive each class individually and to provide the correct answer for each.
For example, to create a mixin that gives every class a simple table name based on class name:
class Tablename:
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
class Engineer(Person):
__tablename__ = None
__mapper_args__ = {'polymorphic_identity': 'engineer'}
primary_language = Column(String(50))
Alternatively, we can modify our __tablename__ function to return None for subclasses, using
has_inherited_table(). This has the effect of those subclasses being mapped with single table inheritance
against the parent:
class Tablename(object):
@declared_attr
def __tablename__(cls):
if has_inherited_table(cls):
return None
return cls.__name__.lower()
class Engineer(Person):
primary_language = Column(String(50))
__mapper_args__ = {'polymorphic_identity': 'engineer'}
In constrast to how __tablename__ and other special names are handled when used with declared_attr, when
we mix in columns and properties (e.g. relationships, column properties, etc.), the function is invoked for the base
class only in the hierarchy. Below, only the Person class will receive a column called id; the mapping will fail on
Engineer, which is not given a primary key:
class HasId(object):
@declared_attr
def id(cls):
return Column('id', Integer, primary_key=True)
class Engineer(Person):
__tablename__ = 'engineer'
primary_language = Column(String(50))
__mapper_args__ = {'polymorphic_identity': 'engineer'}
It is usually the case in joined-table inheritance that we want distinctly named columns on each subclass. However in
this case, we may want to have an id column on every table, and have them refer to each other via foreign key. We
can achieve this as a mixin by using the declared_attr.cascading modifier, which indicates that the function
should be invoked for each class in the hierarchy, just like it does for __tablename__:
class HasId(object):
@declared_attr.cascading
def id(cls):
if has_inherited_table(cls):
return Column('id',
Integer,
ForeignKey('person.id'), primary_key=True)
else:
return Column('id', Integer, primary_key=True)
class Engineer(Person):
__tablename__ = 'engineer'
primary_language = Column(String(50))
__mapper_args__ = {'polymorphic_identity': 'engineer'}
In the case of __table_args__ or __mapper_args__ specified with declarative mixins, you may want to com-
bine some parameters from several mixins with those you wish to define on the class iteself. The declared_attr
decorator can be used here to create user-defined collation routines that pull from multiple collections:
class MySQLSettings(object):
__table_args__ = {'mysql_engine':'InnoDB'}
class MyOtherMixin(object):
__table_args__ = {'info':'foo'}
@declared_attr
def __table_args__(cls):
args = dict()
args.update(MySQLSettings.__table_args__)
args.update(MyOtherMixin.__table_args__)
return args
id = Column(Integer, primary_key=True)
To define a named, potentially multicolumn Index that applies to all tables derived from a mixin, use the “inline”
form of Index and establish it as part of __table_args__:
class MyMixin(object):
a = Column(Integer)
b = Column(Integer)
@declared_attr
def __table_args__(cls):
Declarative API
API Reference
Provides a syntactical shortcut to the cls argument sent to declarative_base(), allowing the base class
to be converted in-place to a “declarative” base:
from sqlalchemy.ext.declarative import as_declarative
@as_declarative()
class Base(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
id = Column(Integer, primary_key=True)
class MyMappedClass(Base):
# ...
@declared_attr
def user(self):
return relationship("User")
It also can be applied to mapped classes, such as to provide a “polymorphic” scheme for inheritance:
class Employee(Base):
id = Column(Integer, primary_key=True)
type = Column(String(50), nullable=False)
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
@declared_attr
def __mapper_args__(cls):
if cls.__name__ == 'Employee':
return {
"polymorphic_on":cls.type,
"polymorphic_identity":"Employee"
}
else:
return {"polymorphic_identity":cls.__name__}
Changed in version 0.8: declared_attr can be used with non-ORM or extension attributes, such as user-
defined attributes or association_proxy() objects, which will be assigned to the class at class construc-
tion time.
cascading
Mark a declared_attr as cascading.
This is a special-use modifier which indicates that a column or MapperProperty-based declared attribute
should be configured distinctly per mapped subclass, within a mapped-inheritance scenario.
Below, both MyClass as well as MySubClass will have a distinct id Column object established:
class HasSomeAttribute(object):
@declared_attr.cascading
def some_id(cls):
if has_inherited_table(cls):
return Column(
ForeignKey('myclass.id'), primary_key=True)
else:
return Column(Integer, primary_key=True)
class MySubClass(MyClass):
""
# ...
The behavior of the above configuration is that MySubClass will refer to both its own id column as
well as that of MyClass underneath the attribute named some_id.
See also:
Inheritance Configuration
Mixing in Columns in Inheritance Scenarios
sqlalchemy.ext.declarative.api._declarative_constructor(self, **kwargs)
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in kwargs.
Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any
mapped columns or relationships.
sqlalchemy.ext.declarative.has_inherited_table(cls)
Given a class, return True if any of the classes it inherits from has a mapped table, otherwise return False.
sqlalchemy.ext.declarative.synonym_for(name, map_column=False)
Decorator, make a Python @property a query synonym for a column.
A decorator version of synonym(). The function being decorated is the ‘descriptor’, otherwise passes its
arguments through to synonym():
@synonym_for('col')
@property
def prop(self):
return 'special sauce'
The regular synonym() is also usable directly in a declarative setting and may be convenient for read/write
properties:
prop = synonym('col', descriptor=property(_read_prop, _write_prop))
sqlalchemy.ext.declarative.comparable_using(comparator_factory)
Decorator, allow a Python @property to be used in query criteria.
This is a decorator front end to comparable_property() that passes through the comparator_factory and
the function being decorated:
@comparable_using(MyComparatorType)
@property
def prop(self):
return 'special sauce'
The regular comparable_property() is also usable directly in a declarative setting and may be convenient
for read/write properties:
prop = comparable_property(MyComparatorType)
class Manager(Employee):
__tablename__ = 'manager'
employee_id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
'polymorphic_identity':'manager',
'concrete':True}
The abstract base class is handled by declarative in a special way; at class configuration time, it behaves like a
declarative mixin or an __abstract__ base class. Once classes are configured and mappings are produced,
it then gets mapped itself, but after all of its decscendants. This is a very unique system of mapping not found
in any other SQLAlchemy system.
Using this approach, we can specify columns and properties that will take place on mapped subclasses, in the
way that we normally do as in Mixin and Custom Base Classes:
class Company(Base):
__tablename__ = 'company'
id = Column(Integer, primary_key=True)
@declared_attr
def company_id(cls):
return Column(ForeignKey('company.id'))
@declared_attr
def company(cls):
return relationship("Company")
class Manager(Employee):
__tablename__ = 'manager'
name = Column(St