Vous êtes sur la page 1sur 25

SQLAlchemy

Just like SQLObject

Third party library Object relational manager


Dene database tables, connect (map) classes to tables Table rows are objects / instances What you do to an object, you do to a row

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.

The awkward way of using the 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), ), )

Using func in select

Can use func to make arbitrary tests of elds. report_table.select (func.substr ( report_table.c.country, 1) == A).execute()

Select via mapped classes

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)

Odds and ends

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

SQLAlchemy SQLAlchemy tutorial SQLAlchemy talk slides

Vous aimerez peut-être aussi