contents from sqlalchemy ORM tutorial


Version check


In [1]:
import sqlalchemy
sqlalchemy.__version__


Out[1]:
'0.9.8'

Connecting

  • create_engien() 함수 파라미터, database url 형식은 여기에서 확인

In [2]:
from sqlalchemy import create_engine
engine = create_engine('sqlite:///:memory:', echo=True)

Declare mapping

  • __tablename__, primary_key 는 필수

In [4]:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()
print Base


<class 'sqlalchemy.ext.declarative.api.Base'>

In [10]:
class UserA(Base):
    __tablename__ = 'users_a'
    
    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)
    
    def __repr__(self):
        return "<UserA(name='{0}', fullname='{1}', password='{3}')>".format(self.name, self.fullname, self.password)

Create a schema


In [9]:
UserA.__table__


Out[9]:
Table('users_a', MetaData(bind=None), Column('id', Integer(), table=<users_a>, primary_key=True, nullable=False), Column('name', String(), table=<users_a>), Column('fullname', String(), table=<users_a>), Column('password', String(), table=<users_a>), schema=None)
  • Table 객체는 많은 MetaData 객체로 이루어지는데, 신경 쓸 필요없다.

    Table(

      'users', MetaData(bind=None), 
      Column('id', Integer(), table=<users>, primary_key=True, nullable=False), 
      Column('name', String(), table=<users>), 
      Column('fullname', String(), table=<users>), 
      Column('password', String(), table=<users>), 
      schema=None)
  • Base.metadata.create_all( engine ) 을 호출해서 실제로 users 테이블을 생성한다.
  • VARCHAR 필드에 length 가 없는데, SQLite, Postgresql 에서는 유효하지만 다른 DB 에선 그렇지 않을 수 있으며 String(250) 형태로 써주면 VARCHAR 에 length 를 지정할 수 있음

In [5]:
class User(Base):
    __tablename__ = 'users'
    __table_args__ = {'extend_existing':True}    # 이미 users 테이블이 존재하는 경우 덮어씀
    
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    fullname = Column(String(255))
    password = Column(String(255))
    
    def __repr__(self):
        return "<User(id={3}, name='{0}', fullname='{1}', password='{2}')>".format(self.name, self.fullname, self.password, self.id)
    
# `users` table 을 실제로 생성한다.    
Base.metadata.create_all(engine)

# `users`, `user_a` 테이블을 보려면
User.__table__


2015-02-24 23:56:16,496 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
INFO:sqlalchemy.engine.base.Engine:SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2015-02-24 23:56:16,499 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
2015-02-24 23:56:16,503 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
INFO:sqlalchemy.engine.base.Engine:SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2015-02-24 23:56:16,509 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
2015-02-24 23:56:16,513 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users")
INFO:sqlalchemy.engine.base.Engine:PRAGMA table_info("users")
2015-02-24 23:56:16,516 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
2015-02-24 23:56:16,520 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE users (
	id INTEGER NOT NULL, 
	name VARCHAR(50), 
	fullname VARCHAR(255), 
	password VARCHAR(255), 
	PRIMARY KEY (id)
)


INFO:sqlalchemy.engine.base.Engine:
CREATE TABLE users (
	id INTEGER NOT NULL, 
	name VARCHAR(50), 
	fullname VARCHAR(255), 
	password VARCHAR(255), 
	PRIMARY KEY (id)
)


2015-02-24 23:56:16,526 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
2015-02-24 23:56:16,529 INFO sqlalchemy.engine.base.Engine COMMIT
INFO:sqlalchemy.engine.base.Engine:COMMIT
Out[5]:
Table('users', MetaData(bind=None), Column('id', Integer(), table=<users>, primary_key=True, nullable=False), Column('name', String(length=50), table=<users>), Column('fullname', String(length=255), table=<users>), Column('password', String(length=255), table=<users>), schema=None)

Create an instance of the Mapped Class


