100% found this document useful (1 vote)
75 views

Object Relational Tutorial - SQLAlchemy 0.9 Documentation

SQLAlchemy Documentation for Python

Uploaded by

adityapurandare
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
75 views

Object Relational Tutorial - SQLAlchemy 0.9 Documentation

SQLAlchemy Documentation for Python

Uploaded by

adityapurandare
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 37

Object Relational Tutorial SQLAlchemy 0.

9 Documentation

SQLAlchemy 0.9 Documentation


SQLAlchemy 0.9
Documentation
Contents | Index
Search

SQLAlchemy ORM
Object Relational Tutorial
Version Check
Connecting
Declare a Mapping
Create a Schema
Create an Instance of the
Mapped Class
Creating a Session
Adding and Updating Objects
Rolling Back
Querying
Common Filter Operators
Returning Lists and Scalars
Using Textual SQL

6/27/16, 4:11 PM

Release: 0.9.10 | Release Date: July 22, 2015

Object Relational 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 system 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.

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 1 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Version Check
A quick check to verify that we are on at least version 0.9 of
SQLAlchemy:
>>> import sqlalchemy
>>> sqlalchemy.__version__
0.9.0

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 Pythons standard logging module.
With it enabled, well 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 doesnt get in our way; just click the SQL links to
see whats 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.
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 dont
use the Engine directly once
created; instead, its used behind
the scenes by the ORM as well see
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

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
Page 2 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

shortly.

6/27/16, 4:11 PM

database.

See also
Database Urls - includes examples of create_engine() connecting to
several kinds of databases with links to more information.

Declare a Mapping
When using the ORM, the configurational process starts by
describing the database tables well 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
>>> Base = 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 well 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)
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 3 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

...
...
...
...
...
...
...

6/27/16, 4:11 PM

name = Column(String)
fullname = Column(String)
password = Column(String)
def __repr__(self):
return "<User(name='%s', fullname='%s', password='
self.name, self.fullname, self

A class using Declarative at a


minimum needs a __tablename__
Tip
attribute, and at least one Column
The User class defines a
which is part of a primary key [1].
__repr__() method, but
SQLAlchemy never makes any
note that is optional; we only
assumptions by itself about the
implement it in this tutorial so
table to which a class refers,
that our examples show nicely
including that it has no built-in
formatted User objects.
conventions for names, datatypes,
or constraints. But this doesnt
mean boilerplate is required; instead, youre 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.
[1] For information on why a primary key is required, see How do I
map a table that has no primary key?.

Create a Schema
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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 4 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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=
Column('name', String(), table=<users>),
Column('fullname', String(), table=<users>),
Column('password', String(), table=<users>), schema

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 dont need to deal with
directly (though it can provide
plenty of information about our
mapping when we need it).

Classical Mappings
The Declarative system,
though highly recommended,
is not required in order to use
SQLAlchemys 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.

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.
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 dont 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) # doctest:+ELLIPSIS,+NORMA

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 5 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

PRAGMA table_info("users")
()
CREATE TABLE users (
id INTEGER NOT NULL,
name VARCHAR,
fullname VARCHAR,
password VARCHAR,
PRIMARY KEY (id)
)
()
COMMIT

Minimal Table Descriptions vs. Full Descriptions


Users familiar with the syntax of CREATE TABLE may notice that the
VARCHAR columns were generated without a length; on SQLite and
Postgresql, this is a valid datatype, but on others, its not allowed. So if
running this tutorial on one of those databases, and you wish to use
SQLAlchemy to issue CREATE TABLE, a length may be provided to the

String type as below:


Column(String(50))
The length field on String , as well as similar precision/scale fields
available on Integer , Numeric , etc. are not referenced by SQLAlchemy
other than when creating tables.
Additionally, Firebird and Oracle require sequences to generate new
primary key identifiers, and SQLAlchemy doesnt generate or assume
these without being instructed. For that, you use the Sequence
construct:
from sqlalchemy import Sequence
Column(Integer, Sequence('user_id_seq'), primary_key=True)
A full, foolproof Table generated via our declarative mapping is
therefore:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 6 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>"
self.name, self.fullname, self
We include this more verbose table definition separately to highlight the
difference between a minimal construct geared primarily towards inPython usage only, versus one that will be used to emit CREATE TABLE
statements on a particular set of backends with more stringent
requirements.

Create an Instance of the Mapped Class


