Sql alchemy bpstyle_4
-
Upload
atsushi-odagiri -
Category
Documents
-
view
127 -
download
8
description
Transcript of Sql alchemy bpstyle_4
![Page 1: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/1.jpg)
SQLAlchemyBPStyle #4小田切 aodag 篤
![Page 2: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/2.jpg)
アクティブレコードとデータマッパーSQLAlchemyデータマッピング宣言的な方法関連継承Session
![Page 3: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/3.jpg)
アクティブレコードとデータマッパー
アクティブレコードクラスとテーブルを1対1に割り当てるマッピング(オブジェクトと行が対応する)簡単融通は利かない多対多関連ではマッピングされないテーブルが存在する
データマッパークラスに対するテーブルマッピングを指定する柔軟性が高いちょっと面倒多対多関連で関連属性もマッピング可能
![Page 4: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/4.jpg)
SQLAlchemy
データマッパータイプのORマッパーSQLをPythonオブジェクトで構築Unit of workパターン
![Page 5: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/5.jpg)
対応データベース
SQLiteMySQLPostgreSQLFirebirdOracleSQL ServerDB2
など
![Page 6: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/6.jpg)
データマッピング(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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/7.jpg)
データマッピング(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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/8.jpg)
データマッピング(3) マッピング
person_mapper = mapper(Person, person_table)
Columnがそのままアトリビュートになる
![Page 9: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/9.jpg)
ぶっちゃけめんどくさい
![Page 10: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/10.jpg)
宣言的マッピング
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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/11.jpg)
関連マッピング
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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/12.jpg)
多対多
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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/13.jpg)
関連属性(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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/14.jpg)
関連属性(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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/15.jpg)
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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/16.jpg)
user.kw[0].registereduser.kw[0].kw.wordword.us[0].user.name
2HOPするのがうざい
![Page 17: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/17.jpg)
関連属性 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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/18.jpg)
user.kw[0].registereduser.keywords[0].wordkeyword.users[0].name
![Page 19: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/19.jpg)
user.kw[0].keyword.word-> user.keyword[0].word
keyword.us[0].user.name-> keyword.users[0].name
![Page 20: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/20.jpg)
継承
RDBの継承実装方法
結合テーブルスーパータイプのテーブルとサブタイプ固有のデータを持つテーブル
単一テーブルすべてのサブタイプのデータを含む1テーブル
完全テーブルサブタイプごとにすべてのデータを持つテーブル
![Page 21: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/21.jpg)
継承(1) スーパークラスの設定
class Person(Base): ... typename = Column(String(20)) __mapper_args__ = {'polymorphic_on':'typename'}
タイプフラグのカラムを追加オプションで、カラムを指定
![Page 22: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/22.jpg)
継承(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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/23.jpg)
継承(2) 単一テーブル継承
class Employee(Person): __mapper_args__ = {'polymorphic_identity':'employee'}
サブタイプはテーブルを持たない
![Page 24: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/24.jpg)
継承(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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/25.jpg)
Unit of work
データ処理をマーキングして管理一度にデータベースに反映
メモリ上でのトランザクション処理
![Page 26: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/26.jpg)
SessionとDB接続
DB接続情報engine = create_engine('sqlite:///')
クラスファクトリSession = sessionmaker(bind=engine)
セッションオブジェクトsession = Session()
![Page 27: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/27.jpg)
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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/28.jpg)
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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/29.jpg)
scoped_session
スレッドローカルなモノステートオブジェクト
Session = scoped_session(sessionmaker(bind=engine))Session.query(...)
直接グローバルオブジェクトでメソッド呼び出しできる。同一スレッド内であれば、同一セッション。
内部状態のリセットはremoveメソッドで。Session.remove()
![Page 30: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/30.jpg)
マルチ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](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/31.jpg)
まとめ
恐ろしく柔軟今回紹介したのはSqlAlchemyができることの1/10くらいその他、コネクションプロキシ2フェーズコミット複数テーブルから1クラスにマッピング1テーブルから複数クラスにマッピングクエリからクラスにマッピング関連の実装クラスをdictやsetに変更アトリビュート単位での遅延ローディング垂直分割、水平分割(sharding)の対応などなど
![Page 32: Sql alchemy bpstyle_4](https://reader031.fdocuments.net/reader031/viewer/2022020115/54c5d57b4a7959254f8b457a/html5/thumbnails/32.jpg)
足りないのはadminだけ!多分FormAlchemyで作れば、それほど問題ないかと。マイグレーションは、sqlalchemy-migrate