我已经有一个现有的数据库,在MySQL
中有很多表和大量数据。我打算创建一个Flask
应用程序并使用sqlalchemy。现在我问了irc并在google上四处寻找并尝试了以下想法:
首先我使用sqlacodegen从我的DB
生成模型。但后来我对此感到困惑,看了一下。我找到了this。
这看起来像是一个优雅的解决方案。
所以第二次,我根据那里的解决方案改写了我的models.py
,现在我更加困惑了。我正在寻找最好的方法来构建这个烧瓶应用程序以及现有的数据库。
我查看了烧瓶文档,但对于已有db的项目没有真正得到任何帮助。从头开始创建内容有很多好东西,创建数据库和所有内容。但我真的很困惑。
请注意,这是Flask
的第一天,但我有Django
的经验,所以基本概念不是障碍。我需要一些指导来为这个用例选择最佳方法。非常感谢详细解释。通过详细说明,我绝对不希望有人写下所有的代码和勺子喂我这个,但足以让我开始,这是通过flask
无缝地将这个数据库集成到sqlalchemy
。请注意我的数据库位于MySQL
。
答案 0 :(得分:83)
我说你的问题与烧瓶完全无关。例如,模板,路径,视图或登录装饰器没有问题。
你在哪里挣扎在SQLAlchemy。
所以我的建议是暂时忽略Flask并首先习惯SQLAlchemy。您需要习惯现有数据库以及如何从SQLAlchemy访问它。使用一些MySQL文档工具来找到解决方法。这样的开头(请注意,它与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数据库的路径,以便SQLAlchemy找到它。就我而言,我使用了一个预先存在的sqlite3数据库。
在“class Users(Base)
”行中,您需要使用MySQL数据库中的一个现有表。我知道我的sqlite3数据库有一个名为“users”的表。
在此之后,SQLalchemy知道如何连接到MySQL数据库,并且知道其中一个表。您现在需要添加您关心的所有其他表。最后,您需要指定与SQLalchemy的关系。在这里,我指的是像一对一,一对多,多对多,亲子等等。 SQLAlchemy网站包含一个相当冗长的部分。
在行“if __name__ == '__main__'
”后面出现了一些测试代码。如果我不导入我的python脚本,它将被执行,但运行。在这里,您可以看到我创建了一个数据库会话,这是一个非常简单的查询。
我的建议是您首先阅读SQLAlchemy文档的重要部分,例如描述性表定义,关系模型以及如何查询。一旦你知道了这一点,就可以将我的例子的最后一部分改成一个控制器(例如使用Python的yield
方法)并编写一个使用该控制器的视图。
答案 1 :(得分:46)
将Holger的答案与瓶子上下文联系起来的关键是db.Model
是一个declarative_base
对象,如Base
。我花了一段时间才注意到flask-sqlalchemy的documentation
以下是我用于我的应用的步骤:
以通常的烧瓶炼金术方式启动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 :(得分:18)
我最近经历了同样的事情,还有将模型链接到两个数据库的额外挑战。
我使用了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 / ___初始化___。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 /模型/ 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/
目录。
答案 3 :(得分:9)
我认为使用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
答案 4 :(得分:3)
我尝试使用自动生成但没有任何作用或我无法运行它。当我使用sqlacodegen搜索生成代码时,我找到https://github.com/ksindi/flask-sqlacodegen,您可以生成代码
flask-sqlacodegen mysql://username:password@host:port/db_name --schema yourschema --tables table1,table2 --flask
我试过,它完美无缺
答案 5 :(得分:1)
这是设置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)
答案 6 :(得分:1)
此解决方案适合我
"""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()
答案 7 :(得分:0)
答案 8 :(得分:0)
我建议使用动态类
from flask import Flask
from sqlalchemy import Table, MetaData
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
class Config(Object):
basedir = os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + + os.path.join(basedir, 'db.sqlite')
SQLALCHEMY_TRACK_MODIFICATIONS = False
app.config.from_object(config)
db = SQLAlchemy(app)
metadata = MetaData()
table_reflection = Table("table_name", metadata, autoload=True, autoload_with=db.engine)
attrs = {"__table__": table_reflection}
TableModel = type("table_name", (db.Model,), attrs)
现在,TableModel可以用作模型类
# Querying
TableModel.query.all()
TableModel.query.get(1)
TableModel.query.filter_by(id=2).first()
# insertion
new_row = TableModel()
db.session.add(new_row)
db.session.commit()
答案 9 :(得分:0)
如果您的应用程序很简单,则可以在模型文件上使用db.reflect(app)
:
def configure(app):
db.init_app(app)
db.reflect(app=app)
app.db = db