def get_db(self,dbfile):
if hasattr(g, 'sqlite_db'): self.close_db(g.sqlite_db)
try:
g.sqlite_db = self.connect_db('{}/{}'.format(app.root_path, dbfile))
except sqlite3.OperationalError as e:
raise e
return g.sqlite_db
Hi this code is located inside DB class, The error I get is
RuntimeError: working outside of application context
the error occurs on this line
g.sqlite_db = self.connect_db('{}/{}'.format(app.root_path, dbfile))
I think the problem is with g, it is imported like that from flask import g
How this error can be fixed?
Thanks.
Maybe you need to call your function inside an application context:
with app.app_context():
# call your method here
When creating your app, use:
app.app_context().push()
for example like this:
from yourapp import create_app
app = create_app()
app.app_context().push()
for further information
From the Flask source code in flask/globals.py:
_app_ctx_err_msg = '''\
Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.\
'''
Following the documentation, you can see that you need to make flask.current_app point to your application and it currently doesn't.
You're probably calling your DB function before Flask has initialized. My guess is that your app object has not been created yet with the Flask constructor.
Two possible solution
First method
Instead of calling create_all() in your code, call manually in the flask shell which is CLI
Go to your terminal
type flask shell, then
db.create_all()
Second method
As it says in the runtime error message
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().
Open the python terminal in your project directory and manually add a context
from project_name import app, db
app.app_context().push()
db.create_all()
Check out this video for better understanding.
YouTube Video
Simple Example To Avoid This Error
Please check out the Purpose of context
#filename = run.py (inside root directory)
from flaskblog import create_app
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
Inside flaskblog folder
filename = __init __.py (inside flaskblog folder)
app = Flask(__name__)
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = "users.login"
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
from flaskblog.user.routes import users
app.register_blueprint(users)
return app
filename = config.py (inside flaskblog folder)
class Config:
SECRET_KEY = 'your secret key'
SQLALCHEMY_DATABASE_URI = 'your db uri'
filename = models.py
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
users folder (inside flaskblog)
users folder contain one __init__.py file
Filename = form.py (inside users folder)
class LoginForm(FlaskForm):
# define your field
pass
Filename = routes.py (inside users folder)
users = Blueprint('users',__name__)
#users.route('/login', methods=['GET', 'POST'])
def login():
# do your stuff
pass
Other users have pointed out how to solve the immediate problem, however you might consider modifying how the database connection is created to solve this issue.
Instead of having a method within you DB class instantiate the database connection you could have the connection created in the controller before every request. Then use the teardown_request decorator to close the connection.
Then when within a route you could pass the connection to the DB class as part of instantiating a new DB object.
This would ensure that you never create a database connection unless you need one. And it prevent you from accessing Flask globals out of the app context.
#app.before_request
def before_request():
try:
g.sqlite_db = self.connect_db('{}/{}'.format(app.root_path, dbfile))
except sqlite3.OperationalError as e:
raise e
#app.teardown_request
def teardown_request(e):
if hasattr(g, 'sqlite_db'): self.close_db(g.sqlite_db)
#app.route('/someroute', methods=["GET"]:
def someroute():
db_obj = DB(g.sqlite_db)
.
.
.
Use
pip install flask-sqlalchemy==2.5.1
This might solve the error
To expand on #VadimK's answer. If you want to prevent your code from executing outside of an app_context you can use flask.has_app_context() to see if the code is currently inside an app context:
See also: flask.has_request_context()
This is what fixed it for me. I hope it helps someone else.
if __name__ == "__main__":
with app.app_context():
db.create_all()
app.run(debug=True)
I had the same issue while doing some unit testing.
Adding the following function to my test class solved my issue:
#classmethod
def setUpClass(self):
self.app = create_app("testing")
self.client = self.app.test_client()
When initializing the app I use this block instead :
def create_app():
app = Flask(__name__)
with app.app_context():
init_db()
return app
when creating an app just add the below code.
app = Flask(__name__)
app.app_context().push()
Install this version of flask using
pip install flask-sqlalchemy==2.5.1
then run db.create_all() and it will run.
ERROR:This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.
Related
def get_db(self,dbfile):
if hasattr(g, 'sqlite_db'): self.close_db(g.sqlite_db)
try:
g.sqlite_db = self.connect_db('{}/{}'.format(app.root_path, dbfile))
except sqlite3.OperationalError as e:
raise e
return g.sqlite_db
Hi this code is located inside DB class, The error I get is
RuntimeError: working outside of application context
the error occurs on this line
g.sqlite_db = self.connect_db('{}/{}'.format(app.root_path, dbfile))
I think the problem is with g, it is imported like that from flask import g
How this error can be fixed?
Thanks.
Maybe you need to call your function inside an application context:
with app.app_context():
# call your method here
When creating your app, use:
app.app_context().push()
for example like this:
from yourapp import create_app
app = create_app()
app.app_context().push()
for further information
From the Flask source code in flask/globals.py:
_app_ctx_err_msg = '''\
Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.\
'''
Following the documentation, you can see that you need to make flask.current_app point to your application and it currently doesn't.
You're probably calling your DB function before Flask has initialized. My guess is that your app object has not been created yet with the Flask constructor.
Two possible solution
First method
Instead of calling create_all() in your code, call manually in the flask shell which is CLI
Go to your terminal
type flask shell, then
db.create_all()
Second method
As it says in the runtime error message
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().
Open the python terminal in your project directory and manually add a context
from project_name import app, db
app.app_context().push()
db.create_all()
Check out this video for better understanding.
YouTube Video
Simple Example To Avoid This Error
Please check out the Purpose of context
#filename = run.py (inside root directory)
from flaskblog import create_app
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
Inside flaskblog folder
filename = __init __.py (inside flaskblog folder)
app = Flask(__name__)
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = "users.login"
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
from flaskblog.user.routes import users
app.register_blueprint(users)
return app
filename = config.py (inside flaskblog folder)
class Config:
SECRET_KEY = 'your secret key'
SQLALCHEMY_DATABASE_URI = 'your db uri'
filename = models.py
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
users folder (inside flaskblog)
users folder contain one __init__.py file
Filename = form.py (inside users folder)
class LoginForm(FlaskForm):
# define your field
pass
Filename = routes.py (inside users folder)
users = Blueprint('users',__name__)
#users.route('/login', methods=['GET', 'POST'])
def login():
# do your stuff
pass
Other users have pointed out how to solve the immediate problem, however you might consider modifying how the database connection is created to solve this issue.
Instead of having a method within you DB class instantiate the database connection you could have the connection created in the controller before every request. Then use the teardown_request decorator to close the connection.
Then when within a route you could pass the connection to the DB class as part of instantiating a new DB object.
This would ensure that you never create a database connection unless you need one. And it prevent you from accessing Flask globals out of the app context.
#app.before_request
def before_request():
try:
g.sqlite_db = self.connect_db('{}/{}'.format(app.root_path, dbfile))
except sqlite3.OperationalError as e:
raise e
#app.teardown_request
def teardown_request(e):
if hasattr(g, 'sqlite_db'): self.close_db(g.sqlite_db)
#app.route('/someroute', methods=["GET"]:
def someroute():
db_obj = DB(g.sqlite_db)
.
.
.
Use
pip install flask-sqlalchemy==2.5.1
This might solve the error
To expand on #VadimK's answer. If you want to prevent your code from executing outside of an app_context you can use flask.has_app_context() to see if the code is currently inside an app context:
See also: flask.has_request_context()
This is what fixed it for me. I hope it helps someone else.
if __name__ == "__main__":
with app.app_context():
db.create_all()
app.run(debug=True)
I had the same issue while doing some unit testing.
Adding the following function to my test class solved my issue:
#classmethod
def setUpClass(self):
self.app = create_app("testing")
self.client = self.app.test_client()
When initializing the app I use this block instead :
def create_app():
app = Flask(__name__)
with app.app_context():
init_db()
return app
when creating an app just add the below code.
app = Flask(__name__)
app.app_context().push()
Install this version of flask using
pip install flask-sqlalchemy==2.5.1
then run db.create_all() and it will run.
ERROR:This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.
The intent: Refactor my code into MVC (this is just the model/database part), and have the server create the database with tables on first run if the database or tables does not exist.
This works when using a "flat" file with all the classes and functions defined in that file, but after moving out the functions into a service class and the models into their own folder with model classes, the db.create_all() function does not seem to be able to detect the table class correctly any more.
Example structure, (minimum viable problem):
server.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
def main():
# Intentionally moved into the main() function to prevent import loops
from services.users import UserService
users = UserService(db)
db.create_all()
app.run(debug=True)
if __name__ == '__main__':
main()
services\users.py
# Class used to access users data using a session
from models.users import Users
class UserService:
def __init__(self, db):
self.db = db
def get_all(self):
return self.db.session.query(Users).all()
def get(self, uid):
return self.db.session.query(Users).get(uid)
def add(self, json):
user = Users(email=json['email'], password=json['password'])
self.db.session.add(user)
self.db.session.commit()
return user
models\users.py
# The actual model
from server import db
class Users(db.Model):
_id = db.Column("id", db.Integer, primary_key=True)
email = db.Column(db.Text)
password = db.Column(db.Text)
Result: The database is created, but it is just an empty file with no tables inside of it.
I have also tried placing the db.create_all() inside the service class def __init__(self, db) (grasping at straws here), both as a self reference and as an argument reference. Neither have worked.
I am sure it is something obvious I am missing, but I have boiled down my project to just the bare minimum and still fail to see why it is not working - so I have to ask. How can I get the db.create_all() to detect my table classes correctly and actually create the required tables, while using this code structure (or something similar, in case I have misunderstood MVC)?
The problem is that server.py is executed twice
when it's imported in models/users.py
when server.py is called to run the app
Each execution generates a new db instance. The db imported by the model file adds the models to its metadata, the db created when the app is run has empty metadata.
You can confirm this by printing id(db) and db.metadata.tables at the end of models/users.py and just before the call to db.create_all() in the main function.
You need to structure your code so that only one db gets created. For example, you could move the app configuration and creation code into its own module, mkapp.py (feel free to come up with a better name):
mkapp.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
And in server.py do
from mkapp import app, db
and in models/users.py do
from mkapp import db
As a bonus, this should also remove the import cycle.
I don't use flask much, so this solution can probably be improved on. For example, having a function create app and db and memoise the results might be better than creating them in top-level module code.
Ok, i'm a bit new to Flask, so I'm not sure if i should be using Flask Script or Flask's built-in CLI took but I'm going with the latter for now.
However, I'm facing the problem that others have faced when it comes to bootstrapping the app context before running a command and having current_app context and whatnot.
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.cli.add_command(seed_db)
return app
#click.command
#with_appcontext
def seed_db():
# Register SqlAlchemy
from .models import db, User, Role
db.init_app(app)
# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
# Some initial models (if they don't exist)
user_datastore.find_or_create_role(name='admin', description='Administrator')
user_datastore.find_or_create_role(name='end-user', description='End user')
return app
So in this case I have a factory method initializing the app. And then I have my custom command that I want to run to seed the database.
I've already been able to run flask db migrate to set up my initial tables, but if I try to run flask seed_db, I get something like this:
File "/usr/local/lib/python3.6/site-packages/click/core.py", line
1150, in add_command
name = name or cmd.name AttributeError: 'function' object has no attribute 'name'
Can someone enlighten me on how to properly bootstrap the app with commands outside the create_app method?
There is an error when you are using #click.command
I think the error message gives you a clear clue that you forget to give a name to your command.
You need to init a name to the command like this #click.command("seed_db") or just default function name like this #click.command()
#click.command("seed_db")
#with_appcontext
def seed_db():
# Register SqlAlchemy
from .models import db, User, Role
db.init_app(app)
Hope it helps.
These two lines are in the wrong place:
app.cli.add_command(seed_db)
return app
Your seed_db() function is adding itself to the app, which is a bit confusing - then returning the app. I think you meant for these two actions to occur your app factory method:
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.cli.add_command(seed_db)
return app
Your app factory is the function with the responsibility of setting up the app object and returning it, no other function should be trying to do this.
I'm trying to run an existing app in a new environment. The app ran fine in a previous environment, but when I run it locally it refuses to connect with my DB.
AssertionError: The sqlalchemy extension was not registered to the current application. Please make sure to call init_app() first.
Where I'm confused is that this exact code worked in a previous environment. It's asking me to call init_app() but, from my understanding, that's only if there are multiple apps, which there aren't.
In debugging mode, the app does recognize the object i.e.
>>> type(Candidate)
<class 'flask_sqlalchemy.model.DefaultMeta'>
I am unclear how and where to incorporate app_init() into my code. I have tried...
db = SQLAlchemy(app)
db.init_app(app)
but this didn't have any impact.
Folder structure...
app
- static folder
- templates folder
- _init_.py
- config.py
- views.py
- run.py
- Procfile
You could try following code and structure in init.py
db = SQLAlchemy()
def create_app():
app = Flask()
db.init_app(app)
from user_model import User
with app.app_context():
db.create_all()
The problem was that there was legacy code that was supposed to be removed. I was initializing an app twice by accident.
Instead of creating init.py, why don't you import db directly from models
The code below shows my models.py with table students
from flask import Flask,session
from flask_sqlalchemy import SQLAlchemy
#initialize this two objects below app and db parameters so that app.py will have the same db session.
#then in app.py add from models import db
#finally add db.init_app(app) at the bottom of app.py or run.py
app = Flask(__name__)
db = SQLAlchemy(app)
class Students(db.Model):
id = db.Column('student_id', db.Integer, primary_key = True)
name = db.Column(db.String(50))
email = db.Column(db.String(50))
def __repr__(self):
return '<Student {}>'.format(self.email)
Then in your app.py or run.py
You will have to make an import for db
from models import db
Your assertion error for sql-alchemy can be mitigate by moving the two following line of code
immediately after this line of code towards the bottom
if __name__ == '__main__':
hence the code will become like below and your application will run without issue
if __name__ == '__main__':
#create table
db.create_all()
db.init_app(app)
# remember to turn app debug by setting it to false in production
app.run(debug=True)
I have a simple single file app to test using SQLAlchemy with Flask. The getResult view uses the MainResult model. However, navigating to /getResult raise NameError: global name 'MainResult' is not defined. That class is defined in the same file as the view, so why do I get that error?
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:#localhost/testDB'
db = SQLAlchemy(app)
#app.route('/getResult')
def getResult():
newEntry = MainResult(metadata_key='test')
db.session.add(newEntry)
db.session.commit()
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
class MainResult(db.Model):
metadata_key = db.Column(db.String(128), primary_key=True)
Python executes files sequentially. app.run runs forever. So anything after app.run in the file will not have been executed and won't be until the server stops. MainResult isn't defined until after the app is run, so the view can't see it. Move it above the __main__ block.
class MainResult(db.Model):
...
# should be the last thing in the file
if __name__ == '__main__':
app.run()
Preferably, use the new flask command to run the dev server instead. The __main__ block is no longer required in this case.
FLASK_APP=my_file.py flask run