ORM:SQLAlchemy初認識

8393 ワード

ORM: Object Relational Mapper.
現在、PythonにはデータベースをPythonのObjectsオブジェクトにイメージできるORMツールがたくさんあります.中でも有名なのはDjangoのORM、SQLAlchemy、PostgreSQLなどです.SQLAlchemyより多くの人がメンテナンスしており、機能もそろっています.だから一般的には私たちのプリファレンスです.SQLAlchemyの利用者にとって、最初にデータベースに接続すれば、Sqlite、MySQL、何でも、後の処理方法はまったく同じです.この利便性も人気の理由です.
伝統的な自分でSQL文を編んだり、モデルを作ったり、データベースに接続したりする方法を捨てて、SQLAlchemyは直接これらのものをブラックボックスに包んで、私たちにまったく管理する必要がありません.SQL-Injection注入というものまで防いでくれました.これにより,データベースへの接続において,少なくとも半分以上のコードを節約できるといえる.
データクエリでさえSQLAlchemyはSQL文の代わりに、MongoDBのようなObject.query.filter_by(name='Jason').all()のような専門的な方法を使用しています.
インストール:
#   sqlalchemy
$ pip install sqlalchemy

Driversのインストール:
# Sqlite
#    ,Python  

# MySQL
$ pip install pymysql

# Postgresql
$ pip install psycopg2

SQLAlchemy自身はデータベースdriverを持たず、自分でインストールし、接続時に指定する必要があります.これらのdriverは、実際にはデータベースに手動で接続するために使用されたパッケージです.SQLAlchemyは私たちの代わりにこれらの同じパッケージを使用しているだけです.
データベースの接続
sqliteのORMエンジンを作成します.
from sqlalchemy import create_engine

#      :sqlite:///
engine  = create_engine('sqlite:///foo.db', echo=True)

MySQLのORMエンジンを作成します.
from sqlalchemy import create_engine

#      :dialect+driver://username:password@host:port/database
engine  = create_engine('mysql+pymysql://root:password123@localhost/db_test_01', echo=True)

データベースの場所:
#             (////), /tmp/mydatabase.db
engine  = create_engine('sqlite:////tmp/mydatabase.db')

#     「    」     (/// ///./)
engine  = create_engine('sqlite:///mydatabase.db')

#     「    」    (///../)      
engine  = create_engine('sqlite:///../mydatabase.db')

#     「    」      
import os
cwd = os.path.split(os.path.realpath(__file__))[0]
engine  = create_engine('sqlite:///{}/mydatabase.db'.format(cwd))

Create Tableテーブルの作成
注意:SQL文とは異なり、SQLAlchemyのテーブル名は
大文字と小文字を完全に区別!
Schemaテーブルを作成します(単純なテーブルで、ORMオブジェクトは含まれません):
from sqlalchemy import create_engine, MetaData
from sqlalchemy import Table, Column
from sqlalchemy import Integer, String, ForeignKey

engine  = create_engine('mysql+pymysql://root:password123@localhost/db_test_01', echo=True)
metadata = MetaData(engine)

#      
user_table = Table( 'tb_user', metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(50)),
        Column('fullname', String(100))
)

#      
metadata.create_all()

テーブルを含むORMオブジェクトを作成します.
#         
from sqlalchemy import create_engine
#      
from sqlalchemy import Column, Integer, String, ForeignKey
#     ORM    
from sqlalchemy.ext.declarative import declarative_base

Base  = declarative_base()

class User(Base):
    __tablename__ = 'tb_Person'

    id = Column('id', Integer, primary_key=True)
    username = Column('username', String, unique=True)

engine = create_engine('sqlite:///test.sqlite', echo=True)
Base.metadata.create_all(bind=engine)

通常テーブルTableとORMオブジェクトで作成されたテーブルの違いは何ですか?彼らがデータベースで作成したのは、まったく同じテーブルです.唯一の違いは、Tableが作成したORMオブジェクトを含まないこと、つまりPythonオブジェクトを直接操作する機能を提供しないことです.このような利点は,関連作用のみのテーブルが多く,ORMオブジェクトを生成する必要がないことである.
データベース内のテーブルの削除
# engine = ...
# Base = ...

#   ORM        , User 
User.__table__.drop(engine)

#      
Base.metadata.drop_all(engine)

設計やデバッグの過程で、テーブルを頻繁に変更することが多いので、テーブルを作成する前にテストデータベースのテーブルを消去してから、新しい定義を作成する必要があります.
Insertion挿入データ
データベースにデータを追加するには、次の手順に従います.
# ...
#   session  (      )
from sqlalchemy.orm import sessionmaker, relationship

user = User()
user.id = 1
user.username = 'Jason'

Session = sessionmaker(bind=engine)
session = Session()
session.add(user)
session.commit()
session.close()

注意:ここのsessionとウェブサイトのsessionの概念は少し違います.ここではcommitがデータベースの変動をコミットするためのツールです.
一括追加データ(add_all()への入力リスト):
session.add_all( [user1, user2, user3] )

