Flask-SQLAlchemy import/context issue
The flask_sqlalchemy
module does not have to be initialized with the app right away - you can do this instead:
# apps.members.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Member(db.Model):
# fields here
pass
And then in your application setup you can call init_app
:
# apps.application.py
from flask import Flask
from apps.members.models import db
app = Flask(__name__)
# later on
db.init_app(app)
This way you can avoid cyclical imports.
This pattern does not necessitate the you place all of your models in one file. Simply import the db
variable into each of your model modules.
Example
# apps.shared.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# apps.members.models
from apps.shared.models import db
class Member(db.Model):
# TODO: Implement this.
pass
# apps.reporting.members
from flask import render_template
from apps.members.models import Member
def report_on_members():
# TODO: Actually use arguments
members = Member.filter(1==1).all()
return render_template("report.html", members=members)
# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members
reporting = Blueprint("reporting", __name__)
reporting.route("/member-report", methods=["GET","POST"])(report_on_members)
# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting
app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)
Note: this is a sketch of some of the power this gives you - there is obviously quite a bit more that you can do to make development even easier (using a create_app
pattern, auto-registering blueprints in certain folders, etc.)
Basic Flask SQLAlchemy Context Issue
Perhaps you could try the following:
app.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
import models
from models import initialize_db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
initialize_db(app)
@app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def initialize_db(app):
app.app_context().push()
db.init_app(app)
db.create_all()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
The key is creating a database initialization function within models.py
which takes the application instance as a parameter. This function only creates the database tables once it has its application instance. This will allow you to import the models module initially without an application instance and still have a modular design.
Flask, push application context for Flask-sqlalchemy to huey worker
It is better if you let Huey create a Flask app for its use. Organize your code as follows:
Add a second method that creates a Flask app for the specific use by Huey, similar to create_app
#__init__.py
from flask import Flask
from app.config import db, Config, huey
from app.tasks import my_task
def create_app():
# ...
return app
def create_huey_app():
app = Flask('HUEY APP')
app.config.from_object(Config)
# only initialize stuff here that is needed by Huey, eg DB connection
db.init_app(app)
# register any blueprints needed
# e.g. maybe it needs a blueprint to work with urls in email generation
return app
Make all your tasks have a first parameter that is a callable:
#tasks.py
from app.config import huey
from app.models import User
# every task takes an app_factory parameter
@huey.task()
def background_task(app_factory):
app = app_factory()
with app.app_context():
User.query.get(1)
return 1
Then pass create_huey_app
as the callable to each task instantiation:
#view.py
from flask import Blueprint
from app.tasks import my_task
main = Blueprint("main", __name__)
@main.route("/")
def index():
# pass the Huey app factory to the task
background_task(create_huey_app) # running the registered background task
return "hello view"
If you want to run the task locally when debugging:
@main.route("/")
def index():
# pass the Huey app factory to the task
if current_app.debug:
background_task.call_local(create_huey_app) # running the task directly
else:
background_task(create_huey_app) # running the task in Huey
return "hello view"
Flask app context for sqlalchemy
You're running a background task in a different thread that doesn't have the application context. You should pass the app object to the background worker. Miguel Grinberg gives an example of this here:
from threading import Thread
from app import app
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
Alternatively (and probably the best solution) would be to actually set up a thread-local scoped SQLAlchemy session instead of relying on Flask-SQLAlchemy's request context.
>>> from sqlalchemy.orm import scoped_session
>>> from sqlalchemy.orm import sessionmaker
>>> session_factory = sessionmaker(bind=some_engine)
>>> Session = scoped_session(session_factory)
Related Topics
Python 2.X - Write Binary Output to Stdout
How to Call an External Program in Python and Retrieve the Output and Return Code
Setting Django Up to Use MySQL
Scikit-Learn Dbscan Memory Usage
How to Strip Decorators from a Function in Python
Python Datetime Formatting Without Zero-Padding
Removing Elements from a List Containing Specific Characters
Receive and Send Emails in Python
How to Write Tests for the Argparse Portion of a Python Module
Why Doesn't Exec Work in a Function with a Subfunction
Saving the State of a Program to Allow It to Be Resumed
What Is the Most Compatible Way to Install Python Modules on a MAC
Use a Library Locally Instead of Installing It
Working with Tiffs (Import, Export) in Python Using Numpy
Attributeerror: Module 'Cv2.Cv2' Has No Attribute 'Createlbphfacerecognizer'