Author: | Jason Kirtland |
---|---|
Date: | July 10th, 2007 |
- SQLite
- PostgreSQL
- MySQL
- SQL Server
- Oracle
- Firebird
- Informix
- ...and more on the way
SQLAlchemy can use any of these- or all of them, all at once.
SQLAlchemy maintains a schema catalog for SQL generation.
You can specify table schemas generically
slides = Table('slides', catalog,
Column('id', Integer, primary_key=True),
Column('title', String(50)))
bullets = Table('bullets', metadata,
Column('id', Integer, primary_key=True),
Column('slide_id', Integer, ForeignKey('slides.id'),
nullable=False),
Column('pos', Integer),
Column('text', String))
Or read tables from the database via reflection
slides = Table('slides', catalog, autoload=True)
bullets = Table('bullets', catalog, autoload=True)
Or just snarf everything
catalog = MetaData('sqlite://file.db', autoload=True)
Or target features of a particular database engine
slides = Table('slides', catalog,
Column('id', mysql.Integer(unsigned=True),
primary_key=True)
Column('title', mysql.SmallText(collate='utf8_bin'),
nullable=False))
The catalog of tables and columns is used for SQL generation and can also generate DDL. Tables can be easily created and dropped:
- slides.create()
- catalog.drop_all()
Generic DDL is adapted to the database engine on creation. Cross-platform is easy, and exploiting the capabilities of a single engine is easy too.
>>> slides.insert().execute(title='slide 1')
<sqlalchemy.engine.base.ResultProxy object at 0x1531f70>
>>> row = slides.select().execute().fetchone()
>>> row
(1, u'slide 1')
>>> row.title
u'slide 1'
slides.select(slides.c.id == 1)
SELECT slides.id, slides.title
FROM slides
WHERE slides.id = ?
slides.select(slides.c.title.in_('slide 1', 'slide 2'))
SELECT slides.id, slides.title
FROM slides
WHERE slides.title IN (?, ?)
slides.join(bullets).select()
SELECT slides.id, slides.title, bullets.id, bullets.slide_id,
bullets.pos, bullets.text
FROM slides JOIN bullets ON slides.id = bullets.slide_id
outerjoin(slides, bullets).select(slides.c.title.like('%SQL Types%'))
SELECT slides.id, slides.title, bullets.id, bullets.slide_id,
bullets.pos, bullets.text
FROM slides LEFT OUTER JOIN bullets ON slides.id = bullets.slide_id
WHERE slides.title LIKE ?
select([bullets.c.slide_id,
func.count(bullets.c.slide_id).label('total')],
group_by=[bullets.c.slide_id])
SELECT bullets.slide_id, count(bullets.slide_id) AS total
FROM bullets GROUP BY bullets.slide_id
cs = select([ bullets.c.slide_id,
func.count(bullets.c.slide_id).label('total') ],
group_by=[bullets.c.slide_id]).alias('totals')
slides.select(and_(slides.c.id==cs.c.slide_id, cs.c.total>1))
SELECT slides.id, slides.title
FROM slides, (SELECT bullets.slide_id AS slide_id,
count(bullets.slide_id) AS total
FROM bullets GROUP BY bullets.slide_id) AS totals
WHERE slides.id = totals.slide_id AND totals.total > ?
- Supports all SQL operators and functions.
- Joins, unions, correlated and uncorrelated subqueries, ...
- Queries can be built up or modifified programaticaly
- An ORM is supplied with the distribution
- Others are possible, and remixes of the default are available
- Default ORM uses the "data mapper" model
- "active record" available through Elixir ORM extension, others
class Slide(object):
def __repr__(self):
return 'Slide("%s")' % self.title
class Bullet(object):
def __repr__(self):
return 'Bullet("%s")' % self.text
mapper(Slide, slides, properties={
'bullets': relation(Bullet, cascade='all, delete-orphan')
})
mapper(Bullet, bullets)
>>> session = create_session()
>>> s1 = session.query(Slide).get(1)
>>> s1
Slide("slide 1")
>>> s1.bullets
[Bullet("foo"), Bullet("bar"), Bullet("baz")]
>>> s1.title = 'new title!'
>>> s1.bullets.pop()
Bullet("baz")
>>> session.flush()
info: BEGIN
info: UPDATE slides SET title=? WHERE slides.id = ?
info: ['new title!', 1]
info: DELETE FROM bullets WHERE bullets.id = ?
info: [3]
info: COMMIT
You can mix SQL and objects
>>> q = session.query(Bullet).filter(bullets.c.text.startswith('b'))
>>> q
<sqlalchemy.orm.query.Query object at 0x1537db0>
>>> list(q)
[Bullet("bar"), Bullet("baz")]
- Object mapping is very flexible
- Work with any legacy schema or schemas
- Multi-database
- Rich relations, collections, cascade rules
- Eager and lazy loading, whole object graphs or individual columns
- Stored procedures and triggers, no problem
- Optional! The SQLAlchemy ORM is decoupled from the base library.
- The RDBMS is a powerful tool, use it
- Object encapsulation is a powerful tool, use it
- SQLAlchemy lets you find the right mix for your problem and performance requirements, without hacks
Date: | July 10th, 2007 |
---|---|
Copyright: | Jason Kirtland |
License: | Creative Commons Attribution-Share Alike 3.0 |
Version: | 1 |