With mappings complete, lets now create and inspect a User
object:
>>> ed_user = User(name='ed', fullname='Ed Jones', password
>>> ed_user.name
'ed'
>>> ed_user.password
'edspassword'
>>> str(ed_user.id)
'None'

Even though we didnt specify it in


the constructor, the id attribute
still produces a value of None when
we access it (as opposed to
Pythons usual behavior of raising
AttributeError for an undefined
attribute). SQLAlchemys
instrumentation normally produces
this default value for columnmapped attributes when first
accessed. For those attributes
where weve actually assigned a
value, the instrumentation system
is tracking those assignments for
use within an eventual INSERT
statement to be emitted to the
database.

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

the __init__() method


Our User class, as defined
using the Declarative system,
has been provided with a
constructor (e.g. __init__()
method) which automatically
accepts keyword names that
match the columns weve
mapped. We are free to define
any explicit __init__()
method we prefer on our
class, which will override the
default method provided by
Declarative.

Page 7 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Creating a Session
Were now ready to start talking to the database. The ORMs
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)

This custom-made Session class


will create new Session objects
which are bound to our database.
Other transactional 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 hasnt opened any
connections yet. When its first
used, it retrieves a connection from
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

# once engine is available

Session Lifecycle Patterns


The question of when to make
a Session depends a lot on
what kind of application is
being built. Keep in mind, the

Session is just a workspace


for your objects, local to a
particular database connection
- if you think of an application
thread as a guest at a dinner
party, the Session is the
guests plate and the objects it
holds are the food (and the
database...the kitchen?)! More
on this topic available at When
do I construct a Session, when
do I commit it, and when do I
Page 8 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

a pool of connections maintained


by the Engine , and holds onto it
until we commit all changes and/or
close the session object.

6/27/16, 4:11 PM

close it?.

Adding and Updating Objects


