Object Relational Tutorial


In [116]:
import sqlalchemy

from sqlalchemy import func
from sqlalchemy import text
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy import ForeignKey
from sqlalchemy import Table, Text

from sqlalchemy.sql import exists
from sqlalchemy.sql import func

from sqlalchemy.orm import relationship
from sqlalchemy.orm import aliased
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import selectinload
from sqlalchemy.orm import contains_eager

from sqlalchemy.ext.declarative import declarative_base

## Version Check
sqlalchemy.__version__


Out[116]:
'1.3.7'

Connecting


In [117]:
engine = create_engine('sqlite:///:memory:', echo=True)

In [118]:
Base = declarative_base()

Creating a Session


In [119]:
Session = sessionmaker(bind=engine)

In [120]:
session = Session()

Declare a Mapping


In [6]:
class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    nickname = Column(String)
    
    def __repr__(self):
        return "<User(name='{}', fullname='{}', nickname='{}')>".format(
        self.name, self.fullname, self.nickname)

Create a Schema


In [7]:
User.__table__


Out[7]:
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('nickname', String(), table=<users>), schema=None)

In [8]:
Base.metadata.create_all(engine)


2019-09-28 23:42:34,489 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2019-09-28 23:42:34,495 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:34,497 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2019-09-28 23:42:34,497 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:34,499 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("users")
2019-09-28 23:42:34,500 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:34,501 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("users")
2019-09-28 23:42:34,501 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:34,504 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE users (
	id INTEGER NOT NULL, 
	name VARCHAR, 
	fullname VARCHAR, 
	nickname VARCHAR, 
	PRIMARY KEY (id)
)


2019-09-28 23:42:34,505 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:34,506 INFO sqlalchemy.engine.base.Engine COMMIT

Create an Instance of the Mapped Class


In [9]:
ed_user = User(name='ed', fullname='Ed Jones', nickname='ednickname')

Adding and Updating Objects


In [10]:
session.add(ed_user)

In [11]:
our_user = session.query(User).filter_by(name='ed').first()


2019-09-28 23:42:34,531 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-09-28 23:42:34,533 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-09-28 23:42:34,534 INFO sqlalchemy.engine.base.Engine ('ed', 'Ed Jones', 'ednickname')
2019-09-28 23:42:34,537 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name = ?
 LIMIT ? OFFSET ?
2019-09-28 23:42:34,539 INFO sqlalchemy.engine.base.Engine ('ed', 1, 0)

In [12]:
ed_user is our_user


Out[12]:
True

In [13]:
session.add_all([
    User(name='wendy', fullname='Wendy Williams', nickname='windy'),
    User(name='mary', fullname='Mary Contrary', nickname='mary'),
    User(name='fred', fullname='Fred Flintstone', nickname='freddy')
])

In [14]:
ed_user.nickname = 'eddie'

In [15]:
session.dirty


Out[15]:
IdentitySet([<User(name='ed', fullname='Ed Jones', nickname='eddie')>])

In [16]:
session.new


