web-dev-qa-db-ja.com

sqlalchemy既存のデータベースクエリ

pythonプロジェクトのORMとしてSQLAlchemyを使用しています。いくつかのモデル/スキーマを作成しましたが、正常に動作しています。今、既存のMySQLデータベースにクエリを実行する必要があります。選択のみを挿入/更新する必要はありません。ステートメント。

この既存のデータベースのテーブルの周りにラッパーを作成するにはどうすればよいですか?私は簡単にsqlalchemyドキュメントとSOを調べましたが、関連するものを見つけることができませんでした。SQLAlchemyクエリを使用しながら、生のSQLクエリを記述する必要があるすべてのexecuteメソッドを提案しますSAモデルで使用しているのと同じ方法です。

たとえば、既存のdbのテーブル名がUserの場合、dbsessionを使用してクエリを実行します(選択操作のみ、おそらく結合を使用)

20
DevC

SQLAlchemyはSQLAlchemy(おそらくMetaData.create_all()を使用)によって作成されたデータベース構造でのみ機能するという印象を持っているようです-これは正しくありません。 SQLAlchemyは既存のデータベースで完全に機能します。データベーステーブルに一致するようにモデルを定義するだけです。そのための1つの方法は、IljaEveriläが示唆するように、リフレクションを使用することです。

class MyClass(Base):
    __table__ = Table('mytable', Base.metadata,
                    autoload=True, autoload_with=some_engine)

(私の意見では、1回限りのスクリプトではまったく問題ありませんが、データベースの構造が時間とともに変化する可能性がある場合、「実際の」アプリケーションで信じられないほどイライラするバグにつながる可能性があります)

別の方法は、データベーステーブルと一致するようにモデルを定義するように注意しながら、通常どおりにモデルを定義することです。これはそれほど難しくありません。このアプローチの利点は、データベーステーブルのサブセットのみをモデルにマップでき、テーブル列のサブセットのみをモデルのフィールドにマップできることです。データベースに10個のテーブルがあるが、usersid、およびnameフィールドのみが必要なemailテーブルのみに関心があるとします。

class User(Base):
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String)
    email = sa.Column(sa.String)

(文字列フィールドの長さやemailフィールドにインデックスがあるという事実など、正しいDDLを出力するためだけに必要な詳細を定義する必要がなかったことに注意してください)

コードでモデルを作成または変更しない限り、SQLAlchemyはINSERT/UPDATEクエリを発行しません。クエリが読み取り専用であることを確認したい場合は、データベースに特別なユーザーを作成し、そのユーザーにSELECT権限のみを付与します。あるいは/さらに、アプリケーションコードでトランザクションをロールバックすることもできます。

10
Sergey

いくつかのサンプルコードで:

from sqlalchemy.sql import select
from sqlalchemy import create_engine, MetaData, Table

CONN_STR = '…'
engine = create_engine(CONN_STR, echo=True)
metadata = MetaData()
cookies = Table('cookies', metadata, autoload=True,
                           autoload_with=engine)
cols = cookies.c


with engine.connect() as conn:

    query = (
        select([cols.created_at, cols.name])
                .order_by(cols.created_at)
                .limit(1)
    )
    for row in conn.execute(query):
        print(row)
5
Gringo Suave

automap extension を使用して、既存のテーブルにアクセスできます。

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session

Base = automap_base()
Base.prepare(engine, reflect=True)

Users = Base.classes.users
session = Session(engine)

res = session.query(Users).first()
5
Rani

他の回答では、主キーのないテーブルがある場合の対処方法については触れられていないため、これに対処しようと思いました。 CustomerId、CustomerName、CustomerLocationの列を持つCustomersという名前のテーブルがあるとします。

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine, MetaData, Column, String, Table
from sqlalchemy.orm import Session

Base = automap_base()

conn_str = '...'    
engine = create_engine(conn_str)
metadata = MetaData()
# you only need to define which column is the primary key. It can automap the rest of the columns.
customers = Table('Customers',metadata, Column('CustomerId', String, primary_key=true), autoload=True, autoload_with=engine)
Base.prepare()
Customers= Base.classes.Customers

session = Session(engine)

customer1 = session.query(Customers).first()
print(customer1.CustomerName)
0
ehambright