In [6]:
ed_user = User(name="ed", fullname="Ed jones", password="EdsPasswordz")
print ed_user
print ed_user.id    # sqlalchemy sets default value


<User(id=None, name='ed', fullname='Ed jones', password='EdsPasswordz')>
None

Creating a session

create_engine() 을 통해서 engine 인스턴스가 아직 만들어지지 않은 경우

Session = sessionmaker()
...
# engine instance 를 만든 후
...
...
# 나중에 engine 과 연결시켜 session 인스턴스를 생성할 수 도 있다.
session = Session.configure(bind=engine)
...

In [7]:
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()    # session 인스턴스 생성

Adding new objects

  • session.add() 를 호출하는 시점에 insert 가 이루어지지 않고, 필요한 시점을 sqlalchemy 가 캐치해서 insert 한다. (select 를 한다든가...)

In [8]:
ed_user = User(name='ed', fullname='ed jones', password='edspasswordz')
session.add(ed_user)
our_user = session.query(User).filter_by(name='ed').first()
print our_user, our_user.id


2015-02-24 23:56:36,782 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO:sqlalchemy.engine.base.Engine:BEGIN (implicit)
2015-02-24 23:56:36,782 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:56:36,782 INFO sqlalchemy.engine.base.Engine ('ed', 'ed jones', 'edspasswordz')
INFO:sqlalchemy.engine.base.Engine:('ed', 'ed jones', 'edspasswordz')
2015-02-24 23:56:36,801 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ?
 LIMIT ? OFFSET ?
2015-02-24 23:56:36,801 INFO sqlalchemy.engine.base.Engine ('ed', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='edspasswordz')> 1
  • 여러 User 객체를 insert

In [8]:
session.add_all([
    User(name='somma', fullname='yonghwan, noh', password='passwordzzzzzz'), 
    User(name='somma1', fullname='yonghwan, noh1', password='passwordzzzzzz1'), 
    User(name='somma2', fullname='yonghwan, noh2', password='passwordzzzzzz2'), 
    User(name='somma3', fullname='yonghwan, noh3', password='passwordzzzzzz3'), 
    User(name='somma4', fullname='yonghwan, noh4', password='passwordzzzzzz4'), 
    User(name='somma5', fullname='yonghwan, noh5', password='passwordzzzzzz5'), 
    User(name='somma6', fullname='yonghwan, noh6', password='passwordzzzzzz6'), 
])
  • ed_user 객체의 값을 변경하면 알아서 감지해서 처리해준다.

In [9]:
print ed_user
ed_user.password = 'changed passwordzz'
print ed_user

session.dirty    # identity map 을 통해 변경이 일어난 객체를 보여주고

session.new      # 추가된 객체들...

session.commit() # db 에 쓴다.

ed_user.id