Out[16]:
IdentitySet([<User(name='wendy', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>, <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>])

In [17]:
session.commit()


2019-09-28 23:42:34,590 INFO sqlalchemy.engine.base.Engine UPDATE users SET nickname=? WHERE users.id = ?
2019-09-28 23:42:34,594 INFO sqlalchemy.engine.base.Engine ('eddie', 1)
2019-09-28 23:42:34,595 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-09-28 23:42:34,596 INFO sqlalchemy.engine.base.Engine ('wendy', 'Wendy Williams', 'windy')
2019-09-28 23:42:34,597 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-09-28 23:42:34,598 INFO sqlalchemy.engine.base.Engine ('mary', 'Mary Contrary', 'mary')
2019-09-28 23:42:34,599 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-09-28 23:42:34,600 INFO sqlalchemy.engine.base.Engine ('fred', 'Fred Flintstone', 'freddy')
2019-09-28 23:42:34,602 INFO sqlalchemy.engine.base.Engine COMMIT

In [18]:
ed_user.id


2019-09-28 23:42:34,610 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-09-28 23:42:34,611 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.id = ?
2019-09-28 23:42:34,612 INFO sqlalchemy.engine.base.Engine (1,)
Out[18]:
1

Rolling Back


In [19]:
ed_user.name = 'Edwardo'

In [20]:
fake_user = User(name='fakeuser', fullname='Invalid', nickname='12345')
session.add(fake_user)

In [21]:
session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()


2019-09-28 23:42:34,640 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
2019-09-28 23:42:34,642 INFO sqlalchemy.engine.base.Engine ('Edwardo', 1)
2019-09-28 23:42:34,643 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-09-28 23:42:34,644 INFO sqlalchemy.engine.base.Engine ('fakeuser', 'Invalid', '12345')
2019-09-28 23:42:34,645 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name IN (?, ?)
2019-09-28 23:42:34,646 INFO sqlalchemy.engine.base.Engine ('Edwardo', 'fakeuser')
Out[21]:
[<User(name='Edwardo', fullname='Ed Jones', nickname='eddie')>,
 <User(name='fakeuser', fullname='Invalid', nickname='12345')>]

In [22]:
session.rollback()


2019-09-28 23:42:34,653 INFO sqlalchemy.engine.base.Engine ROLLBACK

In [23]:
ed_user.name


2019-09-28 23:42:34,668 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-09-28 23:42:34,669 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.id = ?
2019-09-28 23:42:34,670 INFO sqlalchemy.engine.base.Engine (1,)
Out[23]:
'ed'

In [24]:
fake_user in session


Out[24]:
False

In [25]:
session.query(User).filter(User.name.in_(['ed', 'fakeuser'])).all()


2019-09-28 23:42:34,694 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name IN (?, ?)
2019-09-28 23:42:34,695 INFO sqlalchemy.engine.base.Engine ('ed', 'fakeuser')
Out[25]:
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]

Querying


In [26]:
for instance in session.query(User).order_by(User.id):
    print(instance.name, instance.fullname)


2019-09-28 23:42:34,706 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users ORDER BY users.id
2019-09-28 23:42:34,708 INFO sqlalchemy.engine.base.Engine ()
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flintstone

In [27]:
for name, fullname in session.query(User.name, User.fullname):
    print(name, fullname)


2019-09-28 23:42:34,717 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name, users.fullname AS users_fullname 
FROM users
2019-09-28 23:42:34,718 INFO sqlalchemy.engine.base.Engine ()
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flintstone

In [28]:
for row in session.query(User, User.name).all():
    print(row.User, row.name)


2019-09-28 23:42:34,726 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users
2019-09-28 23:42:34,728 INFO sqlalchemy.engine.base.Engine ()
<User(name='ed', fullname='Ed Jones', nickname='eddie')> ed
<User(name='wendy', fullname='Wendy Williams', nickname='windy')> wendy
<User(name='mary', fullname='Mary Contrary', nickname='mary')> mary
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')> fred

In [29]:
for row in session.query(User.name.label('name_label')).all():
    print(row.name_label)


2019-09-28 23:42:34,737 INFO sqlalchemy.engine.base.Engine SELECT users.name AS name_label 
FROM users
2019-09-28 23:42:34,738 INFO sqlalchemy.engine.base.Engine ()
ed
wendy
mary
fred

In [30]:
user_alias = aliased(User, name='user_alias')

In [31]:
for row in session.query(user_alias, user_alias.name).all():
    print(row.user_alias)


2019-09-28 23:42:34,760 INFO sqlalchemy.engine.base.Engine SELECT user_alias.id AS user_alias_id, user_alias.name AS user_alias_name, user_alias.fullname AS user_alias_fullname, user_alias.nickname AS user_alias_nickname 
FROM users AS user_alias
2019-09-28 23:42:34,761 INFO sqlalchemy.engine.base.Engine ()
<User(name='ed', fullname='Ed Jones', nickname='eddie')>
<User(name='wendy', fullname='Wendy Williams', nickname='windy')>
<User(name='mary', fullname='Mary Contrary', nickname='mary')>
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>

In [32]:
for u in session.query(User).order_by(User.id)[1:3]:
    print(u)


2019-09-28 23:42:34,772 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users ORDER BY users.id
 LIMIT ? OFFSET ?
