Successfully reported this slideshow.
Your SlideShare is downloading. ×

Sql alchemy bpstyle_4

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
Sqlalchemy  sqlの錬金術
Sqlalchemy sqlの錬金術
Loading in …3
×

Check these out next

1 of 32 Ad

More Related Content

Slideshows for you (20)

Advertisement

Similar to Sql alchemy bpstyle_4 (20)

More from Atsushi Odagiri (20)

Advertisement

Sql alchemy bpstyle_4

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

×