如何围绕已经存在的数据库构build瓶颈应用程序?

我已经有一个现有的数据库,在MySQL中有很多的表和大量的数据。 我打算创build一个Flask应用程序并使用sqlalchemy。 现在我问了一下irc,在google上四处看了一下,并尝试了下面的想法:

首先,我使用sqlacodegen从我的DB生成模型。 但是当时我对此有些困惑,而且看上去更多一些。 我发现这一点 。

这看起来像一个优雅的解决scheme

第二 ,我根据那里的解决scheme重写了我的models.py ,现在我更加困惑了。 我正在寻找与现有的数据库一起构build这个应用程序的最佳方法。

我看了烧瓶文件,但没有真正得到任何帮助已经存在的数据库的项目。 有很多好东西从头开始创build一些东西,创build数据库和所有。 但是我很困惑。

请注意,这是我第一次使用Flask ,但是我有Django经验,所以基本的概念并不是一个障碍。 我需要一些指导,为这个用例select最好的方法。 详细的解释将不胜感激。 通过详细我绝对不会指望有人写所有的代码和勺子喂我,但只是让我开始,这是通过sqlalchemy将这个数据库无缝地集成到flask 。 注意我的数据库是在MySQL

我会说你的问题与烧瓶无关。 例如,您对模板,路线,视图或login装饰器没有问题。

你在哪里挣扎在SQLAlchemy。

所以我的build议是忽略Flask一段时间,先习惯SQLAlchemy。 您需要习惯现有的数据库以及如何从SQLAlchemy访问它。 使用一些MySQL文档工具来find解决这个问题的方法。 一开始就是这样的(注意它和Flask没有任何关系,请问所有…):

 #!/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 __name__ == '__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 = ”行中,您需要提供到MySQL数据库的path,以便SQLAlchemyfind它。 在我的情况下,我使用了一个预先存在的sqlite3数据库。

在“ class Users(Base) ”这一行中,您需要使用MySQL数据库中的一个现有表。 我知道我的sqlite3数据库有一个名为“用户”的表。

在这之后,SQLalchemy知道如何连接到你的MySQL数据库,并知道其中的一个表。 您现在需要添加所有您关心的其他表格。 最后,您需要指定与SQLalchemy的关系。 在这里,我的意思是一对一,一对多,多对多,母公司等等。 SQLAlchemy网站包含一个相当长的部分。

在“ if __name__ == '__main__' ”行if __name__ == '__main__'一些testing代码。 它将被执行,如果我不导入我的python脚本,但运行。 在这里你看到,我创build了一个数据库会话,这是一个非常简单的查询。

我的build议是,首先阅读SQLAlchemy文档的重要部分,例如描述性表定义,关系模型以及如何查询。 一旦你知道这一点,你可以改变我的例子的最后一部分到控制器(例如使用Python的yield方法),并写一个使用该控制器的视图。

将Holger的答案连接到瓶子上下文的关键是db.Model是一个像Base这样的declarative_base对象。 花了一段时间在flask-sqlalchemy的文档中注意到这个重要的句子

以下是我用于我的应用程序的步骤:

  1. 以通常的烧瓶炼金术方式启动一个db对象: db = SQLAlchemy(app) 。 注意你需要在这之前设置app.config['SQLALCHEMY_DATABASE_URI'] = 'connection_string'

  2. 将声明基础绑定到引擎: db.Model.metadata.reflect(db.engine)

  3. 那么你可以很容易地使用现有的表(例如,我有一个名为BUILDINGS的表):

     class Buildings(db.Model): __table__ = db.Model.metadata.tables['BUILDING'] def __repr__(self): return self.DISTRICT 

现在你的Buildings类将遵循现有的模式。 您可以尝试Pythonshell中的dir(Buildings) ,并查看已经列出的所有列。

我最近经历了同样的事情,还有跨两个数据库链接模型的额外挑战。

我使用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要连接什么,再加上你可以在这里放置任何其他的configuration项(比如日志位置,debuggingconfiguration等)。

 SQLALCHEMY_DATABASE_URI = 'mysql://username:password@host:port/db_name' 

APP_NAME / ___ init___.py

这是我创build我的应用程序并初始化分贝。 这个数据库对象将被导入并用于整个应用程序(即在模型,testing等)。 我也设置我的logging器,初始化我的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 /模型/ model_name.py

 from services.database import db class Bar(db.Model): __tablename__ = '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): __tablename__ = '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 __name__ == '__main__': app.run() 

我使用run.py在本地运行应用程序,但是我使用nginx + uWSGI在dev / stage / live环境中运行应用程序。

我猜你会有除此之外的views/目录。

我认为用sqlalchemy使用现有数据库最简单的方法是使用AutomapBase类。 来自docs的示例代码如下所示:

 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="foo@bar.com", user=User(name="foo"))) session.commit() # collection-based relationships are by default named # "<classname>_collection" print (u1.address_collection) 

有关详细信息和更复杂的用法,请参阅SqlAlchemy-Automap

我尝试使用自动生成,但没有任何工作,或者我无法运行它。 当我使用sqlacodegensearch生成代码时,我发现https://github.com/ksindi/flask-sqlacodegen ,你可以生成代码

 flask-sqlacodegen mysql://username:password@host:port/db_name --schema yourschema --tables table1,table2 --flask 

我尝试过,它完美的作品

这是设置Holger的答案中描述的发动机path的另一种方法。 方便,如果您的用户名或密码中有特殊字符。

 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) 

这个解决scheme为我工作

 """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() 

alembic(flask-sqlalchemy后面的工具)可以configuration为忽略表。 configuration不是很难设置。 请参阅: https : //gist.github.com/utek/6163250