I am building a Flask application which connects to an existing MySQL database as an exercise to learn Flask. I am encountering an error when trying to connect to the database, from a database object which is instantiated from a blueprint.
My Project structure is as follows
project
├─── instance
├─── config.py
├─── application
├─── _src
├─── db.py
├─── extensions.py
├─── admin
├─── templates
├─── __init__.py
├─── views.py
├─── static
__init__.py
My __init__.py (in the applications directory) has the following code:
from flask import Flask
# Config file
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile("config.py")
# Blueprints
from application.admin.views import adminBlueprint
# Register the blueprint
app.register_blueprint(adminBlueprint)
My Config file has the following:
#####################
# Database details ##
#####################
DB_USERNAME = "username"
DB_PASSWORD = "password"
DB_DATABASE_NAME = "databasename"
DB_HOST = "localhost"
The views file, in my admin folder has the following:
# Imports
from flask import render_template, Blueprint
from .._src.db import DB
from .._src import admin as admin
# Config
adminBlueprint = Blueprint("admin", __name__, template_folder="templates")
# Routes
@adminBlueprint.route("/admin")
def admin():
# Connect to the database
db = DB()
cursor, conn = db.connectDB()
# Get the required data
projects = admin.getProjects(cursor, "all")
# Close the database connection
db.close()
# Render data to the template
return render_template("admin.html", projects=projects)
My extensions file, in the _src folder, which is used to allow access to the MySQL object from the blueprint, has the following code:
from flaskext.mysql import MySQL
mysql = MySQL()
And my db file in the _src directory has the following:
from flask import current_app
from .._src.extensions import mysql
class DB:
def __init__(self):
# Something will be done here in the future
pass
def connectDB(self):
# Provide the database connection details
current_app.config['MYSQL_DATABASE_USER'] = current_app.config["DB_USERNAME"]
current_app.config['MYSQL_DATABASE_PASSWORD'] = current_app.config["DB_PASSWORD"]
current_app.config['MYSQL_DATABASE_DB'] = current_app.config["DB_DATABASE_NAME"]
current_app.config['MYSQL_DATABASE_HOST'] = current_app.config["DB_HOST"]
mysql.init_app(current_app)
# Connect to the database
try:
self.conn = mysql.connect()
cursor = self.conn.cursor()
# Return the cursor object
return cursor, self.conn
except:
return False
def close(self):
self.conn.close()
I'm getting the following error:
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late. To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
And the debugger is pointing to this file in the db file:
mysql.init_app(current_app)
I'm a little out of my depth and I don't really understand what the problem is. Can I only initialize the MySQL object from the same place that I initialize the Flask app? If so, how can I then access the MySQL object from the blueprint?
Any help is appreciated.
I was able to fix this by putting my app instantiation into my extensions file instead of my init file:
extensions.py
from flask import Flask
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile("config.py")
Then, in my database connection object, I can import the current app to get the settings:
from flask import current_app
from .._src.extensions import mysql
I also removed this line, as I am now achieving this in my extensions file:
mysql.init_app(current_app)