Flask-SQLAlchemy:如何正确调用“app”来初始化SQLAlchemy数据库对象?

问题描述 投票:0回答:1

大家好。我是 Flask 框架的新手,目前正在尝试将我的 Flask 应用程序重做为我看到的(在线)正确的项目结构,因为我想稍后集成 Dash 应用程序。如果这会很长,我很抱歉。我不知道如何简短地解释它。请多多包涵。

我在使用正确的项目结构时面临的问题是

我不知道在初始化数据库时如何调用“应用程序”...它总是抛出错误“TypeError: cannot create weak reference to 'LocalProxy' object

到这部分我的代码db = SQLAlchemy(server)
来自 models.py 文件。我还想说我将我的“应用程序”命名为“服务器”(Flask 的初始化“server = Flask(__name__, instance_relative_config=False)
”)

我想从我的项目结构开始:

Proper Flask app (Parent folder) l - Application (Folder) l l l l - dashboard (Folder) l l l - dashboard.py l l l l - static (Folder) l l l - assets (Folder) l l l - css (Folder) l l l l - styles.css l l l - db (Folder) l l l l - (This is where the db file will be created and resides.) l l l - schema (Folder) l l l - templates (Folder) l l l l - __init__.py (Initialization code of the Flask app.) l l - models.py (This is where the code "class Finance_Table(db.Model)" resides.) l l - routes.py (This is where the code for the routes resides.) l l - utilities.py (This is where the other functions that I will need resides.) l l l - backups (Folder) l - config.py (This is where the configuration settings for the flask resides) l - main.py (This will run the __init__.py and start the Flask app.)
这些是我的“_

init_.py”、“models.py”、“routes.py”、“config.py”和“main.py”的代码:

“_init_.py”代码:

from flask import Flask def init_app():     server = Flask(__name__, instance_relative_config=False)     server.config.from_object("config.Config")         with server.app_context():         # Import core parts of Flask app:         from . import routes                 # Import Dash Application: Example:         # from .dashboard.dashboard import init_dashboard         # server = init_dashboard(server)         """         For this one, I am still unsure if its "server = " or         "app = "... Will know once I am doing this for real.         """                 return server

“models.py”代码:

from flask import current_app as server from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy(server) class Finance_Table(db.Model):     transact_id = db.Column(db.Integer, primary_key=True)     transact_type = db.Column(db.String(10), nullable=False)     transact_sub_type = db.Column(db.String(100), nullable=False)     transact_date = db.Column(db.DateTime)     money = db.Column(db.Numeric, nullable=False)     note = db.Column(db.String(200), nullable=True)         def __repr__(self) -> str:         return f"<Current {self.transact_id}"         with server.app_context():         db.create_all()

“routes.py”代码:

"""Routes for parent Flask app""" from flask import render_template, redirect, request from flask import current_app as server from datetime import datetime from .models import Finance_Table, db @server.route("/", methods=["POST", "GET"]) def index():     if request.method == "POST":         main_type = request.form["main_type"]         if main_type == "Income":             sub_type = request.form["income_sub_type"]         elif main_type == "Expense":             sub_type = request.form["expense_sub_type"]         else:             print(main_type)         transact_amount = request.form["amount"]         transact_note = request.form["note"]                         try:             select_date_str = request.form["select_date"]             select_date = datetime.strptime(select_date_str, "%Y-%m-%d")         except Exception as e:             print(f"Invalid date format. Please use YYYY-MM-DD.\nError: {type(e).__name__}")                 new_transact = Finance_Table(transact_type=main_type,                                      transact_sub_type=sub_type,                                      transact_date=select_date,                                      money=transact_amount,                                      note=transact_note) # type: ignore                 try:             db.session.add(new_transact)             db.session.commit()         except Exception as e:             print(f"There was an issue adding your transaction. Error: {type(e).__name__}")         finally:             db.session.close()             return redirect("/")             else:         transact = Finance_Table.query.order_by(Finance_Table.transact_date).all()         return render_template("index.html", transact=transact)

“config.py”代码:

"""Flask configs.""" from os import environ, path BASE_DIR = path.abspath(path.dirname(__file__)) db_path = path.join(BASE_DIR, "application", "static", "db", "finance.db") class Config:     """Flask configuration variables:"""         # General config:     ENVIRONMENT = environ.get("ENVIRONMENT")     FLASK_APP = "main.py"     FLASK_DEBUG = environ.get("FLASK_DEBUG")     SECRET_KEY = environ.get("SECRET_KEY")         # Static assets:     STATIC_FOLDER = "static"     TEMPLATES_FOLDER = "templates"     SQLALCHEMY_DATABASE_URI = f"sqlite:///{db_path}"

“main.py”代码:

from application import init_app app = init_app() if __name__ == "__main__":     app.run(host="0.0.0.0", port=5001, debug=True)

我只想说,在我的旧项目中,这是可行的 - Flask 应用程序的所有代码都位于一个 python 文件(app.py)中。如果有帮助的话,这是它的代码。