<User(id=1, name='ed', fullname='ed jones', password='edspasswordz')>
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 23:43:03,690 INFO sqlalchemy.engine.base.Engine UPDATE users SET password=? WHERE users.id = ?
INFO:sqlalchemy.engine.base.Engine:UPDATE users SET password=? WHERE users.id = ?
2015-02-24 23:43:03,690 INFO sqlalchemy.engine.base.Engine ('changed passwordzz', 1)
INFO:sqlalchemy.engine.base.Engine:('changed passwordzz', 1)
2015-02-24 23:43:03,707 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,711 INFO sqlalchemy.engine.base.Engine ('somma', 'yonghwan, noh', 'passwordzzzzzz')
INFO:sqlalchemy.engine.base.Engine:('somma', 'yonghwan, noh', 'passwordzzzzzz')
2015-02-24 23:43:03,713 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,723 INFO sqlalchemy.engine.base.Engine ('somma1', 'yonghwan, noh1', 'passwordzzzzzz1')
INFO:sqlalchemy.engine.base.Engine:('somma1', 'yonghwan, noh1', 'passwordzzzzzz1')
2015-02-24 23:43:03,729 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,732 INFO sqlalchemy.engine.base.Engine ('somma2', 'yonghwan, noh2', 'passwordzzzzzz2')
INFO:sqlalchemy.engine.base.Engine:('somma2', 'yonghwan, noh2', 'passwordzzzzzz2')
2015-02-24 23:43:03,759 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,762 INFO sqlalchemy.engine.base.Engine ('somma3', 'yonghwan, noh3', 'passwordzzzzzz3')
INFO:sqlalchemy.engine.base.Engine:('somma3', 'yonghwan, noh3', 'passwordzzzzzz3')
2015-02-24 23:43:03,763 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,766 INFO sqlalchemy.engine.base.Engine ('somma4', 'yonghwan, noh4', 'passwordzzzzzz4')
INFO:sqlalchemy.engine.base.Engine:('somma4', 'yonghwan, noh4', 'passwordzzzzzz4')
2015-02-24 23:43:03,769 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,772 INFO sqlalchemy.engine.base.Engine ('somma5', 'yonghwan, noh5', 'passwordzzzzzz5')
INFO:sqlalchemy.engine.base.Engine:('somma5', 'yonghwan, noh5', 'passwordzzzzzz5')
2015-02-24 23:43:03,773 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 23:43:03,776 INFO sqlalchemy.engine.base.Engine ('somma6', 'yonghwan, noh6', 'passwordzzzzzz6')
INFO:sqlalchemy.engine.base.Engine:('somma6', 'yonghwan, noh6', 'passwordzzzzzz6')
2015-02-24 23:43:03,779 INFO sqlalchemy.engine.base.Engine COMMIT
INFO:sqlalchemy.engine.base.Engine:COMMIT
2015-02-24 23:43:03,782 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO:sqlalchemy.engine.base.Engine:BEGIN (implicit)
2015-02-24 23:43:03,786 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.id = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.id = ?
2015-02-24 23:43:03,792 INFO sqlalchemy.engine.base.Engine (1,)
INFO:sqlalchemy.engine.base.Engine:(1,)
Out[9]:
1

Rolling Back

session 은 transaction 안에서 동작하기 때문에 rollback 할 수 있다.


In [9]:
# modify ed_user's name
print ed_user.name
ed_user.name = 'not ed jones'

# add erroneous user, `fake_user`
fake_user = User(name="fakeuser", fullname="invalid", password="abcde")
session.add(fake_user)

# query
session.query(User).filter(User.name.in_(['not ed jones', 'fakeuser'])).all()


ed
2015-02-24 10:15:38,661 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
INFO:sqlalchemy.engine.base.Engine:UPDATE users SET name=? WHERE users.id = ?
2015-02-24 10:15:38,664 INFO sqlalchemy.engine.base.Engine ('not ed jones', 1)
INFO:sqlalchemy.engine.base.Engine:('not ed jones', 1)
2015-02-24 10:15:38,665 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
INFO:sqlalchemy.engine.base.Engine:INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
2015-02-24 10:15:38,667 INFO sqlalchemy.engine.base.Engine ('fakeuser', 'invalid', 'abcde')
INFO:sqlalchemy.engine.base.Engine:('fakeuser', 'invalid', 'abcde')
2015-02-24 10:15:38,671 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IN (?, ?)
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IN (?, ?)
2015-02-24 10:15:38,671 INFO sqlalchemy.engine.base.Engine ('not ed jones', 'fakeuser')
INFO:sqlalchemy.engine.base.Engine:('not ed jones', 'fakeuser')
Out[9]:
[<User(name='not ed jones', fullname='ed jones', password='changed passwordzz')>,
 <User(name='fakeuser', fullname='invalid', password='abcde')>]

In [10]:
# rollback
session.rollback()
print session.query(User).filter(User.name.in_(['not ed jones', 'fakeuser'])).all()
print ed_user.name