2019-09-28 23:42:34,773 INFO sqlalchemy.engine.base.Engine (2, 1)
<User(name='wendy', fullname='Wendy Williams', nickname='windy')>
<User(name='mary', fullname='Mary Contrary', nickname='mary')>

In [33]:
for name, in session.query(User.name).filter_by(fullname='Ed Jones'):
    print(name)


2019-09-28 23:42:34,785 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
2019-09-28 23:42:34,786 INFO sqlalchemy.engine.base.Engine ('Ed Jones',)
ed

In [34]:
for name, in session.query(User.name).filter(User.fullname=='Ed Jones'):
    print(name)


2019-09-28 23:42:34,796 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
2019-09-28 23:42:34,797 INFO sqlalchemy.engine.base.Engine ('Ed Jones',)
ed

In [35]:
for user in session.query(User).filter(User.name=='ed').filter(User.fullname=='Ed Jones'):
    print(user)


2019-09-28 23:42:34,807 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name = ? AND users.fullname = ?
2019-09-28 23:42:34,809 INFO sqlalchemy.engine.base.Engine ('ed', 'Ed Jones')
<User(name='ed', fullname='Ed Jones', nickname='eddie')>

Returning Lists and Scalars


In [36]:
query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
query.all()


2019-09-28 23:42:34,820 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
2019-09-28 23:42:34,821 INFO sqlalchemy.engine.base.Engine ('%ed',)
Out[36]:
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>,
 <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]

In [37]:
query.first()


2019-09-28 23:42:34,834 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
 LIMIT ? OFFSET ?
2019-09-28 23:42:34,835 INFO sqlalchemy.engine.base.Engine ('%ed', 1, 0)
Out[37]:
<User(name='ed', fullname='Ed Jones', nickname='eddie')>

In [38]:
# ERROR
# user = query.one()

In [39]:
query = session.query(User.id).filter(User.name == 'ed').order_by(User.id)

In [40]:
query.scalar()


2019-09-28 23:42:34,862 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id 
FROM users 
WHERE users.name = ? ORDER BY users.id
2019-09-28 23:42:34,864 INFO sqlalchemy.engine.base.Engine ('ed',)
Out[40]:
1

Using Textual SQL


In [41]:
for user in session.query(User).filter(text("id < 10")).order_by(text("id")).all():
    print(user.name)


2019-09-28 23:42:34,874 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE id < 10 ORDER BY id
2019-09-28 23:42:34,875 INFO sqlalchemy.engine.base.Engine ()
ed
wendy
mary
fred

In [42]:
session.query(User).filter(text("id < :value and name = :name")).params(value = 10, name = 'fred').order_by(User.id).one()


2019-09-28 23:42:34,885 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE id < ? and name = ? ORDER BY users.id
2019-09-28 23:42:34,886 INFO sqlalchemy.engine.base.Engine (10, 'fred')
Out[42]:
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>

In [43]:
session.query(User).from_statement(text(
    "SELECT * FROM users WHERE name = :name"
)).params(name = 'ed').all()


2019-09-28 23:42:34,900 INFO sqlalchemy.engine.base.Engine SELECT * FROM users WHERE name = ?
2019-09-28 23:42:34,901 INFO sqlalchemy.engine.base.Engine ('ed',)
Out[43]:
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]

In [44]:
stmt = text("SELECT name, id, fullname, nickname FROM users WHERE name = :name")
stmt = stmt.columns(User.name, User.id, User.fullname, User.nickname)

session.query(User).from_statement(stmt).params(name='ed').all()


2019-09-28 23:42:34,915 INFO sqlalchemy.engine.base.Engine SELECT name, id, fullname, nickname FROM users WHERE name = ?
2019-09-28 23:42:34,916 INFO sqlalchemy.engine.base.Engine ('ed',)
Out[44]:
[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]

In [45]:
stmt = text("SELECT name, id FROM users WHERE name = :name")
stmt = stmt.columns(User.name, User.id)

session.query(User.id, User.name).from_statement(stmt).params(name='ed').all()


