SQLAlchemy
доступ к реляционным данным
        в стиле Python


       Юревич Юрий, http://pyobject.ru

     Семинар Учебн...
«SQLAlchemy — это
Python SQL тулкит и ORM,
 которые предоставляют
      разработчику
всю мощь и гибкость SQL»
            ...
Active Record (Django ORM, Storm)




                                3
Data Mapper (SQLAlchemy)




                           4
Архитектура SQLAlchemy




                         5
Про что будет




                6
Про что (почти) не будет




                           7
Управление схемой данных




                           8
Схема == метаданные




                      9
Создание таблиц: SQL
CREATE TABLE users (
     id INTEGER NOT NULL,
     name VARCHAR(255),
     PRIMARY KEY (id)
  );
CRE...
Создание таблиц: SQLAlchemy
meta = MetaData()
users = Table('users', meta,
    Column('id', Integer, primary_key=True),
  ...
MetaData: что умеет
    Создавать/удалять:
●



        Всё сразу:
    –
            meta.create_all() / meta.drop_all()
 ...
MetaData: пример из жизни

# ... описание схемы

def get_indexes():
    return [
        Index('ix_users_id', users.c.id, ...
Язык SQL-выражений




                     14
Для любителей трехбуквенных
            сокращений
    DML (Data Managament Language):
●


        insert/update/delete
  ...
Insert
    Данные указываются при создании
●

     ins = users.insert(values={'name': u'Jack'})
     ins.execute()

    Да...
Delete
    Условие — SQLAlchemy SQL expression
●

      del_ = users.delete(users.c.name==u'Jack')
      del_.execute()

 ...
Select
SELECT *
FROM users


q = users.select()


SELECT users.id, users.name
FROM users


                              18
Select
SELECT id
FROM users
WHERE name='Jack'

q = users.select([users.c.id],
             users.c.name==u'Jack')

SELECT ...
Select
SELECT *
FROM users
JOIN creds ON
creds.user_id=users.id

q = users.join(creds).select()

SELECT users.id, users.na...
Почему SA SQL Expr?
    Потому что Python круче SQL
●




                                  21
Почему SA SQL Expr?
    Потому что Python круче SQL
●


    Генерация SQL на лету:
●


        q = select([users, creds.c....
Object Relational Mapper (ORM)




                                 23
Data Mapper, снова




                     24
Рабочий пример:
 схема данных




                  25
Рабочий пример:
                    таблицы в SQL
CREATE TABLE users (              CREATE TABLE messages (
           id ...
Рабочий пример:
                   Данные
users = {
    u'Jack': ['jack', 'jack-rabbit'],
    u'Edvard': ['ed'],
    u'Mar...
Рабочий пример:
              таблицы в SA SQL Expr
users = Table('users', meta,
   Column('id', Integer, primary_key=True...
Рабочий пример:
                     Mappings
Session = scoped_session(sessionmaker(autoflush=False))

class Base(object):...
Рабочий пример:
                  готовность №1
[ 1]>>> import schema as sch
[ 2]>>> import mappings as m

[   3]>>>   eng...
Рабочий пример:
               выборки
[1]>>> q = m.User.query.filter(User.id>1)
[2]>>> print str(q)
SELECT users.id AS us...
Рабочий пример:
      выборки (продолжение)
[1]>>> rabbit = m.Cred.query.
           filter_by(login='jack-rabbit').one()
...
Рабочий пример:
          выборки (хардкор)
# Выбрать пользователей, у которых
# в исходящих больше одного сообщения
[1]>>...
Рабочий пример:
                 сессия, unit of work
[   1]>>>   engine = create_engine('sqlite:///example.sqlite', echo=...
users = Table(
    'users', meta, ...)

class User:
    pass

mapper(users, User)




 «user» 5 раз, скучно?
             ...
Elixir:
ActiveRecord поверх SQLAlchemy
    Elixir (http://elixir.ematia.de):
●


        Декларативное описание в стиле Dj...
Еще вкусности SQLAlchemy
    «Хитрые» атрибуты:
●


          Отложенная/непосредственная подгрузка
     –

          SQL-...
Диагноз:
                нужна ли вам SA
    Используете другой           Используете DB
●                            ●

 ...
Вопросы?

 ... не успели задать? - шлите почтой: the.pythy@gmail.com



                                                  ...
Upcoming SlideShare
Loading in …5
×

SQLAlchemy Seminar

2,907 views
2,802 views

Published on

Seminar topic about SQLAlchemy -- Pythonic ORM and SQL toolkit.

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,907
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
40
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

SQLAlchemy Seminar

  1. 1. SQLAlchemy доступ к реляционным данным в стиле Python Юревич Юрий, http://pyobject.ru Семинар Учебного центра Люксофт, 16 сентября 2008
  2. 2. «SQLAlchemy — это Python SQL тулкит и ORM, которые предоставляют разработчику всю мощь и гибкость SQL» http://sqlalchemy.org 2
  3. 3. Active Record (Django ORM, Storm) 3
  4. 4. Data Mapper (SQLAlchemy) 4
  5. 5. Архитектура SQLAlchemy 5
  6. 6. Про что будет 6
  7. 7. Про что (почти) не будет 7
  8. 8. Управление схемой данных 8
  9. 9. Схема == метаданные 9
  10. 10. Создание таблиц: SQL CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id) ); CREATE TABLE creds ( id INTEGER NOT NULL, user_id INTEGER, login VARCHAR(20), passwd VARCHAR(40), PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES users (id) ); 10
  11. 11. Создание таблиц: SQLAlchemy meta = MetaData() users = Table('users', meta, Column('id', Integer, primary_key=True), Column('name', Unicode(255)), ) creds = Table('creds', meta, Column('id', Integer, primary_key=True), Column('user_id', Integer, ForeignKey('users.id')), Column('login', String(20)), Column('passwd', String(40)), ) 11
  12. 12. MetaData: что умеет Создавать/удалять: ● Всё сразу: – meta.create_all() / meta.drop_all() По отдельности: – users.create() / users.drop() Рефлексия: ● Потаблично: – users = Table('users', meta, autoload=True) Всё сразу: – meta.reflect() Интроспекция: ● meta.tables – 12
  13. 13. MetaData: пример из жизни # ... описание схемы def get_indexes(): return [ Index('ix_users_id', users.c.id, unique=True), Index('ix_creds_id', creds.c.id, unique=True), Index('ix_creds_user_id', creds.c.user_id), ] def load(): # ... загрузка данных pass def postload(): for ix in get_indexes(): ix.create() 13
  14. 14. Язык SQL-выражений 14
  15. 15. Для любителей трехбуквенных сокращений DML (Data Managament Language): ● insert/update/delete – DQL (Data Query Language): ● select – 15
  16. 16. Insert Данные указываются при создании ● ins = users.insert(values={'name': u'Jack'}) ins.execute() Данные указываются при выполнении ● ins = users.insert() ins.execute(name=u'Jack') Несколько записей сразу ● ins = users.insert() ins.execute([{'name': u'Jack'}, {'name': u'Ed'}]) Явно указывая соединение ● engine = create_engine('sqlite:///') ins = insert(users) engine.connect().execute(ins, {'name': u'Jack'}) 16
  17. 17. Delete Условие — SQLAlchemy SQL expression ● del_ = users.delete(users.c.name==u'Jack') del_.execute() Условие — строка с SQL ● del_ = users.delete('users.name=:user') del_.params({'user': u'Jack'}).execute() 17
  18. 18. Select SELECT * FROM users q = users.select() SELECT users.id, users.name FROM users 18
  19. 19. Select SELECT id FROM users WHERE name='Jack' q = users.select([users.c.id], users.c.name==u'Jack') SELECT users.id FROM users WHERE users.name=:name 19
  20. 20. Select SELECT * FROM users JOIN creds ON creds.user_id=users.id q = users.join(creds).select() SELECT users.id, users.name, creds.id, creds.user_id, creds.login, creds.passwd JOIN creds ON users.id=creds.user_id 20
  21. 21. Почему SA SQL Expr? Потому что Python круче SQL ● 21
  22. 22. Почему SA SQL Expr? Потому что Python круче SQL ● Генерация SQL на лету: ● q = select([users, creds.c.login], – from_obj=users.join(creds), whereclause=users.c.name==u'Jack') q = users.select() – q = q.where(users.c.name==u'Jack') q = q.column(creds.c.login) q.append_from(join(users, creds)) SELECT users.id, users.name, creds.login – FROM users JOIN creds ON creds.user_id = users.id WHERE users.name = 'Jack' 22
  23. 23. Object Relational Mapper (ORM) 23
  24. 24. Data Mapper, снова 24
  25. 25. Рабочий пример: схема данных 25
  26. 26. Рабочий пример: таблицы в SQL CREATE TABLE users ( CREATE TABLE messages ( id INTEGER NOT NULL, id INTEGER NOT NULL, name VARCHAR(255), subject VARCHAR(255), PRIMARY KEY (id) body TEXT, ); author_id INTEGER, PRIMARY KEY (id), CREATE TABLE creds ( FOREIGN KEY(author_id) id INTEGER NOT NULL, REFERENCES users (id) user_id INTEGER, ); login VARCHAR(20), passwd VARCHAR(20), CREATE TABLE message_recipients ( PRIMARY KEY (id), message_id INTEGER NOT NULL, FOREIGN KEY(user_id) recipient_id INTEGER NOT NULL, REFERENCES users (id) PRIMARY KEY ( message_id, recipient_id), ); FOREIGN KEY(message_id) REFERENCES messages (id), FOREIGN KEY(recipient_id) REFERENCES users (id) ); 26
  27. 27. Рабочий пример: Данные users = { u'Jack': ['jack', 'jack-rabbit'], u'Edvard': ['ed'], u'Mary': ['mary'], } messages = ( { 'author': u'Jack', 'recipients': [u'Edvard', u'Mary'], 'title': u'The first', 'body': u'Ha-ha, I'm the first!, }, { 'author': u'Edvard', 'recipients': [u'Jack', u'Mary'], 'title': u'Hey all', 'body': u'Hi, I'm here', }, { 'author': u'Edvard', 'recipients': [u'Mary'], 'title': u'The silence', 'body': u'Why are you ignoring me?', }, { 'author': u'Mary', 'recipients': [u'Jack'], 'title': u'Hi', 'body': u'Hi, Jack, how are you?', }, 27 )
  28. 28. Рабочий пример: таблицы в SA SQL Expr users = Table('users', meta, Column('id', Integer, primary_key=True), Column('name', Unicode(255)), ) creds = Table('creds', meta, Column('id', Integer, primary_key=True), Column('user_id', Integer, ForeignKey('users.id')), Column('login', String(20)), Column('passwd', String(20)), ) messages = Table('messages', meta, Column('id', Integer, primary_key=True), Column('subject', Unicode(255)), Column('body', Text), Column('author_id', Integer, ForeignKey('users.id')), ) message_recipients = Table('message_recipients', meta, Column('message_id', Integer, ForeignKey('messages.id'), primary_key=True), Column('recipient_id', Integer, ForeignKey('users.id'), primary_key=True), ) 28
  29. 29. Рабочий пример: Mappings Session = scoped_session(sessionmaker(autoflush=False)) class Base(object): def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) class User(Base): pass class Cred(Base): pass class Message(Base): pass Session.mapper(User, users) # (1) Session.mapper(Cred, creds, properties={ # (2) 'user': relation(User, backref='credentials'),}) Session.mapper(Message, messages, properties={ # (3) 'recipients': relation(User, backref='inbox', secondary=message_recipients), 29 'author': relation(User, backref='outbox'),})
  30. 30. Рабочий пример: готовность №1 [ 1]>>> import schema as sch [ 2]>>> import mappings as m [ 3]>>> engine = create_engine('sqlite:///example.sqlite') [ 4]>>> sch.meta.bind = engine [ 5]>>> sch.meta.create_all() [ 6]>>> m.Session.bind = engine [ 7]>>> u1 = m.User.query.get(1) [ 8]>>> u1.id <<< 1 [ 9]>>> u1.name <<< u'Jack' [10]>>> u1.credentials <<< [<Cred: jack>, <Cred: jack-rabbit>] [11]>>> u1.outbox <<< [<Message: from Jack to Edvard, Mary (subj: The first)>] 30
  31. 31. Рабочий пример: выборки [1]>>> q = m.User.query.filter(User.id>1) [2]>>> print str(q) SELECT users.id AS users_id, users.name AS users_name FROM users WHERE users.id > ? [3]>>> q = q.filter(m.User.name!=None) [4]>>> print str(q) SELECT users.id AS users_id, users.name AS users_name FROM users WHERE users.id > ? AND users.name IS NOT NULL [5]>>> list(q) <<< [<User u'Edvard'>, <User u'Mary'>] [6]>>> q.first() <<< <User u'Edvard'> 31
  32. 32. Рабочий пример: выборки (продолжение) [1]>>> rabbit = m.Cred.query. filter_by(login='jack-rabbit').one() [2]>>> rabbit_user = m.User.query. filter(User.credentials.contains(rabbit)). one() [3]>>> rabbit_messages = m.Message.query. filter(or_( Message.author==rabbit_user, Message.recipients.contains(rabbit_user) )) [4]>>> list(rabbit_messages) <<< [<Message: from Jack to Edvard, Mary (subj: The first)>, <Message: from Edvard to Jack, Mary (subj: Hey all)>, <Message: from Mary to Jack (subj: Hi)>] 32
  33. 33. Рабочий пример: выборки (хардкор) # Выбрать пользователей, у которых # в исходящих больше одного сообщения [1]>>> sess = m.Session() [2]>>> q = sess.query(m.User, func.count('*')). join(m.Message).group_by(m.User). having(func.count('*')>1) [3]>>> list(q) <<< [(<User u'Edvard'>, 2)] # Выбрать пользователей, у которых # во входящих больше одного сообщения [4]>>> sess = m.Session() [5]>>> q = sess.query(m.User, func.count('*')). join(sch.message_recipients).group_by(m.User). having(func.count('*')>1) [6]>>> list(q) <<< [(<User u'Jack'>, 2), (<User u'Mary'>, 3)] 33
  34. 34. Рабочий пример: сессия, unit of work [ 1]>>> engine = create_engine('sqlite:///example.sqlite', echo=True) [ 2]>>> sch.meta.bind = engine [ 3]>>> m.Session.bind = engine [ 4]>>> sess = m.Session() [ 5]>>> jack = m.User.query.filter_by(name=u'Jack').one() 2008-09-14 14:19:11,504 INFO sqlalchemy.engine.base.Engine.0x...ca2c SELECT... [ 6]>>> ed = m.User.query.filter_by(name=u'Edvard').one() 2008-09-14 14:20:22,731 INFO sqlalchemy.engine.base.Engine.0x...ca2c SELECT... [ 7]>>> jack.name = u'Jack Daniels' [ 8]>>> sess.dirty <<< IdentitySet([<User u'Jack Daniels'>]) [ 9]>>> ed.name = u'Edvard Noringthon' [10]>>> sess.dirty <<< IdentitySet([<User u'Edvard Noringthon'>, <User u'Jack Daniels'>]) [11]>>> sess.flush() 2008-09-14 14:21:00,535 INFO sqlalchemy.engine.base.Engine.0x...ca2c UPDATE users SET name=? WHERE users.id = ? 2008-09-14 14:21:00,535 INFO sqlalchemy.engine.base.Engine.0x...ca2c ['Jack Daniels', 1] 2008-09-14 14:21:00,604 INFO sqlalchemy.engine.base.Engine.0x...ca2c UPDATE users SET name=? WHERE users.id = ? 2008-09-14 14:21:00,604 INFO sqlalchemy.engine.base.Engine.0x...ca2c ['Edvard Noringthon', 2] 34
  35. 35. users = Table( 'users', meta, ...) class User: pass mapper(users, User) «user» 5 раз, скучно? 35
  36. 36. Elixir: ActiveRecord поверх SQLAlchemy Elixir (http://elixir.ematia.de): ● Декларативное описание в стиле Django – События: – До (update, insert, delete) ● После (update, insert, delete) ● Плагины: – acts_as_versioned (автоматическое хранение истории) ● acts_as_encrypted (шифрование колонок) ● associable (аналог Django generic relations) ● ... ● 36
  37. 37. Еще вкусности SQLAlchemy «Хитрые» атрибуты: ● Отложенная/непосредственная подгрузка – SQL-выражение как атрибут – Партицирование: ● Вертикальное (часть таблиц в одной БД, часть в другой) – Горизонтальное (шардинг, содержимое одной таблицы – «раскидано» по таблицам/БД) Нетривиальные маппинги: ● Несколько маппингов к одному классу – Маппинг классов к SQL-запросам – ... ● 37
  38. 38. Диагноз: нужна ли вам SA Используете другой Используете DB ● ● ORM и счастливы? API2 и «чистый» SQL? Нет, в SQLAlchemy – «много буков», нет Да, SQLAlchemy – смысла даст вам это и много что еще 38
  39. 39. Вопросы? ... не успели задать? - шлите почтой: the.pythy@gmail.com 39

×