2015-02-24 10:15:43,224 INFO sqlalchemy.engine.base.Engine ROLLBACK
INFO:sqlalchemy.engine.base.Engine:ROLLBACK
2015-02-24 10:15:43,224 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO:sqlalchemy.engine.base.Engine:BEGIN (implicit)
2015-02-24 10:15:43,224 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IN (?, ?)
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IN (?, ?)
2015-02-24 10:15:43,234 INFO sqlalchemy.engine.base.Engine ('not ed jones', 'fakeuser')
INFO:sqlalchemy.engine.base.Engine:('not ed jones', 'fakeuser')
[]
2015-02-24 10:15:43,234 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.id = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.id = ?
2015-02-24 10:15:43,234 INFO sqlalchemy.engine.base.Engine (1,)
INFO:sqlalchemy.engine.base.Engine:(1,)
ed

Querying

basic query, order_by, label


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

for name, fullname in session.query(User.name, User.fullname):
    print name, fullname
    
for row in session.query(User, User.name).all():
    print row.User, row.name
    
for row in session.query(User.name.label('name_label')).all():
    print row.name_label


2015-02-24 23:43:26,782 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users ORDER BY users.id
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users ORDER BY users.id
2015-02-24 23:43:26,783 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
ed ed jones
somma yonghwan, noh
somma1 yonghwan, noh1
somma2 yonghwan, noh2
somma3 yonghwan, noh3
somma4 yonghwan, noh4
somma5 yonghwan, noh5
somma6 yonghwan, noh6
2015-02-24 23:43:26,792 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name, users.fullname AS users_fullname 
FROM users
INFO:sqlalchemy.engine.base.Engine:SELECT users.name AS users_name, users.fullname AS users_fullname 
FROM users
2015-02-24 23:43:26,809 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
ed ed jones
somma yonghwan, noh
somma1 yonghwan, noh1
somma2 yonghwan, noh2
somma3 yonghwan, noh3
somma4 yonghwan, noh4
somma5 yonghwan, noh5
somma6 yonghwan, noh6
2015-02-24 23:43:26,816 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users
2015-02-24 23:43:26,822 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')> ed
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')> somma
<User(id=3, name='somma1', fullname='yonghwan, noh1', password='passwordzzzzzz1')> somma1
<User(id=4, name='somma2', fullname='yonghwan, noh2', password='passwordzzzzzz2')> somma2
<User(id=5, name='somma3', fullname='yonghwan, noh3', password='passwordzzzzzz3')> somma3
<User(id=6, name='somma4', fullname='yonghwan, noh4', password='passwordzzzzzz4')> somma4
<User(id=7, name='somma5', fullname='yonghwan, noh5', password='passwordzzzzzz5')> somma5
<User(id=8, name='somma6', fullname='yonghwan, noh6', password='passwordzzzzzz6')> somma6
2015-02-24 23:43:26,832 INFO sqlalchemy.engine.base.Engine SELECT users.name AS name_label 
FROM users
INFO:sqlalchemy.engine.base.Engine:SELECT users.name AS name_label 
FROM users
2015-02-24 23:43:26,834 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
ed
somma
somma1
somma2
somma3
somma4
somma5
somma6

alias, limit, offset


In [11]:
# alias
from sqlalchemy.orm import aliased
user_alias = aliased(User, name='user_alias')

for row in session.query(user_alias, user_alias.name).all():
    print row.user_alias

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


2015-02-24 12:40:31,642 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.password AS user_alias_password 
FROM users AS user_alias
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.password AS user_alias_password 
FROM users AS user_alias
2015-02-24 12:40:31,645 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')>
<User(id=3, name='somma1', fullname='yonghwan, noh1', password='passwordzzzzzz1')>
<User(id=4, name='somma2', fullname='yonghwan, noh2', password='passwordzzzzzz2')>
<User(id=5, name='somma3', fullname='yonghwan, noh3', password='passwordzzzzzz3')>
<User(id=6, name='somma4', fullname='yonghwan, noh4', password='passwordzzzzzz4')>
<User(id=7, name='somma5', fullname='yonghwan, noh5', password='passwordzzzzzz5')>
<User(id=8, name='somma6', fullname='yonghwan, noh6', password='passwordzzzzzz6')>
2015-02-24 12:40:31,651 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users ORDER BY users.id
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users ORDER BY users.id
 LIMIT ? OFFSET ?
