5. Preparation
sakila 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
6. Myths
[WRONG!] It's just an ORM library
Not limited to. SQLAlchemy is a DB manipulation framework.
[WRONG!] SA is built on ORM
NO. Connection management and SQL expression framework are its core.
ORM is built on them.
[WRONG!] SA cannot handle raw SQL
Table definition is not required. Even textual SQL is available.
[WRONG!] SA automatically escapes value for you
SQLAlchemy 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 SA
SQLAlchemy is EASY. You may need SQL and RDBMS experience. Let's see!
[AGREE] Documentation is somewhat difficult to understand
Agreed.
10. Engine
manages DB connection(s)
SQL Expression
describes SQL statement in Python
Mapping
reflects DB record with Python object
Dialect
DB Backend specific functionalities
13. 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
14. 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
15. Engine DB API DB ServerProgram
>>> from sqlalchemy import create_engine
>>>
16. Engine DB API DB ServerProgram
>>> from sqlalchemy import create_engine
>>> e = create_engine('sqlite://') # SQLite memory engine
>>>
17. Engine DB API DB ServerProgram
# Use URL for specifying database
>>> e = create_engine('sqlite://') # SQLite memory engine
>>> 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
>>>
18. Engine DB API DB ServerProgram
# Be careful with number of slashes
>>> e = create_engine('sqlite:///sqlite-sakila.sq')
>>> e = create_engine('sqlite:////<absolute_path>/sqlite-sakila.sq')
19. Engine DB API DB ServerProgram
>>> e = create_engine('sqlite:///sqlite-sakila.sq')
>>> e
Engine(sqlite:///sakila-data.sq)
# execute returns ResultProxy
>>> q = 'select title from film limit 5')
>>> res = e.execute(q)
>>> res
<sqlalchemy.engine.result.ResultProxy object at 0x10da96990>
>>>
20. Engine DB API DB ServerProgram
>>> e = create_engine('sqlite:///sqlite-sakila.sq')
>>> e
Engine(sqlite:///sakila-data.sq)
# execute returns ResultProxy
>>> q = 'select title from film limit 5')
>>> res = e.execute(q)
>>> res
<sqlalchemy.engine.result.ResultProxy object at 0x10da96990
>>> for row in res: # ResultProxy can be iterated/namedtuple access
... print(row.title)
...
ACADEMY DINOSAUR
ACE GOLDFINGER
ADAPTATION HOLES
AFFAIR PREJUDICE
AFRICAN EGG
>>>
21. Engine DB API DB ServerProgram
>>> q = 'select film_id, title from film limit 10'
>>> rows = list(e.execute(q))
>>> rows[2][1] # each row is accessible like as tuple
'ADAPTATION HOLES'
>>> rows[4]['title'] # row can be accessible like as dictionary
'AFRICAN EGG'
>>> res = e.execute(q)
>>> for fid, title in res: # can be expanded as normal tuple
... print((fid, title))
...
(1, 'ACADEMY DINOSAUR')
(2, 'ACE GOLDFINGER')
(3, 'ADAPTATION HOLES')
(4, 'AFFAIR PREJUDICE')
(5, 'AFRICAN EGG')
>>> rows = list(e.execute(q))
>>>
23. HANDS ON: Engine basics
Connect to sqlite-
sakila.sq database
List actors in film
"DINOSAUR SECRETARY"
24. HANDS ON: Engine basics
>>> e = create_engine('sqlite:///sqlite-sakila.sq')
>>> q = '''select a.first_name, a.last_name
... from film as f
... inner join film_actor as fa
... on f.film_id=fa.film_id
... inner join actor as a
... on fa.actor_id=a.actor_id
... where f.title = "DINOSAUR SECRETARY"'''
>>> for first_name, last_name in e.execute(q):
... print('{} {}'.format(first_name, last_name))
...
LUCILLE TRACY
BURT DUKAKIS
JAYNE NEESON
RUSSELL BACALL
PENELOPE MONROE
MINNIE KILMER
26. Remember: SQL is a language
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ ORDER BY expression
[ ASC | DESC | USING operator ]
[ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
27. Remember: SQL is a language
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ ORDER BY expression
[ ASC | DESC | USING operator ]
[ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
STATEMENT
28. Remember: SQL is a language
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ ORDER BY expression
[ ASC | DESC | USING operator ]
[ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
CLAUSE
CLAUSE
CLAUSE
CLAUSE
CLAUSE
CLAUSE
29. Remember: SQL is a language
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ ORDER BY expression
[ ASC | DESC | USING operator ]
[ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
parameter
parameter
expression
expression
expression
expression
expression
expression
30. Remember: SQL is a Language
SELECT
FROM selectables
selectable
join
WHERE
selectable
selectable
GROUP BY
ORDER BY
expression
expression
condition
expression
expressions
expression
expression
SELECT statement
71. HANDS ON: SQL expression
• define actor table with
table()/column()
• build query with sql
expression to search
actor having initial A.H.
(result should include
actor_id)
80. 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
82. 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
83. ORM in SQLAlchemy
• mapper maps a table with Python class
mapped class will have instrumented attribute
• Session manipulates DB for you to retrieve / save
mapped objects
84. mapping
Table
Column foo
Column bar
Column baz
...
entity class
"mapped" entity class
instrumented foo
instrumented bar
instrumented baz
...
method qux
method quux
method qux
method quux
...
mapper
89. ORM in SQLAlchemy
• mapper maps a table with Python class
mapped class will have instrumented attribute
• Session manipulates DB for you to retrieve / save
mapped objects
90. session
Engine
Program
query A
select A
record Aobject B
start
tracking A...
(updates) flag A as
"dirty"
reflect new/dirty
changes
flush
start
tracking B
...
add
object B
update A
insert B
commit
begin