Cover | Table of Contents | Colophon
sql="INSERT INTO user(user_name, password) VALUES (%s, %s)"
cursor = conn.cursor()
cursor.execute(sql, ('rick', 'parrot'))
sql="INSERT INTO user(user_name, password) VALUES (:1, :2)" cursor = conn.cursor() cursor.execute(sql, 'rick', 'parrot')
sql="INSERT INTO user(user_name, password) VALUES (%s, %s)"
cursor = conn.cursor()
cursor.execute(sql, ('rick', 'parrot'))
sql="INSERT INTO user(user_name, password) VALUES (:1, :2)" cursor = conn.cursor() cursor.execute(sql, 'rick', 'parrot')
CREATE TABLE tf_user (
id INTEGER NOT NULL,
user_name VARCHAR(16) NOT NULL,
email_address VARCHAR(255) NOT NULL,
password VARCHAR(40) NOT NULL,
first_name VARCHAR(255),
last_name VARCHAR(255),
created TIMESTAMP,
PRIMARY KEY (id),
UNIQUE (user_name),
UNIQUE (email_address));
CREATE TABLE tf_group (
id INTEGER NOT NULL,
group_name VARCHAR(16) NOT NULL,
PRIMARY KEY (id),
UNIQUE (group_name));
CREATE TABLE tf_permission (
id INTEGER NOT NULL,
permission_name VARCHAR(16) NOT NULL,
PRIMARY KEY (id),
UNIQUE (permission_name));
-- Relate the user and group tables
CREATE TABLE user_group (
user_id INTEGER,
group_id INTEGER,
PRIMARY KEY(user_id, group_id),
FOREIGN KEY(user_id) REFERENCES tf_user (id),
FOREIGN KEY(group_id) REFERENCES tf_group (id));
-- Relate the group and permission tables
CREATE TABLE group_permission (
group_id INTEGER,
permission_id INTEGER,
PRIMARY KEY(group_id, permission_id),
FOREIGN KEY(group_id) REFERENCES tf_group (id),
FOREIGN KEY(permission_id) REFERENCES tf_permission (id));FromSQL databases behave less and less like object collections the more size and performance start to matter; object collections behave less and less like tables and rows the more abstraction starts to matter. SQLAlchemy aims to accommodate both of these principles.
class User(object):
def __init__(self, user_name=None, password=None, groups=None):
if groups is None: groups = []
self.user_name = user_name
self.password = password
self._groups = groups
def join_group(self, group):
self._groups.append(group)
def leave_group(self, group):
self._groups.remove(group)
class Group(object):
def __init__(self, group_name=None, users=None, permissions=None):
if users is None: users = []
if permissions is None: permissions = []
self.group_name = group_name
self._users = users
self._permissions = permissions
def add_user(self, user):
self._users.append(user)
def del_user(self, user):
self._users.remove(user)
def add_permission(self, permission):
self._permissions.append(permission)
def del_permission(self, permission):
self._permissions.remove(permission)
class Permission(object):
def __init__(self, permission_name=None, groups=None):
self.permission_name = permission_name
self._groups = groups
def join_group(self, group):
self._groups.append(group)
def leave_group(self, group):
self._groups.remove(group)Engine class, which manages connection
pools and SQL dialects, a MetaData class, which
manages your table information, and a flexible type system for mapping SQL
types to Python types.metadata=MetaData('sqlite://')
engine = metadata.bind
engine=create_engine('sqlite://')
bind attribute on the
MetaData:metadata.bind = engine
user_table.create(bind=engine)
for row in engine.execute("select user_name from tf_user"):
print 'user name: %s' % row['user_name']
from sqlalchemy import * from datetime import datetime
metadata = MetaData('sqlite:///tutorial.sqlite')
user_table = Table(
'tf_user', metadata,
Column('id', Integer, primary_key=True),
Column('user_name', Unicode(16),
unique=True, nullable=False),
Column('password', Unicode(40), nullable=False),
Column('display_name', Unicode(255), default=''),
Column('created', DateTime, default=datetime.now))
'tf_user'), a reference to the metadata
object, and a list of columns. The columns are similarly defined with
their SQL names, data types, and various optional constraints. In this
case, since we defined an 'id' column as a primary
key, SQLAlchemy will automatically create the column with an
auto-increment default value. Also note that we can specify uniqueness
and nullability constraints on columns, provide literal defaults, or
provide Python callables (e.g., # Create a connection to a SQLite in-memory database
engine = create_engine('sqlite://')
# Create a connection to a SQLite on-disk database "data.sqlite"
engine = create_engine('sqlite:///data.sqlite')
# Create a connection to a PostGreSQL database
engine = create_engine('postgres://rick:foo@localhost:5432/pg_db')
# Create a connection to a MySQL database
engine = create_engine('mysql://localhost/mysql_db')
# Create a connection to an Oracle database (via TNS)
engine = create_engine('oracle://rick:foo@oracle_tns')
# Create a connection to an Oracle database (without a TNS name)
engine =
... create_engine('oracle://rick:foo@localhost:1521/oracle_sid')
url='postgres://rick:foo@localhost/pg_db?arg1=foo&arg2=bar' engine = create_engine(url)
# Create a connection to a SQLite in-memory database
engine = create_engine('sqlite://')
# Create a connection to a SQLite on-disk database "data.sqlite"
engine = create_engine('sqlite:///data.sqlite')
# Create a connection to a PostGreSQL database
engine = create_engine('postgres://rick:foo@localhost:5432/pg_db')
# Create a connection to a MySQL database
engine = create_engine('mysql://localhost/mysql_db')
# Create a connection to an Oracle database (via TNS)
engine = create_engine('oracle://rick:foo@oracle_tns')
# Create a connection to an Oracle database (without a TNS name)
engine =
... create_engine('oracle://rick:foo@localhost:1521/oracle_sid')
url='postgres://rick:foo@localhost/pg_db?arg1=foo&arg2=bar' engine = create_engine(url)
engine = create_engine('postgres://rick:foo@localhost/pg_db',
connect_args=dict(arg1='foo', arg2='bar'))
import psycopg
def connect_pg():
return psycopg.connect(user='rick', host='localhost')
engine = create_engine('postgres://', creator=connect_pg)# create an unbound MetaData
unbound_meta = MetaData()
# create an Engine and bind the MetaData to it
db1 = create_engine('sqlite://')
unbound_meta.bind = db
# Create an engine and then a bound MetaData
db2 = MetaData('sqlite:///test1.db')
bound_meta1 = MetaData(db2)
# Create a bound MetaData with an implicitly created engine
bound_meta2 = MetaData('sqlite:///test2.db')
bind. This is referred to as explicit
execution. If a MetaData instance is bound,
then the String(40) is an instance of a
TypeEngine that represents a VARCHAR(40).
TypeEngines also supply SQL text for use when
creating tables using or
table.create().String(40) is an instance of a
TypeEngine that represents a VARCHAR(40).
TypeEngines also supply SQL text for use when
creating tables using or
table.create().CLOB). These are derived from other
TypeEngines and may or may not be further
specialized to allow finer-grained specification of the underlying
database type.| Class name | Python type | Arguments | |
|---|---|---|---|
String
|
string
| TEXT or VARCHAR | length (default is unbounded) |
Integer
|
int
| INTEGER |
none
|
SmallInteger
|
int
| SMALLINT |
none
|
Numeric
| float,
Decimal | NUMERIC |
TypeDecorator:from sqlalchemy import types
class MyCustomEnum(types.TypeDecorator):
impl=types.Integer
def __init__(self, enum_values, *l, **kw):
types.TypeDecorator.__init__(self, *l, **kw)
self._enum_values = enum_values
def convert_bind_param(self, value, engine):
result = self.impl.convert_bind_param(value, engine)
if result not in self._enum_values:
raise TypeError, (
"Value %s must be one of %s" % (result, self._enum_values))
return result
def convert_result_value(self, value, engine):
'Do nothing here'
return self.impl.convert_result_value(value, engine)>>> metadata=MetaData()
>>>
>>> simple_table = Table(
... 'simple', metadata,
... Column('id', Integer, primary_key=True),
... Column('col1', Unicode(20)))
>>>
>>> stmt = simple_table.insert()
>>> print stmt
INSERT INTO simple (id, col1) VALUES (:id, :col1)
>>> compiled_stmt = stmt.compile()
>>> print compiled_stmt.params
ClauseParameters:{'id': None, 'col1': None}
>>> engine = create_engine('sqlite://')
>>> simple_table.create(bind=engine)
>>> engine.execute(stmt, col1="Foo")
<sqlalchemy.engine.base.ResultProxy object at 0x2b3210b00f10>
>>> metadata.bind = engine
>>> stmt.execute(col1="Bar")
<sqlalchemy.engine.base.ResultProxy object at 0x2b3210b020d0>>>> metadata=MetaData()
>>>
>>> simple_table = Table(
... 'simple', metadata,
... Column('id', Integer, primary_key=True),
... Column('col1', Unicode(20)))
>>>
>>> stmt = simple_table.insert()
>>> print stmt
INSERT INTO simple (id, col1) VALUES (:id, :col1)
>>> compiled_stmt = stmt.compile()
>>> print compiled_stmt.params
ClauseParameters:{'id': None, 'col1': None}
>>> engine = create_engine('sqlite://')
>>> simple_table.create(bind=engine)
>>> engine.execute(stmt, col1="Foo")
<sqlalchemy.engine.base.ResultProxy object at 0x2b3210b00f10>
>>> metadata.bind = engine
>>> stmt.execute(col1="Bar")
<sqlalchemy.engine.base.ResultProxy object at 0x2b3210b020d0>
>>> stmt = simple_table.insert(values=dict(col1="Initial value"))
>>> print stmt
INSERT INTO simple (col1) VALUES (?)
>>> compiled_stmt = stmt.compile()
>>> print compiled_stmt.params
ClauseParameters:{'col1': 'Initial value'}>>> stmt = select([product_table.c.sku]) >>> for row in stmt.execute(): ... print row ... (u'123',) (u'456',) (u'789',)
>>> stmt = product_table.select()
>>> for row in stmt.execute():
... print row
...
(u'123', Decimal("12.34"))
(u'456', Decimal("22.12"))
(u'789', Decimal("41.44"))
level_table = Table(
'level', metadata,
Column('id', Integer, primary_key=True),
Column('parent_id', None, ForeignKey('level.id')),
Column('name', String(20)))
category_table = Table(
'category', metadata,
Column('id', Integer, primary_key=True),
Column('level_id', None, ForeignKey('level.id')),
Column('parent_id', None, ForeignKey('category.id')),
Column('name', String(20)))
product_table = Table(
'product', metadata,
Column('sku', String(20), primary_key=True),
Column('msrp', Numeric))
product_summary_table = Table(
'product_summary', metadata,
Column('sku', None, ForeignKey('product.sku'), primary_key=True),
Column('name', Unicode(255)),
Column('description', Unicode))
product_category_table = Table(
'product_category', metadata,
Column('product_id', None, ForeignKey('product.sku'), primary_key=True),
Column('category_id', None, ForeignKey('category.id'), primary_key=True))
region_table = Table(
'region', metadata,
Column('id', Integer, primary_key=True),
Column('name', Unicode(255)))
store_table = Table(
'store', metadata,
Column('id', Integer, primary_key=True),
Column('region_id', None, ForeignKey('region.id')),
Column('name', Unicode(255)))
product_price_table = Table(
'product_price', metadata,
Column('sku', None, ForeignKey('product.sku'), primary_key=True),
Column('store_id', None, ForeignKey('store.id'), primary_key=True),
Column('price', Numeric, default=0))
Region
class as follows:>>> mapper(Store, store_table) <sqlalchemy.orm.mapper.Mapper object at 0x2b794eb2f610> >>> mapper(Region, region_table, properties=dict( ... stores=relation(Store))) <sqlalchemy.orm.mapper.Mapper object at 0x2b794eb3af90> >>> rgn = session.query(Region).get(1) 2007-10-13 12:59:47,876 INFO sqlalchemy.engine.base.Engine.0x..90 ... SELECT region.id AS region_id, region.name AS region_name FROM region WHERE region.id = ? ORDER BY region.oid LIMIT 1 OFFSET 0 2007-10-13 12:59:47,877 INFO sqlalchemy.engine.base.Engine.0x..90 ... [1] >>> s0 = Store(name='3rd and Juniper') >>> rgn.stores.append(s0) 2007-10-13 13:00:06,339 INFO sqlalchemy.engine.base.Engine.0x..90 ... SELECT store.id AS store_id, store.region_id AS store_region_id, ... store.name AS store_name FROM store WHERE ? = store.region_id ORDER BY store.oid 2007-10-13 13:00:06,339 INFO sqlalchemy.engine.base.Engine.0x..90 ... [1] >>> session.flush() 2007-10-13 13:00:14,344 INFO sqlalchemy.engine.base.Engine.0x..90 ... INSERT INTO store (region_id, name) VALUES (?, ?) 2007-10-13 13:00:14,345 INFO sqlalchemy.engine.base.Engine.0x..90 ... [1, '3rd and Juniper']