2015-02-24 12:40:31,653 INFO sqlalchemy.engine.base.Engine (2, 1)
INFO:sqlalchemy.engine.base.Engine:(2, 1)
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')>
<User(id=3, name='somma1', fullname='yonghwan, noh1', password='passwordzzzzzz1')>

filtering results

session.query() 의 결과는 KeyedTuple 객체, for name, in ... 이렇게 쓰면 name 에는 tuple[0] 이 할당되고, for name in ... 이렇게 쓰면 name 은 KeyedTuple 객체이므로 출력하려면 name[0], name[1] 이런식으로 사용하면 됨


In [11]:
for name in session.query(User.name).filter_by(fullname='ed jones'):
    print name[0], type(name)
    
for name, in session.query(User.name).filter_by(fullname='ed jones'):
    print name
    
for name, in session.query(User.name).filter(User.fullname=='ed jones'):
    print name
    
for name, in session.query(User.name).filter(User.name == 'ed').\
                                      filter(User.fullname == 'ed jones'):
    print name


2015-02-24 23:43:39,792 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
2015-02-24 23:43:39,792 INFO sqlalchemy.engine.base.Engine ('ed jones',)
INFO:sqlalchemy.engine.base.Engine:('ed jones',)
ed <class 'sqlalchemy.util._collections.KeyedTuple'>
2015-02-24 23:43:39,815 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
2015-02-24 23:43:39,818 INFO sqlalchemy.engine.base.Engine ('ed jones',)
INFO:sqlalchemy.engine.base.Engine:('ed jones',)
ed
2015-02-24 23:43:39,831 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.name AS users_name 
FROM users 
WHERE users.fullname = ?
2015-02-24 23:43:39,835 INFO sqlalchemy.engine.base.Engine ('ed jones',)
INFO:sqlalchemy.engine.base.Engine:('ed jones',)
ed
2015-02-24 23:43:39,842 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name 
FROM users 
WHERE users.name = ? AND users.fullname = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.name AS users_name 
FROM users 
WHERE users.name = ? AND users.fullname = ?
2015-02-24 23:43:39,845 INFO sqlalchemy.engine.base.Engine ('ed', 'ed jones')
INFO:sqlalchemy.engine.base.Engine:('ed', 'ed jones')
ed

common filter operators


In [12]:
# is null / is not null
print session.query(User).filter(User.name != None).first()
print session.query(User).filter(User.name.is_(None)).first()    
print session.query(User).filter(User.name.isnot(None)).first()

# not in
print session.query(User).filter(~User.name.in_(['ed', 'somma'])).first()

# in
print session.query(User).filter(User.name.in_(['ed', 'somma'])).first()
    
# like
print session.query(User).filter(User.name.like('%somma%')).first()

# not equals
print session.query(User).filter(User.name != 'ed').first()
    
# equals
print session.query(User).filter(User.name == 'ed').first()