To persist our User object, we add() it to our Session :
>>> ed_user = User(name='ed', fullname='Ed Jones', password
>>> session.add(ed_user)

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 wed like only the first result in the full list of rows. A
User instance is returned which is equivalent to that which weve
added:
>>> our_user = session.query(User).filter_by(name='ed').first
SQL
>>> 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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 9 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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
...
User(name='mary', fullname='Mary Contrary', password
...
User(name='fred', fullname='Fred Flinstone', password

Also, weve decided the password for Ed isnt 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

and that three new User objects are pending:


>>> session.new # doctest: +SKIP
IdentitySet([<User(name='wendy', fullname='Wendy Williams',
<User(name='mary', fullname='Mary Contrary', password='xxg527'
<User(name='fred', fullname='Fred Flinstone', password='blah'

We tell the Session that wed 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 weve
added:
>>> session.commit()

SQL

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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 10 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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 Eds id attribute, which earlier was None , it now
has a value:
>>> ed_user.id # doctest: +NORMALIZE_WHITESPACE
1

SQL

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-firstaccess. 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 its 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.

Session Object States


As our User object moved from being outside the Session , to inside
the Session without a primary key, to actually being inserted, it moved
between three out of four available object states - transient,
pending, and persistent. Being aware of these states and what they
mean is always a good idea - be sure to read Quickie Intro to Object
States for a quick overview.

Rolling Back
Since the Session works within a transaction, we can roll back
changes made too. Lets make two changes that well revert;
ed_user s user name gets set to Edwardo :
>>> ed_user.name = 'Edwardo'

and well add another erroneous user, fake_user :

>>> fake_user = User(name='fakeuser', fullname='Invalid', passw


http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 11 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

>>> session.add(fake_user)

Querying the session, we can see that theyre flushed into the
current transaction:

>>> session.query(User).filter(User.name.in_(['Edwardo',
SQL 'fakeu
[<User(name='Edwardo', fullname='Ed Jones', password='f8s7ccs'

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()

SQL

>>> ed_user.name #doctest: +NORMALIZE_WHITESPACE


u'ed'
>>> fake_user in session
False

SQL

issuing a SELECT illustrates the changes made to the database:


>>> session.query(User).filter(User.name.in_(['ed', SQL
'fakeuser'
[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>

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):
SQL
...
print instance.name, instance.fullname
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

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 12 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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.fullnam


SQL
...
print name, fullname
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 attributes name
for an attribute, and the class name for a class:

>>> for row in session.query(User, User.name).all():SQL


#doctest:
...
print row.User, row.name
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
<User(name='wendy', fullname='Wendy Williams', password='foobar
<User(name='mary', fullname='Mary Contrary', password='xxg527'
<User(name='fred', fullname='Fred Flinstone', password='blah'

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'))
SQL
...
print(row.name_label)
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')
>>> for row in session.query(user_alias, user_alias.name).all
SQL
...
print row.user_alias
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 13 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

<User(name='wendy', fullname='Wendy Williams', password='foobar


<User(name='mary', fullname='Mary Contrary', password='xxg527'
<User(name='fred', fullname='Fred Flinstone', password='blah'

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]:


SQL #docte
...
print u
<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).\


SQL
...
filter_by(fullname='Ed Jones'): # doctest: +NOR
...
print name
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).\


SQL
...
filter(User.fullname=='Ed Jones'): # doctest: +
...
print name
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).\


SQL
...
filter(User.name=='ed').\
...
filter(User.fullname=='Ed Jones'): # doctest: +NOR
...
print user
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>

Common Filter Operators


http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 14 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Heres a rundown of some of the most common operators used in


filter() :

equals :
query.filter(User.name == 'ed')

not equals :
query.filter(User.name != 'ed')

LIKE :
query.filter(User.name.like('%ed%'))

IN :
query.filter(User.name.in_(['ed', 'wendy', 'jack']))
# works with query objects too:
query.filter(User.name.in_(
session.query(User.name).filter(User.name.like
))

NOT IN :
query.filter(~User.name.in_(['ed', 'wendy', 'jack']))

IS NULL :
query.filter(User.name == None)
# alternatively, if pep8/linters are a concern
query.filter(User.name.is_(None))

IS NOT NULL :
query.filter(User.name != None)
# alternatively, if pep8/linters are a concern
query.filter(User.name.isnot(None))

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 15 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

AND :
# use and_()
from sqlalchemy import and_
query.filter(and_(User.name == 'ed', User.fullname ==

# or send multiple expressions to .filter()


query.filter(User.name == 'ed', User.fullname == 'Ed Jones
# or chain multiple filter()/filter_by() calls
query.filter(User.name == 'ed').filter(User.fullname ==

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.

Returning Lists and Scalars


A number of methods on Query immediately issue SQL and
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 16 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

return a value containing loaded database results. Heres a brief


tour:

all() returns a list:

>>> query = session.query(User).filter(User.name.like(


>>> query.all() #doctest: +NORMALIZE_WHITESPACESQL
[<User(name='ed', fullname='Ed Jones', password='f8s7ccs'
<User(name='fred', fullname='Fred Flinstone', passwo

first() applies a limit of one and returns the first result


as a scalar:
>>> query.first() #doctest: +NORMALIZE_WHITESPACE
SQL
<User(name='ed', fullname='Ed Jones', password='f8s7ccs'

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:
>>> from sqlalchemy.orm.exc import MultipleResultsFound
SQL
>>> try: #doctest: +NORMALIZE_WHITESPACE
...
user = query.one()
... except MultipleResultsFound, e:
...
print e
Multiple rows were found for one()

With no rows found:


>>> from sqlalchemy.orm.exc import NoResultFound
SQL
>>> try: #doctest: +NORMALIZE_WHITESPACE
...
user = query.filter(User.id == 99).one()
... except NoResultFound, e:
...
print e
No row was 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.

scalar() invokes the one() method, and upon success


returns the first column of the row:
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 17 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

>>> query = session.query(User.id).filter(User.name ==


...
order_by(User.id)
>>> query.scalar() #doctest: +NORMALIZE_WHITESPACE
SQL
1

Using Textual SQL


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).\
SQL
...
filter(text("id<224")).\
...
order_by(text("id")).all(): #doctest: +NORMALIZ
...
print user.name
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"
SQL
...
params(value=224, name='fred').order_by(User.id).one
<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(
SQL
...
text("SELECT * FROM users where name=:n
...
params(name='ed').all()
[<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>

See also
Using Textual SQL - The text() construct explained from the
perspective of Core-only queries.

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 18 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Counting
Query includes a convenience method for counting called
count() :
>>> session.query(User).filter(User.name.like('%ed')).count
SQL
2

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
dont try to guess when this is
appropriate, as the exact SQL can
be emitted using more explicit
means.

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 wouldnt do the
right thing. Now that it uses a
simple subquery every time,
its only two lines long and
always returns the right
answer. Use func.count() if
a particular statement

absolutely cannot tolerate the


For situations where the thing to
subquery being present.
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
SQL
[(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
SQL
4

The usage of select_from() can be removed if we express the


http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 19 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

count in terms of the User primary key directly:

>>> session.query(func.count(User.id)).scalar() #doctest:


SQL +NORM
4

Building a Relationship
Lets 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, backref

>>> 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", backref=backref('addresses'
...
...
def __repr__(self):
...
return "<Address(email_address='%s')>" % self.email

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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 20 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

nature of this linkage, determining that Address.user will be


many to one. A subdirective of relationship() called
backref() is placed inside of relationship() , providing
details about the relationship as expressed in reverse, that of a
collection of Address objects on User referenced by
User.addresses . 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 Declarative 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. Below we illustrate creation of the same
addresses/user bidirectional relationship in terms of User
instead of Address :
class User(Base):
# ....
addresses = relationship("Address", order_by="Address.id"

See the docstring for relationship() for more detail on


argument style.

Did you know ?


a FOREIGN KEY constraint in most (though not all) relational
databases can only link to a primary key column, or a column that
has a UNIQUE constraint.
a FOREIGN KEY constraint that refers to a multiple column primary
key, and itself has multiple columns, is known as a composite
foreign key. It can also reference a subset of those columns.
FOREIGN KEY columns can automatically update themselves, in
response to a change in the referenced column or row. This is
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 21 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

known as the CASCADE referential action, and is a built in function


of the relational database.
FOREIGN KEY can refer to its own table. This is referred to as a
self-referential foreign key.
Read more about foreign keys at Foreign Key - Wikipedia.

Well 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) # doctest: +NORMALIZE_WHIT


SQL

Working with Related Objects


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
>>> 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')

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 22 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Lets 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()

SQL

Querying for Jack, we get just Jack back. No SQL is yet issued for
Jacks addresses:

>>> jack = session.query(User).\


SQL
... filter_by(name='jack').one() #doctest: +NORMALIZE_WHITESPAC
>>> jack
<User(name='jack', fullname='Jack Bean', password='gjffdd')

Lets look at the addresses collection. Watch the SQL:

>>> jack.addresses #doctest: +NORMALIZE_WHITESPACE SQL


[<Address(email_address='[email protected]')>, <Address(email_add

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. Well cover ways to optimize the loading of this
collection in a bit.

Querying with Joins


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 well
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).\
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

SQL
Page 23 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

...
filter(User.id==Address.user_id).\
...
filter(Address.email_address=='jack@goo
...
all():
# doctest: +NORMALIZE_WHITESPA
...
print u
...
print a
<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).\
SQL
...
filter(Address.email_address=='[email protected]'
...
all() #doctest: +NORMALIZE_WHITESPACE
[<User(name='jack', fullname='Jack Bean', password='gjffdd'

Query.join() knows how to join between User and Address


because theres 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)
query.join(User.addresses)
query.join(Address, User.addresses)
query.join('addresses')

#
#
#
#

explicit con
specify rela
same, with e
same, using

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.

What does Query select from if theres multiple entities?


The Query.join() method will typically join from the leftmost item
in the list of entities, when the ON clause is omitted, or if the ON clause
is a plain SQL expression. To control the first entity in the list of JOINs,
use the Query.select_from() method:

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 24 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

query = Session.query(User, Address).select_from(Address).join

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 \
SQL
...
session.query(User.name, adalias1.email_address, adalia
...
join(adalias1, User.addresses).\
...
join(adalias2, User.addresses).\
...
filter(adalias1.email_address=='[email protected]').\
...
filter(adalias2.email_address=='[email protected]'):
...
print username, email1, email2
# doctest: +NORMALI
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 dont have any addresses, e.g.:

SELECT users.*, adr_count.address_count FROM users LEFT OUTER J


(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 http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 25 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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 (its 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


SQL
...
outerjoin(stmt, User.id==stmt.c.user_id).order_by(User
...
print u, count
<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>
<User(name='wendy', fullname='Wendy Williams', password='foobar
<User(name='mary', fullname='Mary Contrary', password='xxg527'
<User(name='fred', fullname='Fred Flinstone', password='blah'
<User(name='jack', fullname='Jack Bean', password='gjffdd')

Selecting Entities from Subqueries


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:

>>> stmt = session.query(Address).\


SQL
...
filter(Address.email_address != 'j25@yahoo.
...
subquery()
>>> adalias = aliased(Address, stmt)
>>> for user, address in session.query(User, adalias).\
...
join(adalias, User.addresses): # doctest: +NORMALIZ
...
print user
...
print address
<User(name='jack', fullname='Jack Bean', password='gjffdd')
<Address(email_address='[email protected]')>

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 26 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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):
SQL
...
print name
jack

# doc

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).\


SQL
...
filter(User.addresses.any()):
# doctest: +NORMALI
...
print name
jack

any() takes criterion as well, to limit the rows matched:


>>> for name, in session.query(User.name).\
SQL
...
filter(User.addresses.any(Address.email_address.like
...
print name
jack

has() is the same operator as any() for many-to-one


relationships (note the ~ operator here too, which means NOT):
>>> session.query(Address).\
SQL
...
filter(~Address.user.has(User.name=='jack')).all
[]

Common Relationship Operators


Heres all the operators which build on relationships - each one is
linked to its API documentation which includes full details on
usage and behavior:
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 27 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

__eq__() (many-to-one equals comparison):


query.filter(Address.user == someuser)

__ne__() (many-to-one not equals comparison):


query.filter(Address.user != someuser)

IS NULL (many-to-one comparison, also uses __eq__() ):


query.filter(Address.user == None)

contains() (used for one-to-many collections):


query.filter(User.addresses.contains(someaddress))

any() (used for collections):


query.filter(User.addresses.any(Address.email_address
# also takes keyword arguments:
query.filter(User.addresses.any(email_address='bar'))

has() (used for scalar references):


query.filter(Address.user.has(name='ed'))

Query.with_parent() (used for any relationship):


session.query(Address).with_parent(someuser, 'addresses'

Eager Loading
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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 28 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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 wed 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).\
SQL
...
options(subqueryload(User.addresses)).\
...
filter_by(name='jack').one() #doctest: +NOR
>>> jack
<User(name='jack', fullname='Jack Bean', password='gjffdd')

>>> jack.addresses
[<Address(email_address='[email protected]')>, <Address(email_add

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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 29 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

is actually populated right now, the query will emit the extra join
regardless:
>>> from sqlalchemy.orm import joinedload

>>> jack = session.query(User).\


SQL
...
options(joinedload(User.addresses
...
filter_by(name='jack').one() #doctes
>>> jack
<User(name='jack', fullname='Jack Bean', password='gjffdd')

>>> jack.addresses
[<Address(email_address='[email protected]')>, <Address(email_add

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.

joinedload() is not a replacement for join()


The join created by joinedload() is anonymously aliased such that it
does not affect the query results. An Query.order_by() or

Query.filter() call cannot reference these aliased tables - so-called


user space joins are constructed using Query.join() . The rationale
for this is that joinedload() is only applied in order to affect how
related objects or collections are loaded as an optimizing detail - it can
be added or removed with no impact on actual results. See the section
The Zen of Eager Loading for a detailed description of how this is used.

Explicit Join + Eagerload


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
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 30 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

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).\
SQL
...
join(Address.user).\
...
filter(User.name=='jack').\
...
options(contains_eager(Address
...
all() #doctest: +NORMALIZE_WHIT
>>> jacks_addresses
[<Address(email_address='[email protected]')>, <Address(email_add
>>> 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.

Deleting
Lets try to delete jack and see how that goes. Well mark as
deleted in the session, then well issue a count query to see that
no rows remain:

>>> session.delete(jack)
>>> session.query(User).filter_by(name='jack').count()
SQL# doctes
0

So far, so good. How about Jacks Address objects ?

>>> session.query(Address).filter(
SQL
...
Address.email_address.in_(['[email protected]', 'j25@yaho
... ).count() # doctest: +NORMALIZE_WHITESPACE
2

Uh oh, theyre still there ! Analyzing the flush SQL, we can see

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 31 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

that the user_id column of each address was set to NULL, but
the rows werent deleted. SQLAlchemy doesnt assume that
deletes cascade, you have to tell it to do so.

Configuring delete/delete-orphan Cascade


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 - well close the Session :
>>> session.close()

and use a new declarative_base() :


>>> Base = declarative_base()

Next well declare the User class, adding in the addresses


relationship including the cascade configuration (well 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", backref='user',
...
cascade="all, delete, delete-orphan"
...
...
def __repr__(self):
...
return "<User(name='%s', fullname='%s', password'
...
self.name, self.fullname

Then we recreate Address , noting that in this case weve created


the Address.user relationship via the User class already:
>>> class Address(Base):
...
__tablename__ = 'addresses'
...
id = Column(Integer, primary_key=True)
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 32 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

...
...
...
...
...

6/27/16, 4:11 PM

email_address = Column(String, nullable=False)


user_id = Column(Integer, ForeignKey('users.id'))

def __repr__(self):
return "<Address(email_address='%s')>" % self.email

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:
# load Jack by primary key
>>> jack = session.query(User).get(5)

#doctest: +NORMALIZE_W
SQL

# remove one Address (lazy load fires off)


>>> del jack.addresses[1] #doctest: +NORMALIZE_WHITESPACE
SQL

# only one address remains


>>> session.query(Address).filter(
SQL
...
Address.email_address.in_(['[email protected]', 'j25@yaho
... ).count() # doctest: +NORMALIZE_WHITESPACE
1

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()
SQL# doctes
0

>>> session.query(Address).filter(
SQL
...
Address.email_address.in_(['[email protected]', 'j25@yahoo
... ).count() # doctest: +NORMALIZE_WHITESPACE
0

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.

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 33 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Building a Many To Many Relationship


Were moving into the bonus round here, but lets show off a
many-to-many relationship. Well sneak in some other features
too, just to take a tour. Well 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', Integer, ForeignKey('posts.id')),
Column('keyword_id', Integer, ForeignKey('keywords.id'
)

Above, we can see declaring a Table directly is a little different


than declaring a mapped class. Table is a constructor 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 , with a
relationship() linked via the post_keywords 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_keywo
...
...
def __init__(self, headline, body, author):
...
self.author = author
...
self.headline = headline
...
self.body = body
...
...
def __repr__(self):
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 34 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

...

6/27/16, 4:11 PM

return "BlogPost(%r, %r, %r)" % (self.headline,

>>> class Keyword(Base):


...
__tablename__ = 'keywords'
...
...
id = Column(Integer, primary_key=True)
...
keyword = Column(String(50), nullable=False, unique
...
...
def __init__(self, keyword):
...
self.keyword = keyword

Note
The above class declarations illustrate explicit __init__() methods.
Remember, when using Declarative, its optional!

Above, the many-to-many relationship is BlogPost.keywords .


The defining feature of a many-to-many relationship 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 relationship, except one
issue well have is that a single user might have lots of blog
posts. When we access User.posts , wed 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. To use it on the reverse side of a
relationship() , we use the backref() function:

>>> from sqlalchemy.orm import backref


>>> # "dynamic" loading relationship to User
>>> BlogPost.author = relationship(User, backref=backref('posts

Create new tables:

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 35 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

>>> Base.metadata.create_all(engine) # doctest: +NORMALIZE_WHIT

SQL
Usage is not too different from what weve been doing. Lets give
Wendy some blog posts:
>>> wendy = session.query(User).\
SQL
...
filter_by(name='wendy').\
...
one() #doctest: +NORMALIZE_WHITESPACE
>>> post = BlogPost("Wendy's Blog Post", "This is a test",
>>> session.add(post)

Were storing keywords uniquely in the database, but we know


that we dont 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.
Well use the any operator to locate blog posts where any of its
keywords has the keyword string firstpost:

>>> session.query(BlogPost).\
SQL
...
filter(BlogPost.keywords.any(keyword='firstpost
...
all() #doctest: +NORMALIZE_WHITESPACE
[BlogPost("Wendy's Blog Post", 'This is a test', <User(name

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).\
SQL
...
filter(BlogPost.author==wendy).\
...
filter(BlogPost.keywords.any(keyword='firstpost
...
all() #doctest: +NORMALIZE_WHITESPACE
[BlogPost("Wendy's Blog Post", 'This is a test', <User(name

Or we can use Wendys own posts relationship, which is a


dynamic relationship, to query straight from there:
>>> wendy.posts.\
SQL
...
filter(BlogPost.keywords.any(keyword='firstpost'
...
all() #doctest: +NORMALIZE_WHITESPACE
[BlogPost("Wendy's Blog Post", 'This is a test', <User(name
http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 36 of 37

Object Relational Tutorial SQLAlchemy 0.9 Documentation

6/27/16, 4:11 PM

Further Reference
Query Reference: query_api_toplevel
Mapper Reference: Mapper Configuration
Relationship Reference: Relationship Configuration
Session Reference: Using the Session

Previous: SQLAlchemy ORM Next: Mapper Configuration


Copyright 2007-2015, the SQLAlchemy authors and contributors. Created using Sphinx 1.3.6.

Website content copyright by SQLAlchemy authors and contributors. SQLAlchemy and its documentation are
licensed under the MIT license.
SQLAlchemy is a trademark of Michael Bayer. mike(&)zzzcomputing.com All rights reserved.
Website generation by Blogofile and Mako Templates for Python.

http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html

Page 37 of 37

You might also like