2019-09-28 23:42:34,929 INFO sqlalchemy.engine.base.Engine SELECT name, id FROM users WHERE name = ?
2019-09-28 23:42:34,930 INFO sqlalchemy.engine.base.Engine ('ed',)
Out[45]:
[(1, 'ed')]

Counting


In [46]:
session.query(User).filter(User.name.like('%ed')).count()


2019-09-28 23:42:34,943 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1 
FROM (SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name LIKE ?) AS anon_1
2019-09-28 23:42:34,945 INFO sqlalchemy.engine.base.Engine ('%ed',)
Out[46]:
2

In [47]:
session.query(func.count(User.name), User.name).group_by(User.name).all()


2019-09-28 23:42:34,956 INFO sqlalchemy.engine.base.Engine SELECT count(users.name) AS count_1, users.name AS users_name 
FROM users GROUP BY users.name
2019-09-28 23:42:34,957 INFO sqlalchemy.engine.base.Engine ()
Out[47]:
[(1, 'ed'), (1, 'fred'), (1, 'mary'), (1, 'wendy')]

In [48]:
session.query(func.count('*')).select_from(User).scalar()


2019-09-28 23:42:34,972 INFO sqlalchemy.engine.base.Engine SELECT count(?) AS count_1 
FROM users
2019-09-28 23:42:34,974 INFO sqlalchemy.engine.base.Engine ('*',)
Out[48]:
4

In [49]:
session.query(func.count(User.id)).scalar()


2019-09-28 23:42:34,984 INFO sqlalchemy.engine.base.Engine SELECT count(users.id) AS count_1 
FROM users
2019-09-28 23:42:34,985 INFO sqlalchemy.engine.base.Engine ()
Out[49]:
4

Building a Relationship


In [50]:
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={})>".format(self.email_address)

In [51]:
User.addresses = relationship("Address", order_by=Address.id, back_populates="user")

In [52]:
Base.metadata.create_all(engine)


2019-09-28 23:42:35,021 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("users")
2019-09-28 23:42:35,022 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:35,023 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("addresses")
2019-09-28 23:42:35,024 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:35,026 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("addresses")
2019-09-28 23:42:35,027 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:35,029 INFO sqlalchemy.engine.base.Engine 
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)
)


2019-09-28 23:42:35,030 INFO sqlalchemy.engine.base.Engine ()
2019-09-28 23:42:35,031 INFO sqlalchemy.engine.base.Engine COMMIT

In [53]:
jack = User(name='jack', fullname='Jack Bean', nickname='jacknick')
jack.addresses


Out[53]:
[]

In [54]:
jack.addresses = [Address(email_address='jack@gmail.com'),
                 Address(email_address='jack@yahoo.com')]

In [55]:
jack.addresses[1]


Out[55]:
<Address(email_address=jack@yahoo.com)>

In [56]:
jack.addresses[1].user


Out[56]:
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>

In [57]:
session.add(jack)
session.commit()


2019-09-28 23:42:35,083 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-09-28 23:42:35,085 INFO sqlalchemy.engine.base.Engine ('jack', 'Jack Bean', 'jacknick')
2019-09-28 23:42:35,087 INFO sqlalchemy.engine.base.Engine INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
2019-09-28 23:42:35,088 INFO sqlalchemy.engine.base.Engine ('jack@gmail.com', 5)
2019-09-28 23:42:35,089 INFO sqlalchemy.engine.base.Engine INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
2019-09-28 23:42:35,090 INFO sqlalchemy.engine.base.Engine ('jack@yahoo.com', 5)
2019-09-28 23:42:35,092 INFO sqlalchemy.engine.base.Engine COMMIT

In [58]:
jack = session.query(User).filter_by(name='jack').one()
jack


2019-09-28 23:42:35,100 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-09-28 23:42:35,102 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name = ?
2019-09-28 23:42:35,103 INFO sqlalchemy.engine.base.Engine ('jack',)
Out[58]:
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>

In [59]:
jack.addresses


2019-09-28 23:42:35,117 INFO sqlalchemy.engine.base.Engine 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 ORDER BY addresses.id
2019-09-28 23:42:35,118 INFO sqlalchemy.engine.base.Engine (5,)
Out[59]:
[<Address(email_address=jack@gmail.com)>,
 <Address(email_address=jack@yahoo.com)>]