2015-02-24 23:43:51,395 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IS NOT NULL
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IS NOT NULL
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,398 INFO sqlalchemy.engine.base.Engine (1, 0)
INFO:sqlalchemy.engine.base.Engine:(1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 23:43:51,403 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IS NULL
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IS NULL
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,407 INFO sqlalchemy.engine.base.Engine (1, 0)
INFO:sqlalchemy.engine.base.Engine:(1, 0)
None
2015-02-24 23:43:51,415 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IS NOT NULL
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IS NOT NULL
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,417 INFO sqlalchemy.engine.base.Engine (1, 0)
INFO:sqlalchemy.engine.base.Engine:(1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 23:43:51,427 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name NOT IN (?, ?)
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name NOT IN (?, ?)
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,430 INFO sqlalchemy.engine.base.Engine ('ed', 'somma', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 'somma', 1, 0)
<User(id=3, name='somma1', fullname='yonghwan, noh1', password='passwordzzzzzz1')>
2015-02-24 23:43:51,440 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IN (?, ?)
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name IN (?, ?)
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,450 INFO sqlalchemy.engine.base.Engine ('ed', 'somma', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 'somma', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 23:43:51,466 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ?
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,470 INFO sqlalchemy.engine.base.Engine ('%somma%', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('%somma%', 1, 0)
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')>
2015-02-24 23:43:51,483 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name != ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name != ?
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,490 INFO sqlalchemy.engine.base.Engine ('ed', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 1, 0)
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')>
2015-02-24 23:43:51,500 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ?
 LIMIT ? OFFSET ?
2015-02-24 23:43:51,506 INFO sqlalchemy.engine.base.Engine ('ed', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>

In [55]:
# and 
from sqlalchemy import and_
print session.query(User).filter(and_(User.name == 'ed', User.fullname == 'ed jones')).first()

# send multiple expression to .filter()
print session.query(User).filter(User.name == 'ed', User.fullname == 'ed jones').first()

# or chain multiple filter()/filter_by() calls
print session.query(User).filter(User.name == 'ed').filter(User.fullname == 'ed jones').first()


2015-02-24 16:34:57,168 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? AND users.fullname = ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? AND users.fullname = ?
 LIMIT ? OFFSET ?
2015-02-24 16:34:57,171 INFO sqlalchemy.engine.base.Engine ('ed', 'ed jones', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 'ed jones', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 16:34:57,174 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? AND users.fullname = ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? AND users.fullname = ?
 LIMIT ? OFFSET ?
2015-02-24 16:34:57,176 INFO sqlalchemy.engine.base.Engine ('ed', 'ed jones', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 'ed jones', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 16:34:57,178 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? AND users.fullname = ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? AND users.fullname = ?
 LIMIT ? OFFSET ?
2015-02-24 16:34:57,180 INFO sqlalchemy.engine.base.Engine ('ed', 'ed jones', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 'ed jones', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>

In [58]:
# or
from sqlalchemy import or_
print session.query(User).filter(or_(User.name == 'ed', User.fullname == 'ed jones' )).first()


2015-02-24 16:36:11,789 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? OR users.fullname = ?
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? OR users.fullname = ?
 LIMIT ? OFFSET ?
2015-02-24 16:36:11,789 INFO sqlalchemy.engine.base.Engine ('ed', 'ed jones', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('ed', 'ed jones', 1, 0)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>

Returning Lists and Scalars


In [73]:
# all()
query = session.query(User).filter(User.name.like('somm%')).order_by(User.id)
for row in query.all():
    print row
    
# first()    
print query.first()


2015-02-24 20:16:35,249 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
2015-02-24 20:16:35,269 INFO sqlalchemy.engine.base.Engine ('somm%',)
INFO:sqlalchemy.engine.base.Engine:('somm%',)
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')>
<User(id=3, name='somma1', fullname='yonghwan, noh1', password='passwordzzzzzz1')>
<User(id=4, name='somma2', fullname='yonghwan, noh2', password='passwordzzzzzz2')>
<User(id=5, name='somma3', fullname='yonghwan, noh3', password='passwordzzzzzz3')>
<User(id=6, name='somma4', fullname='yonghwan, noh4', password='passwordzzzzzz4')>
<User(id=7, name='somma5', fullname='yonghwan, noh5', password='passwordzzzzzz5')>
<User(id=8, name='somma6', fullname='yonghwan, noh6', password='passwordzzzzzz6')>
2015-02-24 20:16:35,279 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
 LIMIT ? OFFSET ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
 LIMIT ? OFFSET ?
2015-02-24 20:16:35,282 INFO sqlalchemy.engine.base.Engine ('somm%', 1, 0)
INFO:sqlalchemy.engine.base.Engine:('somm%', 1, 0)
<User(id=2, name='somma', fullname='yonghwan, noh', password='passwordzzzzzz')>

In [89]:
# one() 
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound

# if no result
try:
    query = session.query(User).filter(User.name == 'no_name').order_by(User.id)
    users = query.one()
except NoResultFound as e:
    print 'exception = {0}'.format(e.message)
    
# if multiple results    
try:
    query = session.query(User).filter(User.name.like('somma%')).order_by(User.id)
    users = query.one()
    print users
except MultipleResultsFound as e:
    print 'exception = {0}'.format(e.message)
    

# scalar()
# return first element of first result or None if no result present. 
# if multiple result returned, `MultipleResultsFound` exception raised.

try:
    query = session.query(User).filter(User.name.like('somma%')).order_by(User.id)
    users = query.scalar()
except MultipleResultsFound as e:
    print 'exception = {0}'.format(e.message)


2015-02-24 20:51:26,339 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? ORDER BY users.id
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name = ? ORDER BY users.id
2015-02-24 20:51:26,342 INFO sqlalchemy.engine.base.Engine ('no_name',)
INFO:sqlalchemy.engine.base.Engine:('no_name',)
exception = No row was found for one()
2015-02-24 20:51:26,348 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
2015-02-24 20:51:26,349 INFO sqlalchemy.engine.base.Engine ('somma%',)
INFO:sqlalchemy.engine.base.Engine:('somma%',)
exception = Multiple rows were found for one()
2015-02-24 20:51:26,355 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE users.name LIKE ? ORDER BY users.id
2015-02-24 20:51:26,358 INFO sqlalchemy.engine.base.Engine ('somma%',)
INFO:sqlalchemy.engine.base.Engine:('somma%',)
exception = Multiple rows were found for one()

Using Literal SQL


In [13]:
from sqlalchemy import text
for user in session.query(User).filter(text('id < 3')).order_by(text('id')).all():
    print user.name

for user in session.query(User).filter(text('id < :id and name = :name')).params(id = 3, name = 'somma').all():
    print user.name
    
for users in session.query(User).from_statement(text('select * from users where name=:name')).params(name='ed').all():
    print users
    
for id, name, third_ret in session.query('id', 'name', 'the_number_12')\
                    .from_statement(text('select id, name, 12 as the_number_12 from users where name like :name'))\
                    .params(name='somma%').all():
    print '{0}, {1}, {2}'.format(id, name, third_ret)


2015-02-24 23:44:12,296 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE id < 3 ORDER BY id
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE id < 3 ORDER BY id
2015-02-24 23:44:12,299 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
ed
somma
2015-02-24 23:44:12,316 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE id < ? and name = ?
INFO:sqlalchemy.engine.base.Engine:SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password 
FROM users 
WHERE id < ? and name = ?
2015-02-24 23:44:12,322 INFO sqlalchemy.engine.base.Engine (3, 'somma')
INFO:sqlalchemy.engine.base.Engine:(3, 'somma')
somma
2015-02-24 23:44:12,329 INFO sqlalchemy.engine.base.Engine select * from users where name=?
INFO:sqlalchemy.engine.base.Engine:select * from users where name=?
2015-02-24 23:44:12,335 INFO sqlalchemy.engine.base.Engine ('ed',)
INFO:sqlalchemy.engine.base.Engine:('ed',)
<User(id=1, name='ed', fullname='ed jones', password='changed passwordzz')>
2015-02-24 23:44:12,342 INFO sqlalchemy.engine.base.Engine select id, name, 12 as the_number_12 from users where name like ?
INFO:sqlalchemy.engine.base.Engine:select id, name, 12 as the_number_12 from users where name like ?
2015-02-24 23:44:12,349 INFO sqlalchemy.engine.base.Engine ('somma%',)
INFO:sqlalchemy.engine.base.Engine:('somma%',)
2, somma, 12
3, somma1, 12
4, somma2, 12
5, somma3, 12
6, somma4, 12
7, somma5, 12
8, somma6, 12

Counting


In [104]:
print session.query(User).count()
print session.query(User).filter(User.name.like('somma%')).count()


2015-02-24 21:37:24,838 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.password AS users_password 
FROM users) AS anon_1
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.password AS users_password 
FROM users) AS anon_1
2015-02-24 21:37:24,854 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
8
2015-02-24 21:37:24,861 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.password AS users_password 
FROM users 
WHERE users.name LIKE ?) AS anon_1
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.password AS users_password 
FROM users 
WHERE users.name LIKE ?) AS anon_1
2015-02-24 21:37:24,874 INFO sqlalchemy.engine.base.Engine ('somma%',)
INFO:sqlalchemy.engine.base.Engine:('somma%',)
7

count() more nicer way!


In [108]:
from sqlalchemy import func
session.query(func.count(User.name), User.name).group_by(User.name).all()

# select count(*) from users
session.query(func.count('*')).select_from(User).scalar()

# `select_from()` can be removed if express the count of User's primary key.
session.query(func.count(User.id)).scalar()


2015-02-24 21:47:12,503 INFO sqlalchemy.engine.base.Engine SELECT count(users.name) AS count_1, users.name AS users_name 
FROM users GROUP BY users.name
INFO:sqlalchemy.engine.base.Engine:SELECT count(users.name) AS count_1, users.name AS users_name 
FROM users GROUP BY users.name
2015-02-24 21:47:12,503 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
2015-02-24 21:47:12,523 INFO sqlalchemy.engine.base.Engine SELECT count(?) AS count_1 
FROM users
INFO:sqlalchemy.engine.base.Engine:SELECT count(?) AS count_1 
FROM users
2015-02-24 21:47:12,526 INFO sqlalchemy.engine.base.Engine ('*',)
INFO:sqlalchemy.engine.base.Engine:('*',)
2015-02-24 21:47:12,536 INFO sqlalchemy.engine.base.Engine SELECT count(users.id) AS count_1 
FROM users
INFO:sqlalchemy.engine.base.Engine:SELECT count(users.id) AS count_1 
FROM users
2015-02-24 21:47:12,542 INFO sqlalchemy.engine.base.Engine ()
INFO:sqlalchemy.engine.base.Engine:()
Out[108]:
8

Building a Relationship


In [46]:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref

class Address(Base):
    __tablename__ = 'addresses'
    #__table_args__ = {'extend_existing':True}    # 이미 users 테이블이 존재하는 경우 덮어씀
    
    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', order_by = id))
    
    def __repr__(self):
        return '<Address (email_address = {0})>'.format(self.email_address)
    
# create table 
Base.metadata.create_all(engine)


---------------------------------------------------------------------------
InvalidRequestError                       Traceback (most recent call last)
<ipython-input-46-5ea2d03b79f7> in <module>()
      2 from sqlalchemy.orm import relationship, backref
      3 
----> 4 class Address(Base):
      5     __tablename__ = 'addresses'
      6     #__table_args__ = {'extend_existing':True}    # 이미 users 테이블이 존재하는 경우 덮어씀

C:\Python27\lib\site-packages\sqlalchemy\ext\declarative\api.pyc in __init__(cls, classname, bases, dict_)
     53     def __init__(cls, classname, bases, dict_):
     54         if '_decl_class_registry' not in cls.__dict__:
---> 55             _as_declarative(cls, classname, cls.__dict__)
     56         type.__init__(cls, classname, bases, dict_)
     57 

C:\Python27\lib\site-packages\sqlalchemy\ext\declarative\base.pyc in _as_declarative(cls, classname, dict_)
    252                 tablename, cls.metadata,
    253                 *(tuple(declared_columns) + tuple(args)),
--> 254                 **table_kw)
    255     else:
    256         table = cls.__table__

C:\Python27\lib\site-packages\sqlalchemy\sql\schema.pyc in __new__(cls, *args, **kw)
    391                     "to redefine "
    392                     "options and columns on an "
--> 393                     "existing Table object." % key)
    394             table = metadata.tables[key]
    395             if extend_existing:

InvalidRequestError: Table 'addresses' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

Working with Related Objects