各データを追加するときに自動flush():
session = sessionmaker(bind=engine, autoflush=True)
autoflushは、session.add()のたびにsession.flush()が自動的に実行される.すなわち、データベースを挿入する前に、プライマリ・キーIDなどのすべてのオブジェクトの動的データがメモリに生成される.一般的にデフォルトはfalseを選択します.効率に影響を与えるからです.session.flush()を手動で実行するには、必要な場合が望ましい.
具体的な理由は、次のセクション「データの有効化」を参照してください.
Take effectデータの有効化
SQLAlchemyのcreate_all()session.commit()は、pythonファイルで定義されたオブジェクトをデータベースで直接有効にする文です.これまでは、どのように定義しても、データベースではなくメモリにデータが格納されていました.
注意:
  • create_allは、insertに関係なくテーブル構造の作成を有効にするだけです.
  • session.commit()は、追加されたデータを有効にするだけで、テーブル構造を担当しません.

  • この2つの順序は、もちろんテーブルを作成してからデータを挿入します.
    ただ,この原理を知れば,符号化において自由に運用できる.たとえば、create_engine()でエンジンを作成する場合でも、ファイルヘッダ、すなわちすべてのORM定義の前に書く必要はありません.create_engineは、すべてのORMクラスおよびSchemaテーブルの後に定義すればよい.
    その後,データ挿入作業を再開し,sessionを利用した.
    セッション中は、プライマリ・キーの外部キーIDを相互に参照する場合もあります.ただし、この場合、最終的なsession.commit()を使用してデータベースにデータを送信していないため、これらのIDには値がありません.解決策は内蔵の方法session.flush()を利用して、sessionに追加されたすべてのオブジェクトをデータに埋め込むことですが、この時点でデータベースに提出されていません.ただ、私たちの内部では正常に各種IDにアクセスすることができます.
    データの更新/削除
    更新:
    # Get a row of data
    me = session.query(User).filter_by(username='Jason').first()
    
    # Method 1:
    me.age += 1
    session.commit()
    
    # Method 2:
    session.query().filter(
        User.username == 'Jason'
    ).update(
        {"age": (User.age +1)}
    )
    session.commit()
    
    # Method 3:
    setattr(user, 'age', user.age+1)
    session.commit()

    Get Primary Key Valueプライマリ・キー値の取得#sqlalchemy can't get primary key , #sqlalchemy
    この問題は私に多くの時間を費やして照会を探求して、その解を得られなくて、やっともとは明らかなことであることを理解しました.
    参考:SQLAlchemyで新しく挿入したデータのidを返しますか?
    セッションやengineでデータを挿入する前に、ORMから作成したオブジェクトのプロパティ値を直接参照できます.しかし、このときはどうしてもprimar_keyのプライマリ・キー列の値が得られない.
    このときプライマリ・キーはまだデータベースに挿入されていないため、 として、データベースが有効にならない前にNoneとなります.
    なぜvalue of primary_keyを取得する必要がありますか?次のようなシナリオを考慮します.
  • サブテーブルのforeign key外部キーは、プライマリテーブルのid
  • を参照する必要がある.
  • ??

  • では、プライマリ・キーIDはどのように取得すればいいのでしょうか.
    Stackoverflow:sqlalchemy flush()and get inserted id?再参照:sqlalchemy挿入されたidを取得再参照:Sqlalchemy;プライマリ・キーを事前に存在するデータベース・テーブルに設定します(sqliteは使用しません).
    データを挿入する前に、プライマリ・キーなどの の値を取得するには、次の方法があります.
  • SQLAlchemyを直接利用してクラスの直接的な内部関連を確立し、ID
  • を直接使用しない
  • プライマリテーブルにデータを挿入し、別のセッションが有効になった後、queryで対応するオブジェクトを取得してIDを取得します.
  • (*)プライマリテーブルは、まずsession.add(..)、さらにsession.flush()を使用し、その後IDを取得することができ、最後にsession.commit()
  • を使用する.
  • primaryキーを使用せずに、自分でIDを手動で作成し、勝手に取得します.

  • 推奨方法は次のとおりです.
    すなわち、オブジェクトを新しく作成するたびに、すぐにsession.add(..),そしてすぐにflush()は、すべての文末を追加して、セッションします.commit().
    Queryクエリー
    注意:queryはセッションによって行われます.つまり、session.commit()以降にクエリーを行わなければなりません.そうしないと、エラーが発生します.
    ここで示すqueryクエリは、すべて .これを理解することは重要です.オブジェクトがデータベースに挿入される前に、多くのプライマリ・キー、外部キーなどのコンテンツが存在せず、クエリーできないためです.
    参照:pythonsheets-Object Relational basic query
    クエリーデータ:
    session.commit()
    # ...
    
    users = session.query(User).all()
    #       User    :>>> [ , , .... ]
    
    for u in users:
        print(u.id, u.username)

    一般的なクエリー方法:
    #    ORM    .query(ORM  )
    >>> session.query( User ).all()     # All rows of data
    >>> session.query( User ).first()    # First row of data as an object
    
    #        .order_by(  .  )
    >>> session.query(User).order_by( User.birth ).all()
    
    #      .filter( True/False     )
    >>> session.query(User).filter( User.name != 'Jason' ).all()
    >>> session.query(User).filter( User.name.like('%ed%') ).all()    # Fuzzy search
    >>> session.query(User).filter( User.id in [1, 2, 3] ).all()    # IN
    >>> session.query(User).filter( ~ User.id in [4, 5, 6] ).all()   # NOT IN
    >>> session.query(User).filter( User.school == 'MIT', User.age < 24 ).first()   # AND
    >>> session.query(User).filter( _or(User.school == 'MIT', User.age < 24) ).first()   # OR