SQL Alchemy Advanced Python NBN 2007
SQL Alchemy Advanced Python NBN 2007
Phrase queries in a more pythonic (less SQL-ish) way Hide database dierences The database disappears ...
Making an engine
Connecting is slightly more complicated than SQLObject: Use a connection string of the form driver://username:password@host:port/database Make a database engine with create_engine encoding and convert_unicode can be used to convert characters for all transactions echo can be set to print raw SQL Use to make special metadata object from sqlalchemy import * conn_str = "mysql://dbuser:dbpass@localhost:8028/epi" engine = create_engine (conn_str, echo=True) metadata = MetaData (engine)
Making a connection
Call connect from engine Connection can execute raw SQL, like DB-API cursor objects. Dont forget to close() it! Actually we dont need to use the connection ... connection = engine.connect() result = connection.execute ("SELECT * FROM reports") # returns a sequence of dictionaries for row in result: print row[id], row[country] connection.close()
Dene tables
Instantiating a Table object (not dening a class), denes the corresponding table. The general form is Table (<name>, <metadata>, [<column denition>]+) Metadata binds table to database SampleTable = Table (sample, metadata, Column (ident, String(32), primary_key=True), Column (locn_lat, Float()), Column (locn_lon, Float()), Column (locn_method, String(32), default=EXACT), Column (country, String(64), nullable=False), Column (date_collected, Date()), ) SampleTable.create()
Table options
Dening table is a call. Create table via <class>.create(). Can create all bound tables with <metadata>.create all(). Links to actual database via metadata. Can take autoload parameter to work out columns from database.
Require a call on the table then an explicit execution query = SampleTable.insert() query.execute (ident=X47, locn_lat=34.1, locn_lon=-12.1) # ... or ... query = SampleTable.insert().execute ( ident=X47, locn_lat=34.1, locn_lon=-12.1)
Columns
Oddly familiar: String (length) A string. If length isnt given, the eld width is variable (Text) UnicodeCol A per StringCol, but with unicode strings. DateTime Also see Date and Time. Boolean May be implemented as a variety of types. Integer Duh. Numeric (precision, length) Precise oat with the given overall width and number of gures after the point. FloatCol (precision) A oat, with a level of precision.
Column parameters
primarykey False Is it a unique id for the row? You can have as many as you want ... nullable True Value for this column. when created. Can be callable. If no default, must be provided (like NOT NULL). default Default value for column. Will call if callable. Opposite to SQLObject. oninsert Default value when entry created and no value supplied. onupdate Default value when entry updated and no value supplied.
Column example
A timestamped table for samples, where a source must be provided, and a user-provided string serves as an id TimedTable = Table (sample, metadata, Column (ident, String(10), primarykey=True ) Column (source, String(30), nullable=False) Column (time_created, DateTime(), default=func.now()), Column(time_updated, DateTime(), onupdate=func.now()), )
Autoload tables
Derive columns from database users = Table(users, metadata, autoload=True) emails = Table(emails, metadata, autoload=True)
func
An answer to delayed execution / calling of functions: it binds a function and can later call it with passed parameters. func.now () Wraps now() for later calling. func.max (mylist) Wraps max for later calling max (mylist). func.substr (users.c.name, 2, 1) Wraps for later call users.c.name.substr (2, 1)
Mappers
Objects (in Python) dont automatically map to database tables and rows. Instead they are mapped. users = Table (user_table, ...) class User (object): pass usermapper = mapper (User, users)
Mapped classes
Any mapped classes get the columns of the table as members for free. Mapped classes must be derived from object. mapper (<class>, <table object>) You can use __init__ and subclass mapped objects Interaction takes place in the context of a session class Report (object): def init (self): # ... def setLocn (self, lat, lon): self.lat = lat self.lon = lon
Sessions
Sessions are devices for caching and saving the changes in objects in tables. bind_to parameter is optional. List the objects to be saved. sess = create_session (bind_to=engine) # ... much later ... sess.save (changed_objs) # saves everything sess.flush()
select
select method of table searches rows query = <table-class>.select ([<class>.q.field == <val>]+) query.execute() select_by() >>> query = report_table.select () >>> str (query) SELECT * FROM report ... >>> results = query.execute()
Results
Query results are sequences of dictionary-like objects Results are lazy and can be sliced Use fetch syntax Can (should) close results >>> results = query.execute() >>> first_row = results.fetchone() >>> first_row[id] X47 >>> first_row.id X47 >>> second_row = results[1] >>> results.close()
Select options
Use special c attribute to express clauses and conditions Can specify columns to return in select Can test elds some_cols_query = report_table.select ([report_table.c.id, report_table.c.country]) country_query = report_table.select (report_table.c.country==Burma) next_query = report_table.select (report_table.c.country.in_ ( North Korea, South Korea))
select operators
==, >, >=, etc. .like(), .startswith(), .endswith() .between(), and .in_() not_(), and_() and or_() (or ~, &, and |) +, -, *, /
Multiple selectors
Use and_, op_ & not to combine conditions. query = report_table.select (and_ ( (Report.c.diseaseStatus == None), or_ ( (Report.c.country == Burma), (Report.c.country == Myanmar), ), )
Can use func to make arbitrary tests of elds. report_table.select (func.substr ( report_table.c.country, 1) == A).execute()
You can select classes instead of tables. Make queries on session and filter. report_table.select (func.substr ( Report.c.country, 1) == A).execute() query = session.query (Report) reps = query.filter (Report.c.country == Burma)
orm.clear_mappers(): clears all class mappings, useful during development Allegedly slow Have to explicitly manage sessions Many ways to do things (like SQLObject)
MySQL tools
Graphical tools for administering MySQL. There are many - these are only based on my personal experience. Aqua Data Studio ($?) CocoaMySQL (OSX, maybe the best) iSQL (cross platform)
Resources