Post on 27-Jan-2015
description
SQLAlchemy andAlembic
ORM, Core and Migrations / Jason Myers @jasonamyers
Architecture
pip install sqlalchemy
pip install flask-sqlalchemy
bin/paster create -t pyramid_alchemy tutorial
from sqlalchemy import create_engineengine = create_engine( ‘dialect+driver://USER:PASS@HOST:PORT/DB’)
Porcelain
from sqlalchemy.ext.declarative import ( declarative_base)
Base = declarative_base()
from sqlalchemy import ( Column, Integer, String, Float)from sqlalchemy import ForeignKeyfrom sqlalchemy.orm import ( relationship, backref)
class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) fullname = Column(String) balance = Column(Float) group = Column(String) addresses = relationship( "Address", order_by="Address.id", backref="user" )
def __init__(self, name, fullname, balance, group): self.name = name self.fullname = fullname self.balance = balance self.group = group
Base.metadata.create_all(engine)
from sqlalchemy.orm import sessionmakerSession = sessionmaker(bind=engine)db = Session()
user1 = User('Bob', 'Big Bob', 1000000.00, 'Mob')user2 = User('Linda', 'Linda Lu', 100.50, 'Diner')user3 = User('Lil Bob', 'Bobby Jr', 100500.00, 'Mob')user4 = User('Rachael', 'Rachael Rach', 125.50, 'Personal')
db.add(user1)
db.commit()
db.delete(user1)
db.expunge(user1)
db.refresh(user1)db.expire(user1)
db.rollback()
for user in db.query(User).all(): print user.name, user.balance
Out[1]: Bob 1000000.0
entries = db.session.query(Entries).filter_by(user_id=user.id)\ .filter(Entries.entry_time > (datetime.datetime.utcnow() - datetime.timedelta(30))).order_by('ID DESC').all()
SELECT entries.id AS entries_id, entries.user_id AS entries_user_id, entries.phone AS entries_phone, entries.measurement AS entries_measurement, entries.insulin AS entries_insulin, entries.insulin_type AS entries_insulin_type, entries.carbs AS entries_carbs, entries.tag AS entries_tag, entries.three_sixty_id AS entries_three_sixty_id, entries.entry_time AS entries_entry_time, entries.created_time AS entries_created_timeFROM entriesWHERE entries.user_id = :user_id_1 AND entries.entry_time > :entry_time_1ORDER BY ID DESC
from sqlalchemy import funcfrom sqlalchemy.sql import labelresults = db.query( User.group, label('members', func.count(User.id)), label( 'total_balance', func.sum(User.balance) )).group_by(User.group).all()for result in results: print result.group, result.members, result.total_balance
bob.addresses.append(home_address)
bob.addresses
bob.addresses.filter(Address.type='H').one()
query = db.query(User, Address).filter(User.id==Address.user_id)query = query.filter(Address.email_address=='jack@goog.com').all()
@hybrid_propertydef grand_total(self): rollup_fields = [ 'merchandise_cost', 'tax', 'shipping', ] total = sum([self.__getattribute__(x) for x in rollup_fields]) return round(total, 2)
Plumbing
from sqlalchemy import create_engineengine = create_engine( ‘dialect+driver://USER:PASS@HOST:PORT/DB’)
from sqlalchemy import (Table, Column, Integer, String, MetaData, ForeignKey)metadata = MetaData()users = Table('users', metadata, Column('id', Integer, primary_key=True), Column('name', String), Column('fullname', String),)
Base.metadata.create_all(engine)conn = engine.connect()
ins = users.insert().values(name='jack', fullname='Jack Bell')result = conn.execute(ins)
ins = users.insert()conn.execute(ins, id=2, name='wendy', fullname='Wendy McDonalds')
conn.execute(addresses.insert(), [ {'user_id': 1, 'email_address' : 'j@y.com'}, {'user_id': 1, 'email_address' : 'j@m.com'},])
def build_table(table_name):return Table( table_name, metadata, autoload=True, autoload_with=engine)
build_table('census')unavailable_fields = [ c.name for c in t.c if isinstance(c.type, NullType)]
InformixMS SQLOraclePostgresSQLiteCustom
class UnloadFromSelect(Executable, ClauseElement):
def __init__(self, select, bucket, access_key, secret_key): self.select = select self.bucket = bucket self.access_key = access_key self.secret_key = secret_key
@compiles(UnloadFromSelect)def visit_unload_from_select(element, compiler, **kw): return "unload ('%(query)s') to '%(bucket)s' credentials 'aws_access_key_id=%(access_key)s; aws_secret_access_key=%(secret_key)s' delimiter ',' addquotes allowoverwrite" % { 'query': compiler.process(element.select, unload_select=True, literal_binds=True), 'bucket': element.bucket, 'access_key': element.access_key, 'secret_key': element.secret_key, }
unload = UnloadFromSelect( select([fields]), '/'.join(['s3:/', BUCKET, filename]), ACCESS_KEY, SECRET_KEY)
unload ( 'select * from venue where venueid in ( select venueid from venue order by venueid desc limit 10)')to 's3://mybucket/venue_pipe_'credentials 'aws_access_key_id=ACCESS_KEY; aws_secret_access_key=SECRET_KEY';
s = select( [ t.c.race, t.c.factor, func.sum(g.t.c.value).label('summed') ], t.c.race > 0).where( and_( t.c.type == 'POVERTY', t.c.value != 0 )).group_by( t.c.race, t.c.factor).order_by( t.c.race, t.c.factor)
s = select( [ table.c.discharge_year, func.count(1).label( 'patient_discharges'), table.c.zip_code, ], table.c.discharge_year.in_(years)).group_by(table.c.discharge_year)s = s.where(table.c.hospital_name == provider)
if 'total_charges' not in unavailable_fields: s = s.column( func.sum(table.c.total_charges ).label('patient_charges') )
s = s.group_by(table.c.zip_code)s = s.order_by('discharges DESC')
cases = conn.execute(s).fetchall()
pip install alembic
alembic init alembic
# A generic, single database configuration.[alembic]# path to migration scriptsscript_location = alembic# template used to generate migration files# file_template = %%(rev)s_%%(slug)s# set to 'true' to run the environment during# the 'revision' command, regardless ofautogenerate# revision_environment = falsesqlalchemy.url = driver://user:pass@localhost/dbname
from glu import dbtarget_metadata = db.metadatadef run_migrations_online(): alembic_config = config.get_section(config.config_ini_section) from config import SQLALCHEMY_DATABASE_URI alembic_config['sqlalchemy.url'] = SQLALCHEMY_DATABASE_URI engine = engine_from_config( alembic_config, prefix='sqlalchemy.', poolclass=pool.NullPool)
alembic revision -m "initial"
def upgrade(): op.create_table('users_to_users', sa.Column('patient_user_id', sa.Integer(), nullable=False), sa.Column('provider_user_id', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['patient_user_id'], ['users.id'],), sa.ForeignKeyConstraint(['provider_user_id'], ['users.id'],), sa.PrimaryKeyConstraint('patient_user_id','provider_user_id') )
op.alter_column(u'reminders', u'user_created', nullable=True)
def downgrade(): op.alter_column(u'reminders', u'user_created', existing_type=mysql.TINYINT(display_width=1), nullable=False ) op.drop_table('users_to_users')
alembic upgrade head
alembic revision --autogenerate -m "Added account table"
Table (adds/removes)Columns (adds/removes)Nullable changes
Optionally: Column Type changescompare_type=TrueNo Name changes on Columns or Table
alembic currentalembic upgrade +2alembic downgrade -1alembic upgrade ae1alembic upgrade 1 --sql > file.sqlalembic history
2806761df139 -> 1e9831c8fa7d (head), Adding tags to ...2806761df139 -> 46a1d4de6e04 (head), Added timezone ...4f7119855daf -> 2806761df139 (branchpoint), Added Pr...377addf23edb -> 4f7119855daf, Added user_created to ...483d9a63fbf5 -> 377addf23edb, Adding claimed to user...464ba41d7ad8 -> 483d9a63fbf5, Adding username/passwo...2cfd9dc89267 -> 464ba41d7ad8, Adding Intercom.iod4774a3ce8 -> 2cfd9dc89267, Seperating Roles and Use...None -> d4774a3ce8, Base
THE END@jasonamyers