大家好。我是 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'
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.
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
db.init_app(server)
再次抱歉,这太长了。
我已经修复了它。不过,我不知道这是否是最佳实践。
更改位于 __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”方法。感谢您的阅读~~