from util.utilities import path_generator from flask import Flask, render_template, redirect, request from flask_sqlalchemy import SQLAlchemy from datetime import datetime _, db_path, _, _, _ = path_generator() app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}" db = SQLAlchemy(app) class Finance_Table(db.Model): transact_id = db.Column(db.Integer, primary_key=True) transact_type = db.Column(db.String(10), nullable=False) transact_sub_type = db.Column(db.String(100), nullable=False) transact_date = db.Column(db.DateTime) money = db.Column(db.Numeric, nullable=False) note = db.Column(db.String(200), nullable=True) def __repr__(self) -> str: return f"<Current {self.transact_id}" with app.app_context(): # table creation if not exists. db.create_all() @app.route("/", methods=["POST", "GET"]) def index(): if request.method == "POST": main_type = request.form["main_type"] if main_type == "Income": sub_type = request.form["income_sub_type"] elif main_type == "Expense": sub_type = request.form["expense_sub_type"] else: print(main_type) transact_amount = request.form["amount"] transact_note = request.form["note"] try: select_date_str = request.form["select_date"] select_date = datetime.strptime(select_date_str, "%Y-%m-%d") except Exception as e: print(f"Invalid date format. Please use YYYY-MM-DD.\nError: {type(e).__name__}") new_transact = Finance_Table(transact_type=main_type, transact_sub_type=sub_type, transact_date=select_date, money=transact_amount, note=transact_note) # type: ignore try: db.session.add(new_transact) db.session.commit() except Exception as e: print(f"There was an issue adding your transaction. Error: {type(e).__name__}") finally: db.session.close() return redirect("/") else: transact = Finance_Table.query.order_by(Finance_Table.transact_date).all() return render_template("index.html", transact=transact) if __name__ == "__main__": app.run(debug=True)

这些是我尝试解决问题的方法:

我问过双子座...不过,没有成功。 这是Gemini给我提供的解决方案:

解决方案1:

推荐的方法是将数据库初始化移动到 _

init_.py 文件中。这可确保数据库仅在应用程序启动时初始化一次。这是更新后的_init_.py:

from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() def init_app(): server = Flask(__name__, instance_relative_config=False) server.config.from_object("config.Config") db.init_app(server) # Initialize db with the Flask app instance with server.app_context(): # Import core parts of Flask app: from . import routes # ... (other imports) return server

解决方案2:

如果您更喜欢将数据库保留在 models.py 中,则可以完全避免使用 current_app。相反,从 Flask 应用程序配置访问数据库 URI。这是更新后的 models.py:

from flask import current_app from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Finance_Table(db.Model): # ... (your model definition) @classmethod def init_db(cls): db.init_app(current_app) with current_app.app_context(): db.create_all() # Create tables if they don't exist # Call init_db from another module (e.g., main.py): from models import Finance_Table Finance_Table.init_db()

这些是我得到的错误:

解决方案1

ImportError: cannot import name 'db' from 'flask'

因为除了从routes.py和models.py导入current_app之外,我还包含了这样的数据库:from flask import current_app as server, db
。我包含了数据库,以便我的 paths.py 和 models.py 中的代码能够识别该数据库...

此错误指向我的导入代码,其中包括数据库。

解决方案2:

RuntimeError: Working outside of application context.


This typically means that you attempted to use functionality that needed the current application. To solve this, set up an application context with app.app_context(). See the documentation for more information.


这个错误指向我的 models.py 代码

db.init_app(server)


我做过的其他事情:

将代码

from .models import Finance_Table

 
Finance_Table.init_db()
 从 main.py 移至 _
init_.py,如下所示:

def init_app(): server = Flask(__name__, instance_relative_config=False) server.config.from_object("config.Config") with server.app_context(): # Import core parts of Flask app: from .models import Finance_Table Finance_Table.init_db() from . import routes return server
对于routes.py,我刚刚添加了要导入的数据库...

from .models import Finance_Table, db

最后,在models.py中,就是init_db函数所在的地方,就像Gemini提供的第二种解决方案一样。

from flask import current_app as server from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Finance_Table(db.Model): transact_id = db.Column(db.Integer, primary_key=True) transact_type = db.Column(db.String(10), nullable=False) transact_sub_type = db.Column(db.String(100), nullable=False) transact_date = db.Column(db.DateTime) money = db.Column(db.Numeric, nullable=False) note = db.Column(db.String(200), nullable=True) def __repr__(self) -> str: return f"<Current {self.transact_id}" @classmethod def init_db(cls): db.init_app(server) with server.app_context(): db.create_all()
这是我得到的错误:

TypeError: cannot create weak reference to 'LocalProxy' object

指向 models.py 中的代码db.init_app(server)

再次抱歉,这太长了。

python sqlite flask flask-sqlalchemy
1个回答
0
投票

我已经修复了它。不过,我不知道这是否是最佳实践。

更改位于 __init__.py、routes.py 和 models.py 中。

对于__init__.py,像Gemini的解决方案1一样,我在那里添加了数据库实例:

from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # db instance here. def init_app(): server = Flask(__name__, instance_relative_config=False) server.config.from_object("config.Config") db.init_app(server) with server.app_context(): # Import core parts of Flask app: from .models import Finance_Table # Import the Finance_Table class here. Finance_Table.init_db() # Then call the method that creates the table if not exists. from . import routes return server

对于routes.py,我刚刚添加了这个导入:

from . import db

并修复了从烧瓶中的导入:

from flask import current_app as server

最后,在 models.py 中,我还添加了从routes.py 添加的导入,并修复了从flask 的导入。在类中,我添加了方法“init_db(cls)”,如下所示:

from flask import current_app as server from application import db class Finance_Table(db.Model): transact_id = db.Column(db.Integer, primary_key=True) transact_type = db.Column(db.String(10), nullable=False) transact_sub_type = db.Column(db.String(100), nullable=False) transact_date = db.Column(db.DateTime) money = db.Column(db.Numeric, nullable=False) note = db.Column(db.String(200), nullable=True) def __repr__(self) -> str: return f"<Current {self.transact_id}" @classmethod def init_db(cls): # Call this method in __init__.py. after the server.app_context() db.create_all()
最后调用__init__.py中的“init_db”方法。

感谢您的阅读~~

© www.soinside.com 2019 - 2024. All rights reserved.