It seems common practice in Flask to start like this:
from flask import Flask from flaskext.sqlalchemy import SQLAlchemy app = Flask(__name__) SQLALCHEMY_DATABASE_URI = 'something' app.config.from_object(__name__) db = SQLAlchemy(app)
And then import and use app
and db
everywhere. But when you create db
like this, it grabs configuration from the app, and it seems that this configuration can't ever be overridden once it happens. There are some pages on Flask's website about making application factories, but it's not clear how I would be able to still use app
and db
everywhere if I did that.
How do I write a script to test my Flask application with a different database? How should I structure my application to make this possible? Do I have to use module
s ?
If an application has automated tests, you can safely make changes and instantly know if anything breaks. Flask provides a way to test your application by exposing the Werkzeug test Client and handling the context locals for you.
Step 1 - Install the Flask-SQLAlchemy extension. Step 2 - You need to import the SQLAlchemy class from this module. Step 3 - Now create a Flask application object and set the URI for the database to use. Step 4 - then use the application object as a parameter to create an object of class SQLAlchemy.
Running of Unit Tests One thing to keep in mind is to use the top-level folder of the flask application. We might need to import app, db like objects and hence would need to specify a location that is easily discoverable, and python interpreter can locate it easily.
Your instinct to use environment variables is correct. However, there is some danger of running unit tests with the wrong db. Also, you may not want to connect_db
with every request and everywhere you want to use db
. You can use a config directory and environment variables which you set explicitly. This is the best I've come up with so far.
run.py shell.py config/__init__.py config/test.py config/postgres.py ... main/__init__.py main/someapp/__init__.py main/someapp/models.py ... main/tests/__init__.py main/tests/testutils.py
so, the config files may be:
# config/test.py SQLALCHEMY_DATABASE_URI = "sqlite://"
and
# config/postgres.py SQLALCHEMY_DATABASE_URI = 'postgresql://user:pw@localhost/somedb'
So, I can explicitly set the db in my base TestCase:
import os from flask.ext.testing import TestCase os.environ["DIAG_CONFIG_MODULE"] = "config.test" from main import app, db class SQLAlchemyTest(TestCase): def create_app(self): return app def setUp(self): db.create_all() def tearDown(self): db.session.remove() db.drop_all()
Then, the main/__init__.py
, for me:
import os from flask import Flask, render_template, g from flask.ext.sqlalchemy import SQLAlchemy # by default, let's use a DB we don't care about # but, we can override if we want config_obj = os.environ.get("DIAG_CONFIG_MODULE", "config.test") app = Flask(__name__) app.config.from_object(config_obj) db = SQLAlchemy(app) @app.before_request def before_request(): g.db = db g.app = app # ... @app.route('/', methods=['GET']) def get(): return render_template('home.html') # ... from main.someapp.api import mod as someappmod app.register_blueprint(someappmod)
Then, in the other files, where I know what config I want to run, potentially:
# run.py import os os.environ["DIAG_CONFIG_MODULE"] = "config.postgres" from main import app app.run(debug=True)
and
# shell.py import os os.environ["DIAG_CONFIG_MODULE"] = "config.postgres" from main import app, db from main.symdiag.models import * from main.auth.models import * print sorted(k for k in locals().keys() if not k.startswith("_")) import IPython IPython.embed()
Maybe .. best so far :P.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With