Querying with Joins


In [60]:
for u, a in session.query(User, Address).\
                            filter(User.id == Address.user_id).filter(Address.email_address == 'jack@gmail.com').all():
    print(u)
    print(a)


2019-09-28 23:42:35,133 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname, 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 = ?
2019-09-28 23:42:35,134 INFO sqlalchemy.engine.base.Engine ('jack@gmail.com',)
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>
<Address(email_address=jack@gmail.com)>

In [61]:
session.query(User).join(Address).filter(Address.email_address == 'jack@gmail.com').all()


2019-09-28 23:42:35,145 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users JOIN addresses ON users.id = addresses.user_id 
WHERE addresses.email_address = ?
2019-09-28 23:42:35,146 INFO sqlalchemy.engine.base.Engine ('jack@gmail.com',)
Out[61]:
[<User(name='jack', fullname='Jack Bean', nickname='jacknick')>]

Using Aliases


In [62]:
adalias1 = aliased(Address)
adalias2 = aliased(Address)

In [63]:
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 == 'jack@gmail.com').\
                                        filter(adalias2.email_address == 'jack@yahoo.com'):
    print(username, email1, email2)


2019-09-28 23:42:35,169 INFO sqlalchemy.engine.base.Engine 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 = ?
2019-09-28 23:42:35,171 INFO sqlalchemy.engine.base.Engine ('jack@gmail.com', 'jack@yahoo.com')
jack jack@gmail.com jack@yahoo.com

Using Subqueries


In [64]:
stmt = session.query(Address.user_id, func.count('*').label('address_count')).group_by(Address.user_id).subquery()

In [65]:
for u, count in session.query(User, stmt.c.address_count).\
                        outerjoin(stmt, User.id == stmt.c.address_count).order_by(User.id):
    print(u, count)


2019-09-28 23:42:35,195 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname, 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.address_count ORDER BY users.id
2019-09-28 23:42:35,196 INFO sqlalchemy.engine.base.Engine ('*',)
<User(name='ed', fullname='Ed Jones', nickname='eddie')> None
<User(name='wendy', fullname='Wendy Williams', nickname='windy')> 2
<User(name='mary', fullname='Mary Contrary', nickname='mary')> None
<User(name='fred', fullname='Fred Flintstone', nickname='freddy')> None
<User(name='jack', fullname='Jack Bean', nickname='jacknick')> None

Selecting Entities from Subqueries


In [66]:
stmt = session.query(Address).filter(Address.email_address != 'jack@yahoo.com').subquery()

In [67]:
adalias = aliased(Address, stmt)

In [68]:
for user, address in session.query(User, adalias).join(adalias, User.addresses):
    print(user)
    print(address)


2019-09-28 23:42:35,232 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname, anon_1.id AS anon_1_id, anon_1.email_address AS anon_1_email_address, anon_1.user_id AS anon_1_user_id 
FROM users JOIN (SELECT addresses.id AS id, addresses.email_address AS email_address, addresses.user_id AS user_id 
FROM addresses 
WHERE addresses.email_address != ?) AS anon_1 ON users.id = anon_1.user_id
2019-09-28 23:42:35,233 INFO sqlalchemy.engine.base.Engine ('jack@yahoo.com',)
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>
<Address(email_address=jack@gmail.com)>

Using EXISTS


In [69]:
stmt = exists().where(Address.user_id == User.id)

In [70]:
for name, in session.query(User.name).filter(stmt):
    print(name)


2019-09-28 23:42:35,253 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE EXISTS (SELECT * 
FROM addresses 
WHERE addresses.user_id = users.id)
2019-09-28 23:42:35,254 INFO sqlalchemy.engine.base.Engine ()
jack

In [71]:
for name, in session.query(User.name).filter(User.addresses.any()):
    print(name)


2019-09-28 23:42:35,264 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE EXISTS (SELECT 1 
FROM addresses 
WHERE users.id = addresses.user_id)
2019-09-28 23:42:35,266 INFO sqlalchemy.engine.base.Engine ()
jack

