Reputation: 1969
I've been following the flask tutorial to add a database, in their example they're using mysqlite while I'm using MySQL but I figured that shouldn't make a huge difference here. https://flask.palletsprojects.com/en/1.1.x/tutorial/database/
Here's the mysql library I'm trying to use https://flask-mysql.readthedocs.io/en/stable/
However whatever I do I can't seem to get away from this assertion 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.
The error only happens when trying to use the /dbtest path.
Here's my minimal __init__.py
import os
from flask import Flask, render_template
from . import db
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
MYSQL_DATABASE_HOST='mysql-svc',
MYSQL_DATABASE_USER='root',
MYSQL_DATABASE_PASSWORD='root',
DEBUG=True,
TESTING=True
)
db.init_app(app)
# a simple page that says hello
@app.route('/hello')
def hello():
return 'Hello, World!'
@app.route('/dbtest')
def db_test():
with app.app_context():
cursor = db.get_cursor()
cursor.execute('SHOW DATABASES')
return cursor.fetchall()
return app
And here is db.py which is in the same directory
from flaskext.mysql import MySQL
from flask import current_app, g
def get_cursor():
if 'db_cursor' not in g:
mysql = MySQL()
mysql.init_app(current_app)
g.db_cursor = mysql.get_db().cursor()
return g.db_cursor
def close_db(e=None):
db = g.pop('db_cursor', None)
if db is not None:
db.close()
def init_app(app):
app.teardown_appcontext(close_db)
Everything I've read about this error seems to indicate that I'm somehow messing around with routing after I've tried to access the database or something? But I'm just following the tutorial for how the routing is set up. I'm probably missing something obvious here, I believe it's an issue with mysql.init_app
now but I still can't figure out how to do this.
Upvotes: 4
Views: 8761
Reputation: 169
Just encountered the same issue and found this interesting article here. It's about to use plain SQLAlchemy and to avoid Flask-SQLAlchemy. Instead of initializing the connection with
db=SQLAlchemy(app)
(which causes the issue in question) I followed the article and did it like this:
class Query:
def __init__(self):
SQLALCHEMY_DATABASE_URI = 'sqlite:///db/mydb.db'
engine = create_engine(SQLALCHEMY_DATABASE_URI, connect_args={'check_same_thread': False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
self.session = SessionLocal()
Base = automap_base()
Base.prepare(engine, reflect=True)
self.Node = Base.classes.mytable
def getTop20(self):
nodes = self.session.query(self.Node).order_by(desc(self.Node.date_modified)).limit(20)
return nodes
Upvotes: 1
Reputation: 118
The issue may be related if DEBUG = True
, just ran into this myself came here looking for a solution. The closed github ticket below has a comment indicating that it was an issue at some point. As of today it still appears to be an issue.
https://github.com/ga4gh/ga4gh-server/issues/791
Upvotes: 9
Reputation: 1969
In the end I had to say screw it to the whole g
thing with getting the cursor, same goes for closing the db with a teardown. In the end it works with just this in my db.py:
from flaskext.mysql import MySQL
def init_db_connection(app):
mysql = MySQL()
mysql.init_app(app)
return mysql.get_db().cursor()
Which I call once from my __init__.py before I do any routing, this gets me the db cursor. Then I just freely use that variable within the routing.
I'm not sure how well this will scale up, and frankly I think the flask tutorials are rather poor as the mechanics behind g
, app initialisation, routing, current_app
and the rest are poorly explained. But what I've got works for now at least. I hope someone else can provide a better answer to this question.
Upvotes: 1