Good day everyone. I am new to Flask framework and currently trying to redo my Flask app to a proper project structure that I saw (online) since I want to integrate a Dash app later on. I am sorry if this is going to be very long. I don’t know how to explain it very shortly. Please bear with me.
The problem I am facing with using a proper project structure is that I don’t know how to call the “app” when initializing the database… It is always throwing an error “TypeError: cannot create weak reference to 'LocalProxy' object
” to this part of my code “db = SQLAlchemy(server)
” from models.py file. I also want to say that I named my “app” as “server” (the initialization of Flask “server = Flask(__name__, instance_relative_config=False)
“)
I want to start with what my project structure looks like:
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.)
These are my codes for “_init_.py”, “models.py”, “routes.py”, “config.py”, and “main.py”:
Code for “_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
Code for “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()
Code for “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)
Code for “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}"
Code for “main.py”:
from application import init_app
app = init_app()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5001, debug=True)
I just want to say that in my old project, this works – the one where all the code for the flask app is in just one python file (app.py). Here’s the code for it if it helps.
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)
These are things that I tried to fix the problem:
I’ve asked Gemini… Though, it didn’t work.
This is the solution that Gemini provided to me:
Solution 1:
The recommended approach is to move the db initialization to your _init_.py file. This ensures that the database gets initialized only once when the application starts. Here’s the updated _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
Solution 2:
If you prefer keeping db in models.py, you can avoid using current_app altogether. Instead, access the database URI from the Flask app configuration. Here’s the updated 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()
These are the error that I got:
Solution 1:
ImportError: cannot import name 'db' from 'flask'
since other than the current_app import from the routes.py and models.py, I also included the db like this: from flask import current_app as server, db
. I included the db so that the code from my routes.py and models.py will recognize the db…
This error points to my import code which includes the db.
Solution 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.
This error points to my code at models.py db.init_app(server)
Other things that I did:
Move the code from .models import Finance_Table
Finance_Table.init_db()
from main.py to _init_.py like this:
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
For the routes.py, I just added the db to import… from .models import Finance_Table, db
.
Finally, in the models.py, is where the init_db function is, like the second solution provided by 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()
and this is the error that I got: TypeError: cannot create weak reference to 'LocalProxy' object
pointing at this code from models.py db.init_app(server)
Sorry again that this is too long.
Kitayori is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.