32
SQLAlchemy BPStyle #4 小田切 aodag 篤

Sql alchemy bpstyle_4

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Sql alchemy bpstyle_4

SQLAlchemyBPStyle #4小田切 aodag 篤

Page 2: Sql alchemy bpstyle_4

 

アクティブレコードとデータマッパーSQLAlchemyデータマッピング宣言的な方法関連継承Session

Page 3: Sql alchemy bpstyle_4

アクティブレコードとデータマッパー

アクティブレコードクラスとテーブルを1対1に割り当てるマッピング(オブジェクトと行が対応する)簡単融通は利かない多対多関連ではマッピングされないテーブルが存在する

データマッパークラスに対するテーブルマッピングを指定する柔軟性が高いちょっと面倒多対多関連で関連属性もマッピング可能

Page 4: Sql alchemy bpstyle_4

SQLAlchemy

データマッパータイプのORマッパーSQLをPythonオブジェクトで構築Unit of workパターン

Page 5: Sql alchemy bpstyle_4

対応データベース

SQLiteMySQLPostgreSQLFirebirdOracleSQL ServerDB2

など

Page 6: Sql alchemy bpstyle_4

データマッピング(1) スキーマ定義

person_table = Table("person", meta, Column("person_id", Integer, primary_key), Column("first_name", Unicode(20)), Column("last_name", Unicode(20)), Column("birthday", Date))

要するにテーブル

Page 7: Sql alchemy bpstyle_4

データマッピング(2) マッピング先

class Person(object): """ A person """

def __init__(self, first_name, last_name, birthday): self.first_name, self.last_name, self.birthday = first_name, last_name, birthday

普通のクラス

Page 8: Sql alchemy bpstyle_4

データマッピング(3) マッピング

person_mapper = mapper(Person, person_table)

Columnがそのままアトリビュートになる

Page 9: Sql alchemy bpstyle_4

 

ぶっちゃけめんどくさい

Page 10: Sql alchemy bpstyle_4

宣言的マッピング

Base = declarative_base()

class Person(Base): __tablename__ = 'person' person_id = Column(Integer, primary_key=True) first_name = Column(Unicode(20)), last_name = Column(Unicode(20)), birthday = Column(Date))

クラスとスキーマを同時に定義

Page 11: Sql alchemy bpstyle_4

関連マッピング

class Employee(Base): __tablename__ = 'employee' id = Column(Integer, primary_key=True) ..... company_id = Column(Integer, ForeignKey('company.id'))

class Company(Base): __tablename__ = 'company' id = Column(Integer, primary_key=True) employees = relation(Employee, backref="company")

Page 12: Sql alchemy bpstyle_4

多対多

user_keyword_table = Table('user_keyword', meta, Column('user_id', ForeignKey('user.id')), Column('keyword_id', ForeignKey('keyword.id')))

class User(Base): id = Column(Integer, primary_key=True)

class Keyword(Base): id = Column(Integer, primary_key=True) users = relation(User, backref='keywords', secondary=user_keyword_table)

Page 13: Sql alchemy bpstyle_4

関連属性(1)

class User(Base): id = Column(Integer, primary_key=True) name = Column(String(255), unique=True)

class Keyword(Base): id = Column(Integer, primary_key=True) word = Column(String(255), unique=True)

Page 14: Sql alchemy bpstyle_4

関連属性(2)

class UserKeywords(Base): user_id = Column(Integer, ForeignKey('user.id')) keyword_id = Column(Integer, ForeignKey('keyword.id')) registered = Column(DateTime) kw= relation(Keyword, backref="users") us = relation(User, backref="keywords")

Page 15: Sql alchemy bpstyle_4

 

user = User()user.name = 'aodag'keyword = Keyword()keyword.word = 'python'

user_keyword = UserKeyword()user_keyword.registered = datetime.now()user_keyword.us = useruser_keyword.kw= keyword

Page 16: Sql alchemy bpstyle_4

 

user.kw[0].registereduser.kw[0].kw.wordword.us[0].user.name

2HOPするのがうざい

Page 17: Sql alchemy bpstyle_4

関連属性 AssociationProxy

class User(Base): id = Column(Integer, primary_key=True) name = Column(String(255), unique=True) keywords = association_proxy('kw', 'keyword')

class Keyword(Base): id = Column(Integer, primary_key=True) word = Column(String(255), unique=True) users= association_proxy('us', 'user')