In [72]:
for name, in session.query(User.name).filter(User.addresses.any(Address.email_address.like('%gmail%'))):
    print(name)


2019-09-28 23:42:35,277 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE EXISTS (SELECT 1 
FROM addresses 
WHERE users.id = addresses.user_id AND addresses.email_address LIKE ?)
2019-09-28 23:42:35,278 INFO sqlalchemy.engine.base.Engine ('%gmail%',)
jack

In [73]:
session.query(Address).filter(~Address.user.has(User.name == 'jack')).all()


2019-09-28 23:42:35,288 INFO sqlalchemy.engine.base.Engine 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 = ?))
2019-09-28 23:42:35,289 INFO sqlalchemy.engine.base.Engine ('jack',)
Out[73]:
[]

Eager Loading

Selectin Load


In [74]:
jack = session.query(User).options(selectinload(User.addresses)).filter_by(name='jack').one()


2019-09-28 23:42:35,303 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name = ?
2019-09-28 23:42:35,305 INFO sqlalchemy.engine.base.Engine ('jack',)
2019-09-28 23:42:35,308 INFO sqlalchemy.engine.base.Engine SELECT addresses.user_id AS addresses_user_id, addresses.id AS addresses_id, addresses.email_address AS addresses_email_address 
FROM addresses 
WHERE addresses.user_id IN (?) ORDER BY addresses.user_id, addresses.id
2019-09-28 23:42:35,311 INFO sqlalchemy.engine.base.Engine (5,)

In [75]:
jack


Out[75]:
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>

In [76]:
jack.addresses


Out[76]:
[<Address(email_address=jack@gmail.com)>,
 <Address(email_address=jack@yahoo.com)>]

Joined Load


In [77]:
jack = session.query(User).options(joinedload(User.addresses)).filter_by(name='jack').one()


2019-09-28 23:42:35,346 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname, 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 
FROM users LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id 
WHERE users.name = ? ORDER BY addresses_1.id
2019-09-28 23:42:35,347 INFO sqlalchemy.engine.base.Engine ('jack',)

In [78]:
jack


Out[78]:
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>

In [79]:
jack.addresses


Out[79]:
[<Address(email_address=jack@gmail.com)>,
 <Address(email_address=jack@yahoo.com)>]

Explicit Join + Eagerload


In [80]:
jack_addresses = session.query(Address).\
                join(Address.user).filter(User.name=='jack').\
                options(contains_eager(Address.user)).all()


2019-09-28 23:42:35,382 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname, 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 = ?
2019-09-28 23:42:35,404 INFO sqlalchemy.engine.base.Engine ('jack',)

In [81]:
jack_addresses


Out[81]:
[<Address(email_address=jack@gmail.com)>,
 <Address(email_address=jack@yahoo.com)>]

In [82]:
jack_addresses[0].user


Out[82]:
<User(name='jack', fullname='Jack Bean', nickname='jacknick')>

Deleting


In [83]:
session.delete(jack)
session.query(User).filter_by(name='jack').count()


2019-09-28 23:42:35,445 INFO sqlalchemy.engine.base.Engine UPDATE addresses SET user_id=? WHERE addresses.id = ?
2019-09-28 23:42:35,446 INFO sqlalchemy.engine.base.Engine ((None, 1), (None, 2))
2019-09-28 23:42:35,447 INFO sqlalchemy.engine.base.Engine DELETE FROM users WHERE users.id = ?
2019-09-28 23:42:35,449 INFO sqlalchemy.engine.base.Engine (5,)
2019-09-28 23:42:35,451 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1 
FROM (SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname 
FROM users 
WHERE users.name = ?) AS anon_1
2019-09-28 23:42:35,452 INFO sqlalchemy.engine.base.Engine ('jack',)
Out[83]:
0

In [84]:
session.query(Address).filter(Address.email_address.in_(['jack@gmail.com', 'jack@yahoo.com'])).count()


2019-09-28 23:42:35,466 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1 
FROM (SELECT addresses.id AS addresses_id, addresses.email_address AS addresses_email_address, addresses.user_id AS addresses_user_id 
FROM addresses 
WHERE addresses.email_address IN (?, ?)) AS anon_1
2019-09-28 23:42:35,467 INFO sqlalchemy.engine.base.Engine ('jack@gmail.com', 'jack@yahoo.com')
Out[84]:
2

