MySQL
に多くのテーブルと多くのデータを持つ既存のデータベースが既にあります。 Flask
アプリを作成し、sqlalchemyを一緒に使用する予定です。今、私はircに尋ねて、グーグルを見て回って、次のアイデアを試しました:
FirstDB
からモデルを生成するために sqlacodegen を使用しました。しかし、それから私はそれについて少し混乱し、もっと見ました。そして、私は this を見つけました。
これはエレガントなソリューションのように見えました。
だからSecond、私はmodels.py
そこの解決策によると、今ではさらに混乱しています。このflaskアプリと既存のDBを構築するための最良のアプローチを探しています。
flaskのドキュメントを調べましたが、既存のデータベースを使用したプロジェクトのヘルプはまったく得られませんでした。データベースを最初から作成したり、データベースを作成したりするのに役立つものがたくさんあります。しかし、私は本当に混乱しています。
Flask
での最初の日ですが、Django
での経験があるため、基本的な概念はハードルではありません。このユースケースに最適なアプローチを選択するには、いくつかのガイダンスが必要です。詳細な説明をいただければ幸いです。詳細には、誰かがすべてのコードを書いて、これをスプーンで送ってくれることは絶対に期待していませんが、始めるのに十分なのは、このデータベースをflask
を介してsqlalchemy
にシームレスに統合することです。 DBがMySQL
にあることに注意してください。
あなたの質問は、flaskとはまったく関係ありません。たとえば、テンプレート、ルート、ビュー、ログオンデコレータに問題はありません。
苦労するのはSQLAlchemyです。
だから私の提案はFlaskをしばらくの間無視し、最初にSQLAlchemyに慣れる。既存のデータベースに慣れる必要があり、SQLAlchemyからデータベースにアクセスする方法。このようなことから始めましょう(Flask ask all ... yetとは関係ないことに注意してください):
_#!/usr/bin/python
# -*- mode: python -*-
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///webmgmt.db', convert_unicode=True, echo=False)
Base = declarative_base()
Base.metadata.reflect(engine)
from sqlalchemy.orm import relationship, backref
class Users(Base):
__table__ = Base.metadata.tables['users']
if __== '__main__':
from sqlalchemy.orm import scoped_session, sessionmaker, Query
db_session = scoped_session(sessionmaker(bind=engine))
for item in db_session.query(Users.id, Users.name):
print item
_
「_engine =
_」行では、SQLAlchemyがそれを見つけられるように、MySQLデータベースへのパスを指定する必要があります。私の場合、既存のsqlite3データベースを使用しました。
「class Users(Base)
」行では、MySQLデータベースの既存のテーブルのいずれかを使用する必要があります。 sqlite3データベースに「users」という名前のテーブルがあることは知っていました。
この時点で、SQLalchemyはMySQLデータベースへの接続方法を認識し、テーブルの1つを認識します。ここで、必要な他のすべてのテーブルを追加する必要があります。最後に、SQLalchemyとの関係を指定する必要があります。ここでは、1対1、1対多、多対多、親子などを意味します。 SQLAlchemyのWebサイトには、これに関するかなり長いセクションが含まれています。
「_if __== '__main__'
_」行の後に、テストコードがいくつか続きます。 pythonスクリプトをインポートせずに実行します。ここで、DBセッションを作成し、非常に単純なクエリ用であることがわかります。
私の提案は、最初にSQLAlchemyのドキュメントの重要な部分、たとえば説明的なテーブル定義、関係モデル、クエリ方法について読むことです。これを知ったら、私の例の最後の部分をコントローラーに変更し(たとえば、Pythonのyield
メソッドを使用して)、そのコントローラーを使用するビューを記述できます。
Holgerの答えをflaskコンテキストに接続する鍵は、db.Model
がBase
のようなdeclarative_base
オブジェクトであることです。flask-sqlalchemy's ドキュメント
アプリに使用した手順は次のとおりです。
通常のフラスコ錬金術の方法でdb
オブジェクトを開始します:db = SQLAlchemy(app)
。その前にapp.config['SQLALCHEMY_DATABASE_URI'] = 'connection_string'
を設定する必要があることに注意してください。
宣言ベースをエンジンにバインドします:db.Model.metadata.reflect(db.engine)
次に、既存のテーブルを簡単に使用できます(たとえば、BUILDINGSというテーブルがあります)。
class Buildings(db.Model):
__table__ = db.Model.metadata.tables['BUILDING']
def __repr__(self):
return self.DISTRICT
これで、Buildings
クラスは既存のスキーマに従います。 Python Shellでdir(Buildings)
を試して、すでにリストされているすべての列を確認できます。
私は最近、同じことを経験しましたが、2つのデータベース間でモデルをリンクするという追加の課題がありました。
Flask-SQLAlchemy を使用し、データベーステーブルと同じ方法でモデルを定義するだけでした。私が難しいと思ったのは、プロジェクトの構造がどうあるべきかを正確に把握することでした。
私のプロジェクトはRestful APIでしたが、これが私がやったことです:
conf/
__init__.py
local.py
dev.py
stage.py
live.py
deploy/
#nginx, uwsgi config, etc
middleware/
authentication.py
app_name/
blueprints/
__init__.py
model_name.py #routes for model_name
...
models/
__init.py
model_name.py
__init__.py
database.py
tests/
unit/
test_etc.py
...
run.py
メモのファイル:
conf/xxx.py
これは、Flask-SQLAlchemyに接続先を指示する方法です。さらに、ここに他の設定項目(ログの場所、デバッグ設定など)を配置できます。
SQLALCHEMY_DATABASE_URI = 'mysql://username:password@Host:port/db_name'
app_name/__ init __。py
ここでアプリを作成し、データベースを初期化します。このdbオブジェクトはインポートされ、アプリ全体(モデル、テストなど)で使用されます。また、ロガーを設定し、APIと設計図を初期化し、ミドルウェアをここに添付します(図には示されていません)。
from app_name.database import db
from flask import Flask
def create_app(*args, **kwargs):
env = kwargs['env']
app = Flask(__name__)
app.config.from_object('conf.%s' % env)
db.init_app(app)
return app
app_name/database.py
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
app_name/models/model_name.py
from services.database import db
class Bar(db.Model):
__table= 'your_MySQL_table_name'
id = db.Column('YourMySQLColumnName', db.Integer, primary_key=True)
name = db.Column('WhateverName', db.String(100))
foo = db.Column(db.ForeignKey('another_MySQLTableName.id'))
class Foo(db.Model):
__table= 'another_MySQLTableName'
id = db.Column('FooId', db.Integer, primary_key=True)
...
run.py
#! /usr/bin/env python
from app_name import create_app
app = create_app(env='local')
if __== '__main__':
app.run()
run.py
を使用してアプリをローカルで実行しますが、nginx + uWSGIを使用してdev/stage/live環境でアプリを実行します。
ただし、これに加えてviews/
ディレクトリもあると思います。
Sqlalchemyで既存のデータベースを使用する最も簡単な方法は、 AutomapBase classを使用することだと思います。ドキュメントのサンプルコードは次のとおりです。
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine
Base = automap_base()
# engine, suppose it has two tables 'user' and 'address' set up
engine = create_engine("sqlite:///mydatabase.db")
# reflect the tables
Base.prepare(engine, reflect=True)
# mapped classes are now created with names by default
# matching that of the table name.
User = Base.classes.user
Address = Base.classes.address
session = Session(engine)
# rudimentary relationships are produced
session.add(Address(email_address="[email protected]", user=User(name="foo")))
session.commit()
# collection-based relationships are by default named
# "<classname>_collection"
print (u1.address_collection)
詳細およびより複雑な使用法については、 SqlAlchemy-Automap を参照してください
自動生成を使用しようとしましたが、何も機能しないか、実行できませんでした。 sqlacodegenを使用して生成コードを検索すると、 https://github.com/ksindi/flask-sqlacodegen が見つかり、コードを生成できます。
flask-sqlacodegen mysql://username:password@Host:port/db_name --schema yourschema --tables table1,table2 --flask
試しましたが、完全に機能します
このソリューションは私のために働いた
"""Example for reflecting database tables to ORM objects
This script creates classes for each table reflected
from the database.
Note: The class names are imported to the global namespace using
the same name as the tables. This is useful for quick utility scripts.
A better solution for production code would be to return a dict
of reflected ORM objects.
"""
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
def reflect_all_tables_to_declarative(uri):
"""Reflects all tables to declaratives
Given a valid engine URI and declarative_base base class
reflects all tables and imports them to the global namespace.
Returns a session object bound to the engine created.
"""
# create an unbound base our objects will inherit from
Base = declarative_base()
engine = create_engine(uri)
metadata = MetaData(bind=engine)
Base.metadata = metadata
g = globals()
metadata.reflect()
for tablename, tableobj in metadata.tables.items():
g[tablename] = type(str(tablename), (Base,), {'__table__' : tableobj })
print("Reflecting {0}".format(tablename))
Session = sessionmaker(bind=engine)
return Session()
# set to database credentials/Host
CONNECTION_URI = "postgres://..."
session = reflect_all_tables_to_declarative(CONNECTION_URI)
# do something with the session and the orm objects
results = session.query(some_table_name).all()
これは、Holgerの回答で説明されているエンジンパスを設定する代替方法です。ユーザー名またはパスワードに特殊文字が含まれていると便利です。
from sqlalchemy.engine.url import URL
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
engine_URL = URL('mssql+pymssql',
username='DOMAIN\\USERNAME',
password="""p@ssword'!""",
Host='Host.com',
database='database_name')
engine = create_engine(engine_URL)
Base = declarative_base()
Base.metadata.reflect(engine)
alembic(flask-sqlalchemyの背後にあるツール)は、テーブルを無視するように構成できます。構成のセットアップはそれほど難しくありません。参照: https://Gist.github.com/utek/616325