Page 18: Sql alchemy bpstyle_4

 

user.kw[0].registereduser.keywords[0].wordkeyword.users[0].name

Page 19: Sql alchemy bpstyle_4

 

user.kw[0].keyword.word-> user.keyword[0].word

keyword.us[0].user.name-> keyword.users[0].name

Page 20: Sql alchemy bpstyle_4

継承

RDBの継承実装方法

結合テーブルスーパータイプのテーブルとサブタイプ固有のデータを持つテーブル

単一テーブルすべてのサブタイプのデータを含む1テーブル

完全テーブルサブタイプごとにすべてのデータを持つテーブル

Page 21: Sql alchemy bpstyle_4

継承(1) スーパークラスの設定

class Person(Base): ... typename = Column(String(20)) __mapper_args__ = {'polymorphic_on':'typename'}

タイプフラグのカラムを追加オプションで、カラムを指定

Page 22: Sql alchemy bpstyle_4

継承(2) 結合テーブルの場合

class Employee(Person): __tablename__ = 'employee' employee_id = Column(Integer, ForeignKey('person.person_id')) __mapper_args__ = {'polymorphic_identity':'employee'}

サブタイプはテーブルを持つスーパータイプのテーブルを参照する外部参照制約タイプフラグの値を指定

Page 23: Sql alchemy bpstyle_4

継承(2) 単一テーブル継承

class Employee(Person): __mapper_args__ = {'polymorphic_identity':'employee'}

サブタイプはテーブルを持たない

Page 24: Sql alchemy bpstyle_4

継承(3) 完全テーブル

class Employee(Person): __tablename__ = 'employee' person_id = Column(Integer, primary_key=True) first_name = Column(Unicode(20)), last_name = Column(Unicode(20)), birthday = Column(Date)) __mapper_args__ = {'concrete':True}

サブタイプはテーブルを持つオプションで完全に別テーブルとする指定スーパータイプにはタイプフラグが必要ないカラムを再度定義

Page 25: Sql alchemy bpstyle_4

Unit of work

データ処理をマーキングして管理一度にデータベースに反映

メモリ上でのトランザクション処理

Page 26: Sql alchemy bpstyle_4

SessionとDB接続

DB接続情報engine = create_engine('sqlite:///')

クラスファクトリSession = sessionmaker(bind=engine)

セッションオブジェクトsession = Session()

Page 27: Sql alchemy bpstyle_4

Session

p = Person(u'篤', u'小田切', datetime(1979, 8, 2))session.add(p)p = Person(u'John', u'Doe', datetime(1970, 1, 1))session.add(p)

session.commit()

新規オブジェクトは、セッションに追加する

Page 28: Sql alchemy bpstyle_4

Session

p = session.query(Person).filter_by(id=1)p.birthday = date.today()

session.commit()

p = session.query(Person).filter_by(id=1)p.delete()session.commit()

sessionから取り出したオブジェクトはそのまま。

Page 29: Sql alchemy bpstyle_4

scoped_session

スレッドローカルなモノステートオブジェクト

Session = scoped_session(sessionmaker(bind=engine))Session.query(...)

直接グローバルオブジェクトでメソッド呼び出しできる。同一スレッド内であれば、同一セッション。

内部状態のリセットはremoveメソッドで。Session.remove()

Page 30: Sql alchemy bpstyle_4

マルチDB

MasterSession = session_maker(bind=create_engine('mysql://db1/db')

SlaveSession =session_maker(bind=create_engine('sqlite://db2/db')

p = Person(...)s1 = MasterSession()s1.add()s1.commit()

s2 = SlaveSession()s2.query(Person).filter_by(id=1)

Page 31: Sql alchemy bpstyle_4

まとめ

恐ろしく柔軟今回紹介したのはSqlAlchemyができることの1/10くらいその他、コネクションプロキシ2フェーズコミット複数テーブルから1クラスにマッピング1テーブルから複数クラスにマッピングクエリからクラスにマッピング関連の実装クラスをdictやsetに変更アトリビュート単位での遅延ローディング垂直分割、水平分割(sharding)の対応などなど

Page 32: Sql alchemy bpstyle_4

 

足りないのはadminだけ!多分FormAlchemyで作れば、それほど問題ないかと。マイグレーションは、sqlalchemy-migrate