In [85]:
session.close()


2019-09-28 23:42:35,479 INFO sqlalchemy.engine.base.Engine ROLLBACK

In [121]:
Base = declarative_base()

In [122]:
class User(Base):
    
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    nickname = Column(String)
    
    addresses = relationship('Address', back_populates='user', cascade='all, delete, delete-orphan')
    
    def __repr__(self):
        return "<User(name='{}', fullname='{}', nickname='{}')>".format(self.name, self.fullname, self.nickname)

In [123]:
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='{}')>".format(self.email_address)

Building a Many To Many Relationship


In [124]:
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)
    
    author = relationship(User, back_populates='posts')
    
    # 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):
        return "BlogPost({}, {}, {})".format(self.headline, self.body, self.author)

In [125]:
User.posts = relationship(BlogPost, back_populates="author", lazy="dynamic")

In [126]:
class Keyword(Base):
    
    __tablename__ = 'keywords'
    
    id = Column(Integer, primary_key=True)
    keyword = Column(String(50), nullable=False, unique=True)
    
    posts = relationship('BlogPost', secondary=post_keywords, back_populates='keywords')
    
    def __init__(self, keyword):
        self.keyword = keyword

In [127]:
# 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)
)

In [128]:
Base.metadata.create_all(engine)


2019-09-29 00:09:31,850 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2019-09-29 00:09:31,851 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,852 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2019-09-29 00:09:31,852 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,853 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("users")
2019-09-29 00:09:31,854 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,855 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("users")
2019-09-29 00:09:31,856 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,857 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("addresses")
2019-09-29 00:09:31,858 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,859 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("addresses")
2019-09-29 00:09:31,860 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,861 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("posts")
2019-09-29 00:09:31,862 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,863 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("posts")
2019-09-29 00:09:31,863 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,864 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("keywords")
2019-09-29 00:09:31,865 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,867 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("keywords")
2019-09-29 00:09:31,869 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,870 INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("post_keywords")
2019-09-29 00:09:31,871 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,872 INFO sqlalchemy.engine.base.Engine PRAGMA temp.table_info("post_keywords")
2019-09-29 00:09:31,872 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,873 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE users (
	id INTEGER NOT NULL, 
	name VARCHAR, 
	fullname VARCHAR, 
	nickname VARCHAR, 
	PRIMARY KEY (id)
)


2019-09-29 00:09:31,874 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,876 INFO sqlalchemy.engine.base.Engine COMMIT
2019-09-29 00:09:31,876 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE keywords (
	id INTEGER NOT NULL, 
	keyword VARCHAR(50) NOT NULL, 
	PRIMARY KEY (id), 
	UNIQUE (keyword)
)


2019-09-29 00:09:31,877 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,878 INFO sqlalchemy.engine.base.Engine COMMIT
2019-09-29 00:09:31,879 INFO sqlalchemy.engine.base.Engine 
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)
)


2019-09-29 00:09:31,879 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,881 INFO sqlalchemy.engine.base.Engine COMMIT
2019-09-29 00:09:31,882 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE posts (
	id INTEGER NOT NULL, 
	user_id INTEGER, 
	headline VARCHAR(255) NOT NULL, 
	body TEXT, 
	PRIMARY KEY (id), 
	FOREIGN KEY(user_id) REFERENCES users (id)
)


2019-09-29 00:09:31,883 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,885 INFO sqlalchemy.engine.base.Engine COMMIT
2019-09-29 00:09:31,886 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE post_keywords (
	post_id INTEGER NOT NULL, 
	keyword_id INTEGER NOT NULL, 
	PRIMARY KEY (post_id, keyword_id), 
	FOREIGN KEY(post_id) REFERENCES posts (id), 
	FOREIGN KEY(keyword_id) REFERENCES keywords (id)
)


2019-09-29 00:09:31,887 INFO sqlalchemy.engine.base.Engine ()
2019-09-29 00:09:31,888 INFO sqlalchemy.engine.base.Engine COMMIT

In [ ]: