SQLAlchemy Primer

97
SQLAlchemy Primer (extra content) for Kobe Python Meetup #13 2017/09/15 Kobe Japan

Transcript of SQLAlchemy Primer

Page 1: SQLAlchemy Primer

SQLAlchemy Primer(extra content)

for Kobe Python Meetup #13 2017/09/15 Kobe Japan

Page 2: SQLAlchemy Primer

Yasushi Masuda PhD ( @whosaysni )

Tech team, Core IT grp. IT Dept. MonotaRO Co., LTD.

Pythonista since 2001 (2.0~) • elaphe (barcode library) • oikami.py (老神.py) • PyCon JP founder

Japanese Translation works

Page 3: SQLAlchemy Primer

Agenda

Myths

Core concepts in SQLAlchemy

Engine basics (+hands-on)

ORM primer (+hans-on)

Page 4: SQLAlchemy Primer

References

Online Document:http://docs.sqlalchemy.org/

en/rel_1_1/

(Old) Japanese translation:http://omake.accense.com/static/doc-ja/sqlalchemy/

Page 5: SQLAlchemy Primer

Preparationsakila DB on SQLite http://bit.ly/2fdeeft

https://github.com/jOOQ/jOOQ/jOOQ-examples/Sakila/sqlite-sakila-db/sqlite-sakila.sq

Sakila • Demonstration

DB for MySQL • Models a rental

video shop • BSD License

Schema described at: https://dev.mysql.com/doc/sakila/en/sakila-structure-tables.html

Page 6: SQLAlchemy Primer

Myths[WRONG!] It's just an ORM libraryNot limited to. SQLAlchemy is a DB manipulation framework.

[WRONG!] SA is built on ORMNO. Connection management and SQL expression framework are its core.ORM is built on them.[WRONG!] SA cannot handle raw SQLTable definition is not required. Even textual SQL is available.

[WRONG!] SA automatically escapes value for youSQLAlchemy relies value escaping on DB-API, while it escapes schema, table, column names. SQLAlchemy generates parameterized query that helps DB-API level escaping.

[WRONG!] Only Python adept can handle SASQLAlchemy is EASY. You may need SQL and RDBMS experience. Let's see!

[AGREE] Documentation is somewhat difficult to understandAgreed.

Page 7: SQLAlchemy Primer

Core concepts

Page 8: SQLAlchemy Primer

http://docs.sqlalchemy.org/en/latest/index.html

Page 9: SQLAlchemy Primer

http://docs.sqlalchemy.org/en/latest/index.html

SQLAlchemy Core

Engine (connection) Schema definitionSQL Expression

SQLAlchemy ORM

Mapper Declarative Mapper

Session

Dialect DB Backend-specific functionalities

Page 10: SQLAlchemy Primer

Engine manages DB connection(s)

SQL Expressiondescribes SQL statement in Python

Mappingreflects DB record with Python object

Dialect DB Backend specific functionalities

Page 11: SQLAlchemy Primer

DatabaseYour program

SQL construction

Query execution

Typeconversion

Parameter binding

Driver Setup

Connection management

Result data structure

Value escaping

Schema name

Type conversion

Dialect-specific

Query Construction

Query Execution

Result

Schema object Object-relational mapping

High-level Interface

DB Session

Page 12: SQLAlchemy Primer

Engine

Page 13: SQLAlchemy Primer

DB API DB ServerProgram

Issues around DB-API

Which DB-API to use How to initialize the DB-API

How to generate valid query for it How to handle cursor on the DB-API How to execute query on the DB-API How to retrieve result from DB-API How to reserve/reuse connection

Page 14: SQLAlchemy Primer

DB API DB ServerProgram

Engine resolves issues

Select DB-API from DSN URL Initialize DB-API for you

Accept string and SQL expression Manage cursor for you

Unify execution/transaction API Handle result via ResultProxy Pool connection automatically

Engine

Page 15: SQLAlchemy Primer

Engine DB API DB ServerProgram

>>>fromsqlalchemyimportcreate_engine>>>

Page 16: SQLAlchemy Primer

Engine DB API DB ServerProgram

>>>fromsqlalchemyimportcreate_engine>>>e=create_engine('sqlite://')#SQLitememoryengine>>>

Page 17: SQLAlchemy Primer

Engine DB API DB ServerProgram

#UseURLforspecifyingdatabase>>>e=create_engine('sqlite://')#SQLitememoryengine>>>e=create_engine('sqlite:///path_to_db.sqlite3')#sqlite3>>>e=create_engine('mysql://scott:tiger@dbserv/dbname')#mysql>>>e=create_engine('mssql://bill:gates@dbserv/dbname')#mssql>>>

Page 18: SQLAlchemy Primer

Engine DB API DB ServerProgram

#Becarefulwithnumberofslashes>>>e=create_engine('sqlite:///sqlite-sakila.sq')>>>e=create_engine('sqlite:////<absolute_path>/sqlite-sakila.sq')

Page 19: SQLAlchemy Primer

Engine DB API DB ServerProgram

>>>e=create_engine('sqlite:///sqlite-sakila.sq')>>>eEngine(sqlite:///sakila-data.sq)

#executereturnsResultProxy>>>q='selecttitlefromfilmlimit5')>>>res=e.execute(q)>>>res<sqlalchemy.engine.result.ResultProxyobjectat0x10da96990>>>>

Page 20: SQLAlchemy Primer

Engine DB API DB ServerProgram

>>>e=create_engine('sqlite:///sqlite-sakila.sq')>>>eEngine(sqlite:///sakila-data.sq)

#executereturnsResultProxy>>>q='selecttitlefromfilmlimit5')>>>res=e.execute(q)>>>res<sqlalchemy.engine.result.ResultProxyobjectat0x10da96990>>>forrowinres:#ResultProxycanbeiterated/namedtupleaccess...print(row.title)...ACADEMYDINOSAURACEGOLDFINGERADAPTATIONHOLESAFFAIRPREJUDICEAFRICANEGG>>>

Page 21: SQLAlchemy Primer

Engine DB API DB ServerProgram

>>>q='selectfilm_id,titlefromfilmlimit10'>>>rows=list(e.execute(q))>>>rows[2][1]#eachrowisaccessiblelikeastuple'ADAPTATIONHOLES'>>>rows[4]['title']#rowcanbeaccessiblelikeasdictionary'AFRICANEGG'

>>>res=e.execute(q)>>>forfid,titleinres:#canbeexpandedasnormaltuple...print((fid,title))...(1,'ACADEMYDINOSAUR')(2,'ACEGOLDFINGER')(3,'ADAPTATIONHOLES')(4,'AFFAIRPREJUDICE')(5,'AFRICANEGG')>>>rows=list(e.execute(q))>>>

Page 22: SQLAlchemy Primer

transaction

>>>t=e.begin()>>>t.transaction<sqlalchemy...RootTransactionobjectat...>>>>t.transaction.commit()

#withstatementhandlestransactionsmart>>>withe.begin():e.execute(...)>>>#(transactioncommittedautomatically)

Page 23: SQLAlchemy Primer

HANDS ON: Engine basics

Connecttosqlite-sakila.sqdatabase

Listactorsinfilm"DINOSAURSECRETARY"

Page 24: SQLAlchemy Primer

HANDS ON: Engine basics

>>>e=create_engine('sqlite:///sqlite-sakila.sq')>>>q='''selecta.first_name,a.last_name...fromfilmasf...innerjoinfilm_actorasfa...onf.film_id=fa.film_id...innerjoinactorasa...onfa.actor_id=a.actor_id...wheref.title="DINOSAURSECRETARY"'''>>>forfirst_name,last_nameine.execute(q):...print('{}{}'.format(first_name,last_name))...LUCILLETRACYBURTDUKAKISJAYNENEESONRUSSELLBACALLPENELOPEMONROEMINNIEKILMER

Page 25: SQLAlchemy Primer

SQL expression

Page 26: SQLAlchemy Primer

Remember: SQL is a language

SELECT[ALL|DISTINCT[ON(expression[,...])]]

[*|expression[[AS]output_name][,...]]

[FROMfrom_item[,...]]

[WHEREcondition]

[GROUPBYgrouping_element[,...]]

[ORDERBYexpression[ASC|DESC|USINGoperator][NULLS{FIRST|LAST}][,...]]

[LIMIT{count|ALL}]

Page 27: SQLAlchemy Primer

Remember: SQL is a language

SELECT[ALL|DISTINCT[ON(expression[,...])]]

[*|expression[[AS]output_name][,...]]

[FROMfrom_item[,...]]

[WHEREcondition]

[GROUPBYgrouping_element[,...]]

[ORDERBYexpression[ASC|DESC|USINGoperator][NULLS{FIRST|LAST}][,...]]

[LIMIT{count|ALL}]

STATEMENT

Page 28: SQLAlchemy Primer

Remember: SQL is a language

SELECT[ALL|DISTINCT[ON(expression[,...])]]

[*|expression[[AS]output_name][,...]]

[FROMfrom_item[,...]]

[WHEREcondition]

[GROUPBYgrouping_element[,...]]

[ORDERBYexpression[ASC|DESC|USINGoperator][NULLS{FIRST|LAST}][,...]]

[LIMIT{count|ALL}]

CLAUSE

CLAUSE

CLAUSE

CLAUSE

CLAUSE

CLAUSE

Page 29: SQLAlchemy Primer

Remember: SQL is a language

SELECT[ALL|DISTINCT[ON(expression[,...])]]

[*|expression[[AS]output_name][,...]]

[FROMfrom_item[,...]]

[WHEREcondition]

[GROUPBYgrouping_element[,...]]

[ORDERBYexpression[ASC|DESC|USINGoperator][NULLS{FIRST|LAST}][,...]]

[LIMIT{count|ALL}]

parameter

parameter

expression

expression

expression

expression

expression

expression

Page 30: SQLAlchemy Primer

Remember: SQL is a Language

SELECT

FROM selectablesselectable

join

WHERE

selectable

selectable

GROUP BY ORDER BY

expression

expressioncondition

expression

expressionsexpression

expression

SELECT statement

Page 31: SQLAlchemy Primer

SELECTA.name,B.title,C.title

FROMartistsasAINNERJOINalbumasBONA.id=B.artist_idINNERJOINmusicasCONB.id=C.album

WHEREA.nameLIKE'%Astor%'ANDA.yearBETWEEN1970AND2010ANDC.titleLIKE'%Tango%'

From SQL to Python

Page 32: SQLAlchemy Primer

SELECT<column>,<column>,...

FROM<selectable>INNERJOIN<selectable>ON<condition>INNERJOIN<selectable>ON<condition>...

WHERE<condition>AND<condition>AND<condition>

GROUPBY...LIMIT...

Clauses

Page 33: SQLAlchemy Primer

SELECT<[<column>,<column>,<column>]>

FROM<join(<selectable>,<selectable>,...)>

WHERE<and(<condition>,<condition>,...)>

Statement and subjects

Page 34: SQLAlchemy Primer

SELECT<expressions>

FROM<selectable>

WHERE<conditions>

... simplifed

Page 35: SQLAlchemy Primer

<selectstatement>

..., finally

Page 36: SQLAlchemy Primer

engine.execute(<selectstatement>)

If query is "an object"...

Query object

Page 37: SQLAlchemy Primer

>>>query=select(...)

>>>engine.execute(query)

... it can be "execute()-able"

Engine "compiles" query into string and execute it

(according to dialect)

Page 38: SQLAlchemy Primer

query=select(

<expression>,

from_obj=<selectables>,

whereclause=<conditions>,

)

clauses as parameters

Page 39: SQLAlchemy Primer

columns=[col1,col2,...]

fromobj=join(tbl1,tbl2,...)

where=and_(expr1,expr2,...)

query_expr=select(columns,from_obj=fromobj,whereclause=where)

query with SQL expression

Page 40: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,text>>>q=select([text('*')])

building sql statement with basic sql expression

Page 41: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,text>>>q=select([text('*')])>>>q<sqlalchemy.....Selectat...;Selectobject>>>>str(q)'SELECT*'>>>q=select([text('*')],...from_obj=text('foo'),...whereclause=text('id=3'))>>>str(q)'SELECT*\nFROMfoo\nWHEREid=3'

building sql statement with basic sql expression

Page 42: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,text>>>q=select([text('*')])>>>q<sqlalchemy.....Selectat...;Selectobject>>>>str(q)'SELECT*'>>>q=select([text('*')],...from_obj=text('foo'),...whereclause=text('id=3'))>>>str(q)'SELECT*\nFROMfoo\nWHEREid=3'

building sql statement with basic sql expression

Page 43: SQLAlchemy Primer

elements: table and columnSchema

Table Table Table

...

Column

Column

Column

...

Column

Column

Column

...

Column

Column

Column

...

SchemaTable Table Table

Column

Column

Column

Column

Column

Column

...

Page 44: SQLAlchemy Primer

elements: table and column>>>fromsqlalchemy.sqlimportcolumn,table>>>fromsqlalchemyimportINTEGER

Page 45: SQLAlchemy Primer

elements: table and column>>>fromsqlalchemy.sqlimportcolumn,table>>>fromsqlalchemyimportINTEGER>>>c=column('name')#simplest>>>c=column('name',type_=INTEGER)

Page 46: SQLAlchemy Primer

elements: table and column>>>fromsqlalchemy.sqlimportcolumn,table>>>fromsqlalchemyimportINTEGER>>>c=column('name')#simplest>>>c=column('name',type_=INTEGER)>>>c<sqlalchemy....ColumnClauseat...;name>>>>str(c)'name'

Page 47: SQLAlchemy Primer

elements: table and column>>>fromsqlalchemy.sqlimportcolumn,table>>>fromsqlalchemyimportINTEGER>>>c=column('name')#simplest>>>c=column('name',type_=INTEGER)>>>c<sqlalchemy....ColumnClauseat...;name>>>>str(c)'name'>>>c.table#None>>>t1=table('artist')>>>c.table=t1>>>str(c)'artist.name'

Page 48: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),...)

defining table with columnsTable name List of columns

Page 49: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),...)

>>>t.c.col1

<sqlalchemy.....ColumnClauseat...;col1>

defining table with columnsTable name List of columns

Page 50: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),...)

>>>t.c.col1

<sqlalchemy.....ColumnClauseat...;col1>

>>>t.schema='db1'

>>>str(t.c.col1)

'db1.tbl1.col1'

defining table with columnsTable name List of columns

Page 51: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),column('col2'))

select() with table element

Page 52: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),column('col2'))>>>print(select([t]))SELECTtbl1.col1,tbl1.col2FROMtbl1

select() with table element

Page 53: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),column('col2'))>>>print(select([t]))SELECTtbl1.col1,tbl1.col2FROMtbl1

#columnlabeling>>>print(select([t.c.col1.label('col_alias1')])SELECTtbl1.col1as"col_alias1"FROMtbl1

select() with table element

Page 54: SQLAlchemy Primer

>>>t=table('tbl1',column('col1'),column('col2'))>>>print(select([t]))SELECTtbl1.col1,tbl1.col2FROMtbl1

#columnlabeling>>>print(select([t.c.col1.label('col_alias1')])SELECTtbl1.col1as"col_alias1"FROMtbl1

#tablealias>>>t_A,t_B=alias(t,'A'),alias(t,'B')>>>print(select([t_A.c.col1,t_B.c.col2]))SELECT"A".col1,"B".col2FROMtbl1AS"A",tbl1AS"B"

select() with table element

Page 55: SQLAlchemy Primer

howtoworkwith

wheretbl1.col1=42

conditionals

Page 56: SQLAlchemy Primer

howtoworkwith

wheretbl1.col1=42

conditionals

conditional expression (compare operation)

Page 57: SQLAlchemy Primer

>>>cond=text('last_nameLIKE%KOV')>>>str(cond)'last_nameLIKE%KOV'

conditional by text()

Page 58: SQLAlchemy Primer

>>>cond=column('last_name').like('%KOV')>>>cond<sqlalchemy....BinaryExpressionobjectat...>

conditional by like() method

Page 59: SQLAlchemy Primer

>>>cond=column('last_name').like('%KOV')>>>cond<sqlalchemy....BinaryExpressionobjectat...>>>>str(cond)'last_nameLIKE:last_name_1'

conditional by like() method

placeholder for right value of LIKE

Page 60: SQLAlchemy Primer

>>>cond=column('last_name').like('%KOV')>>>cond<sqlalchemy....BinaryExpressionobjectat...>>>>str(cond)'last_nameLIKE:last_name_1

>>>cond.rightBindParameter('%(4339977744last_name)s','%KOV',type_=String())

conditional by like() method

Page 61: SQLAlchemy Primer

>>>column('first_name')='DAVID'File"<stdin>",line1SyntaxError:can'tassigntofunctioncall

conditional by operation

Page 62: SQLAlchemy Primer

>>>column('first_name')='DAVID'File"<stdin>",line1SyntaxError:can'tassigntofunctioncall

>>>column('first_name')=='DAVID'<sqlalchemy...BinaryExpressionobjectat...>

conditional by operation

Page 63: SQLAlchemy Primer

>>>column('first_name')='DAVID'File"<stdin>",line1SyntaxError:can'tassigntofunctioncall

>>>column('first_name')=='DAVID'<sqlalchemy...BinaryExpressionobjectat...>

>>>cond=column('first_name')=='DAVID'>>>str(cond)>>>'first_name=:first_name_1'>>>cond.right>>>BindParameter('%(...)s','DAVID',type_=...)

conditional by operation

Page 64: SQLAlchemy Primer

>>>column('first_name')='DAVID'File"<stdin>",line1SyntaxError:can'tassigntofunctioncall

>>>column('first_name')=='DAVID'<sqlalchemy...BinaryExpressionobjectat...>

>>>cond=column('first_name')=='DAVID'>>>str(cond)>>>'first_name=:first_name_1'>>>cond.right>>>BindParameter('%(...)s','DAVID',type_=...)

>>>str(column('last_name')==None)>>>'last_nameisNULL'

conditional by operation

Page 65: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,table,column>>>actor_tbl=table('actor',column('actor_id'),...column('first_name'),column('last_name'))

conditionals in select

Page 66: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,table,column>>>actor_tbl=table('actor',column('actor_id'),...column('first_name'),column('last_name'))>>>query=select([actor_tbl],...whereclause=(actor_tbl.c.last_name=='TRACY'))

conditionals in select

Page 67: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,table,column>>>actor_tbl=table('actor',column('actor_id'),...column('first_name'),column('last_name'))>>>query=select([actor_tbl],...whereclause=(actor_tbl.c.last_name=='TRACY'))>>>query<sqlalchemy.....Selectat...;Selectobject>>>>print(query)SELECTactor.first_name,actor.last_nameFROMactorWHEREactor.last_name=:last_name_1>>>query.compile().params{'last_name_1':'TRACY'}

conditionals in select

Page 68: SQLAlchemy Primer

>>>fromsqlalchemy.sqlimportselect,table,column>>>actor_tbl=table('actor',column('actor_id'),...column('first_name'),column('last_name'))>>>query=select([actor_tbl],...whereclause=(actor_tbl.c.last_name=='TRACY'))>>>query<sqlalchemy.....Selectat...;Selectobject>>>>print(query)SELECTactor.actor_id,actor.first_name,actor.last_nameFROMactorWHEREactor.last_name=:last_name_1>>>query.compile().params{'last_name_1':'TRACY'}>>>list(e.execute(query))[(20,'LUCILLE','TRACY'),(117,'RENEE','TRACY')]

conditionals in select

Page 69: SQLAlchemy Primer

select(...)

SELECT...

select(...).select_from(...)

SELECT...FROM...

select(...).where(...)

SELECT...WHERE...

select(...).where(...).where(...)

SELECT...WHERE...AND...

select(...).where(...).order_by(...)

SELECT...WHERE...ORDERBY...

generative method

Page 70: SQLAlchemy Primer

actor_tbl.select()SELECT...FROMactor

actor_tbl.select(actor_tbl.c.first_name='BEN')SELECT...FROMactorWHEREfirst_name=...

generative method

Page 71: SQLAlchemy Primer

HANDS ON: SQL expression

• define actor table with table()/column()

• build query with sql expression to searchactor having initial A.H. (result should include actor_id)

Page 72: SQLAlchemy Primer

Schema definition

Page 73: SQLAlchemy Primer

howtoCREATEtable

schema definition

Page 74: SQLAlchemy Primer

howtoCREATEtable

howtodefinecolumndetailhowtodefineconstraints

schema definition

Page 75: SQLAlchemy Primer

>>>fromsqlalchemyimportColumn,MetaData,Table>>>user_table=Table(...'user',MetaData(),...Column('id',INTEGER,primary_key=True),...Column('first_name',VARCHAR(45)),...Column('last_name',VARCHAR(45)))>>>

defining table

Page 76: SQLAlchemy Primer

>>>fromsqlalchemyimportColumn,MetaData,Table>>>user_table=Table(...'user',MetaData(),...Column('id',INTEGER,primary_key=True),...Column('first_name',VARCHAR(45)),...Column('last_name',VARCHAR(45)))>>>user_tableTable('user',MetaData(bind=None),Column...)

defining table

Page 77: SQLAlchemy Primer

>>>fromsqlalchemyimportColumn,MetaData,Table>>>user_table=Table(...'user',MetaData(),...Column('id',INTEGER,primary_key=True),...Column('first_name',VARCHAR(45)),...Column('last_name',VARCHAR(45)))>>>user_tableTable('user',MetaData(bind=None),Column...)

#CREATETABLEbycrete()>>>user_table.create(bind=e)

#DROPTABLEwithdrop()>>>user_table.drop(bind=e)

defining table

Page 78: SQLAlchemy Primer

Table/Column vs table/columnVisitable (base type)

ClauseElement

Selectable

FromClause [ table() ]

ColumnElement

ColumnClause [ column() ]

Column Table

SchemaItem

Page 79: SQLAlchemy Primer

Table/Column vs table/columnVisitable (base type)

ClauseElement

Selectable

FromClause [ table() ]

ColumnElement

ColumnClause [ column() ]

Column Table

SchemaItem

Supprorts same operation

Page 80: SQLAlchemy Primer

HANDS ON: Schema definition

• define "user" table with Table()/Column()

• create table with .create()

• insert records

• drop table with .drop()

name type options

id INTEGER primary_key

username VARCHAR (64) nullable=False

email VARCHAR(128) nullable=False

Page 81: SQLAlchemy Primer

ORM basics

Page 82: SQLAlchemy Primer

Object-Relational Mapping

• Map DB records to objects

• ActiveRecord pattern

• 1 table ~> 1 class, 1 record ~> 1 object

• FK reference -> reference to other object

• column -> property/attribute of object

Page 83: SQLAlchemy Primer

ORM in SQLAlchemy

• mapper maps a table with Python classmapped class will have instrumented attribute

• Session manipulates DB for you to retrieve / save mapped objects

Page 84: SQLAlchemy Primer

mappingTable

Column foo

Column bar

Column baz

...

entity class

"mapped" entity class

instrumented fooinstrumented barinstrumented baz

...

method quxmethod quux

method quxmethod quux

...

mapper

Page 85: SQLAlchemy Primer

classic mapping

[new] declarative mapping

mapping patterns

Page 86: SQLAlchemy Primer

>>>fromsqlalchemy.ormimportmapper>>>actor_tbl=Table(...)>>>classActor(object):pass>>>mapper(Actor,actor_tbl)>>>dir(Actor)['__class__',...'_sa_class_manager','actor_id','first_name','last_name']>>>Actor.actor_id<...InstrumentedAttributeobjectat...>

classic mapping

Page 87: SQLAlchemy Primer

>>>fromsqlalchemy.ext.declarativeimportdeclarative_base>>>fromsqlalchmyimportDateTime,Integer,String>>>Base=declarative_base()>>>>>>classActor(Base):...__tablename__='actor'...actor_id=Column(Integer,primary_key=True)...first_name=Column(String)...last_name=Column(String)...last_update=Column(DateTime)

declarative mapping

Page 88: SQLAlchemy Primer

>>>fromsqlalchemy.ext.declarativeimportdeclarative_base>>>fromsqlalchmyimportDateTime,Integer,String>>>Base=declarative_base()>>>>>>classActor(Base):...__tablename__='actor'...actor_id=Column(Integer,primary_key=True)...first_name=Column(String)...last_name=Column(String)...last_update=Column(DateTime)>>>dir(Actor)['__class__','_decl_class_registry','_sa_class_manager','actor_id','first_name','last_name','last_update','metadata']

declarative mapping

Page 89: SQLAlchemy Primer

ORM in SQLAlchemy

• mapper maps a table with Python classmapped class will have instrumented attribute

• Session manipulates DB for you to retrieve / save mapped objects

Page 90: SQLAlchemy Primer

sessionEngineProgram

query Aselect A

record Aobject Bstart

tracking A

...

(updates) flag A as "dirty"

reflect new/dirty changes

flush

starttracking B

...

add object B

update A insert B

commit

begin

Page 91: SQLAlchemy Primer

Using Session

>>>fromsqlalchemy.ormimportsessionmaker>>>Session=sessionmaker(bind=e)>>>session=Session()>>>>>>

Page 92: SQLAlchemy Primer

Using Session

>>>fromsqlalchemy.ormimportsessionmaker>>>Session=sessionmaker(bind=e)>>>session=Session()>>>query=session.query(Actor)>>>query<sqlalchemy.orm.query.Queryobjectat...>

Page 93: SQLAlchemy Primer

Using Session

>>>fromsqlalchemy.ormimportsessionmaker>>>Session=sessionmaker(bind=e)>>>session=Session()>>>query=session.query(Actor)>>>query<sqlalchemy.orm.query.Queryobjectat...>>>>actor=query.first()>>>actor<...ActorObjectat...>

Page 94: SQLAlchemy Primer

Query object methods: query filtering

>>>q=session.query(Actor)>>>str(q)>>>'SELECT...\nFROMactor'>>>q1=q.filter(Actor.first_name=='BEN')>>>str(q1)'SELECT...\nFROMactor\nWHEREactor.first_name=?'>>>q2=q1.filter_by(last_name='SMITH')>>>str(q2)'SELECT...\nFROMactor\nWHEREactor.first_name=?ANDactor.last_name=?'

Page 95: SQLAlchemy Primer

Query object methods: fetching record(s)

>>>q=session.query(Actor)>>>q.first()<...Actorobjectat...>

>>>q.all()#WARNING:SELECTsallrecords<...Actorobjectat...>,<...Actorobjectat...>,...

>>>q[:3]<...Actorobjectat...>,<...Actorobjectat...>,...

>>>q.count()200

Page 96: SQLAlchemy Primer

Update/Insert in Session

>>>session=Session()>>>actor_a=Actor(first_name='KEN',...last_name='WATANABE')>>>session.add(actor_a)>>>session.commit()

>>>actor_b=session.query(Actor).get(1)>>>actor_b.last_name='GEORGE'>>>session.commit()

Page 97: SQLAlchemy Primer

HANDS ON: ORM basics

• define Category model with declarative ORM

• select any record

• add "Nature" category

• delete "Nature" category