I am currently following this pattern to avoid circular imports. This pattern seems to be pretty niche so it's been difficult trying to find a solution googling.
models.py
from sqlalchemy.orm import relationship
db = SQLAlchemy()
class Choice(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(32))
votes = relationship("Vote")
def __init__(self, text):
self.text = text
application.py
app = Flask(__name__)
app.debug = True
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite3')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app) # Reinitialiez db.Model to avoid cyclical imports in models.py
db_create.py
#!flask/bin/python
from application import app, db
from models import Choice
db.init_app(app)
db.create_all()
db.session.add(Choice("Red"))
db.session.add(Choice("Blue"))
db.session.add(Choice("Green"))
db.session.commit()
When I run db_create.py separately, I get:
$ python db_create.py
Traceback (most recent call last):
File "db_create.py", line 6, in <module>
db.create_all()
File "/home/ubuntu/.virtualenvs/paw-py/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 972, in create_all
self._execute_for_all_tables(app, bind, 'create_all')
File "/home/ubuntu/.virtualenvs/paw-py/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 949, in _execute_for_all_tables
app = self.get_app(app)
File "/home/ubuntu/.virtualenvs/paw-py/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 922, in get_app
raise RuntimeError('application not registered on db '
RuntimeError: application not registered on db instance and no application bound to current context
What should I do? What is the best pattern to deal with this? I've even tried adding db.create_all() in my application.py after if __name__ == '__main__' but I am still getting the same error
Tell Flask-SQLAlchemy which is "current" app with app_context
with app.app_context():
# your code here
db.create_all()
Related
I recently updated Flask-SQLAlchemy, and now db.create_all is raising RuntimeError: working outside of application context. How do I call create_all?
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///project.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
db.create_all()
This raises the following error:
Traceback (most recent call last):
File "/home/david/Projects/flask-sqlalchemy/example.py", line 11, in <module>
db.create_all()
File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 751, in create_all
self._call_for_binds(bind_key, "create_all")
File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 722, in _call_for_binds
engine = self.engines[key]
File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 583, in engines
app = current_app._get_current_object() # type: ignore[attr-defined]
File "/home/david/Projects/flask-sqlalchemy/.venv/lib/python3.10/site-packages/werkzeug/local.py", line 513, in _get_current_object
raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.
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(). See the documentation for more information.
As of Flask-SQLAlchemy 3.0, all access to db.engine (and db.session) requires an active Flask application context. db.create_all uses db.engine, so it requires an app context.
with app.app_context():
db.create_all()
When Flask handles requests or runs CLI commands, a context is automatically pushed. You only need to push one manually outside of those situations, such as while setting up the app.
Instead of calling create_all in your code, you can also call it manually in the shell. Use flask shell to start a Python shell that already has an app context and the db object imported.
$ flask shell
>>> db.create_all()
Or push a context manually if using a plain python shell.
$ python
>>> from project import app, db
>>> app.app_context().push()
>>> db.create_all()
Here's an example.py that configures a SQLite database, a model, then creates the database. The with app.app_context() line around db.create_all() is what's needed to avoid the context error.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
db = SQLAlchemy()
class Article(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.String)
with app.app_context():
db.create_all()
Run the development server with this command, and the database will be created if it doesn't exist.
$ flask -A example.py --debug run
If you're using a python shell instead of flask shell, you can push a context manually. flask shell will handle that for you.
>>> from project import app, db
>>> app.app_context().push()
>>> db.create_all()
Learn more about the application context in the Flask docs or this video.
I'm a beginner of flask,when i tried to run app.py on the server,it seemed to be wrong.And it can works on localhost.
I think it's wrong with the database and have tried to change the ip of database,but it not worked.
Traceback (most recent call last):
File "app.py", line 27, in <module>
import auth
File "/tmp/pycharm_project_flaskr/auth.py", line 5, in <module>
from db import get_db, User
File "/tmp/pycharm_project_flaskr/db.py", line 22, in <module>
db.init_app(app)
File "/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/extension.py", line 305, in init_app
engines = self._app_engines.setdefault(app, {})
File "/usr/local/lib/python3.7/weakref.py", line 489, in setdefault
return self.data.setdefault(ref(key, self._remove),default)
TypeError: cannot create weak reference to 'LocalProxy' object
That's the way about databases.
app = current_app
DB_URI = 'mysql+pymysql://{}:{}#{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy()
db.init_app(app)
I had the same issue yesterday (on Flask 2.2.2) only connecting to my production database, not local. I fixed it without downgrading Flask by re-ordering some of the steps initializing my app.
My final version was:
from flask import Flask
import os
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
with app.app_context():
database_uri = (
f'postgresql+psycopg2://{os.getenv("POSTGRES_USER")}:'
+ f'{os.getenv("POSTGRES_PW")}#'
+ f'{os.getenv("POSTGRES_URL")}/'
+ f'{os.getenv("POSTGRES_DB")}'
)
app.config["SQLALCHEMY_DATABASE_URI"] = database_uri
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
migrate = Migrate(app, db)
db.create_all()
db.session.commit()
import api
api.add_all_apis(app=app)
if __name__ == "__main__":
app.run(host="0.0.0.0")
I change the version of flask from 2.2.2 to 2.0.3 and the problem was solved.
I recently updated Flask-SQLAlchemy, and now db.create_all is raising RuntimeError: working outside of application context. How do I call create_all?
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///project.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
db.create_all()
This raises the following error:
Traceback (most recent call last):
File "/home/david/Projects/flask-sqlalchemy/example.py", line 11, in <module>
db.create_all()
File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 751, in create_all
self._call_for_binds(bind_key, "create_all")
File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 722, in _call_for_binds
engine = self.engines[key]
File "/home/david/Projects/flask-sqlalchemy/src/flask_sqlalchemy/extension.py", line 583, in engines
app = current_app._get_current_object() # type: ignore[attr-defined]
File "/home/david/Projects/flask-sqlalchemy/.venv/lib/python3.10/site-packages/werkzeug/local.py", line 513, in _get_current_object
raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.
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(). See the documentation for more information.
As of Flask-SQLAlchemy 3.0, all access to db.engine (and db.session) requires an active Flask application context. db.create_all uses db.engine, so it requires an app context.
with app.app_context():
db.create_all()
When Flask handles requests or runs CLI commands, a context is automatically pushed. You only need to push one manually outside of those situations, such as while setting up the app.
Instead of calling create_all in your code, you can also call it manually in the shell. Use flask shell to start a Python shell that already has an app context and the db object imported.
$ flask shell
>>> db.create_all()
Or push a context manually if using a plain python shell.
$ python
>>> from project import app, db
>>> app.app_context().push()
>>> db.create_all()
Here's an example.py that configures a SQLite database, a model, then creates the database. The with app.app_context() line around db.create_all() is what's needed to avoid the context error.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
db = SQLAlchemy()
class Article(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.String)
with app.app_context():
db.create_all()
Run the development server with this command, and the database will be created if it doesn't exist.
$ flask -A example.py --debug run
If you're using a python shell instead of flask shell, you can push a context manually. flask shell will handle that for you.
>>> from project import app, db
>>> app.app_context().push()
>>> db.create_all()
Learn more about the application context in the Flask docs or this video.
I'm not able to create tables into a database (PostgresSQL) when using Flask's app factory pattern.
I've looked at different examples from Stackoverflow and the Flask-SQLAlchemy source code. My understanding is that with the factory app pattern, I need to set up the so-called context before I can try creating the tables. However, when I create the context, Flask app's config dictionary gets reset and it doesn't propagate the configurations forward.
Here's my model.py
import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class MyModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
some = db.Column(db.DateTime, nullable=False)
random = db.Column(db.String, nullable=False)
model = db.Column(db.String, nullable=False)
fields = db.Column(db.Integer, nullable=False)
def __init__(self, some: datetime.datetime, random: str, model: str,
fields: int) -> None:
self.some = some
self.random = random
self.model = model
self.fields = fields
def __repr__(self):
return f"""<MyModel(some={self.some}, random={self.random},
model={self.model}, fields={self.fields})>"""
Here's the app's __init__.py file
import os
from flask import Flask
from flask_migrate import Migrate
from myapp.models import db
migrate = Migrate()
def create_app(config):
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
migrate.init_app(app, db)
from .models import MyModel
with app.app_context():
db.create_all()
#app.route('/hello')
def hello():
return('Hello World!')
return app
I also have a main.py file:
from myapp import create_app
from config import Config
app = create_app(Config)
if __name__ == "__main__":
app.run(host='127.0.0.1', port=8080, debug=True)
The root folder contains the main.py and the MyModule app folder. Furthermore, I've set up a Postgres instance and the required config constants in a config.py file:
import os
from dotenv import load_dotenv
basedir = os.path.abspath(__file__)
load_dotenv(os.path.join(basedir, '.env'))
class Config(object):
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI')
SQLALCHEMY_TRACK_MODIFICATIONS = False
I'm reading the variables from an .env file.
When I run main.py, I get the following error:
(venv) $:project-name username$ python main.py
Traceback (most recent call last):
File "main.py", line 4, in <module>
app = create_app(Config)
File "/Users/username/project-name/myapp/__init__.py", line 18, in create_app
db.create_all()
File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 1033, in create_all
self._execute_for_all_tables(app, bind, 'create_all')
File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 1025, in _execute_for_all_tables
op(bind=self.get_engine(app, bind), **extra)
File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 956, in get_engine
return connector.get_engine()
File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 560, in get_engine
options = self.get_options(sa_url, echo)
File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 575, in get_options
self._sa.apply_driver_hacks(self._app, sa_url, options)
File "/Users/username/venv/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py", line 877, in apply_driver_hacks
if sa_url.drivername.startswith('mysql'):
AttributeError: 'NoneType' object has no attribute 'drivername'
Now what's strange here is that when I print print(app.config) inside the create_app function, the configurations are in place, just like I want them to be. So for example SQLALCHEMY_DATABASE_URI=postgresql://testuser:testpassword#localhost:5432/testdb'. However, when I print the same info inside the app.app_context() loop, SQLALCHEMY_DATABASE_URI=None (as an example, the other key-value pairs are also reset).
What am I missing here?
You are loading your .env file incorrectly:
basedir = os.path.abspath(__file__)
load_dotenv(os.path.join(basedir, '.env'))
basedir is the module file itself, not the directory. So for a file named config.py, basedir is set to /..absolutepath../config.py, not /..absolutepath../config.py. As a result, you are asking dotenv() to load the file /..absolutepath../config.py/.env, which won't exist.
You are missing a os.path.dirname() call:
basedir = os.dirname(os.path.abspath(__file__))
You can avoid this issue altogether by using dotenv.find_dotenv():
load_dotenv(find_dotenv())
which uses the __file__ attribute of the module it is called from.
Other remarks:
You are using Flask-Migrate to manage the schema, so don't call db.create_all(). Instead use the Flask CLI and the Flask Migrate commands (flask db init, flask db migrate, and flask db upgrade to create a migration directory and your initial migration script and then upgrade your connected database to use the latest schema version.
If you are configuring your database from environment variables, then don't use a variable config object. It's easier to work with a Flask app factory if you just import config from the current project for default configuration that applies to all development. You can always load in more configuration via app.config.from_obj() or app.config.from_envvar(), using optional arguments and an environment variable, as needed.
I am writing a flask application. I have two files. main.py and databases.py. I want to create a database from the database.py file. The main.py should access the databases.py file and create the database and table named "Users". But it shows import error. Help me with this issue
main.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from databases import User
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/data_log.db'
db = SQLAlchemy(app)
if __name__ == '__main__':
db.create_all()
app.run(host='0.0.0.0', port=5001)
databases.py
from main import db
from passlib.apps import custom_app_context as pwd_context
class User(db.Model) :
__tablename__ = 'users'
user_id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(32), index = True)
password = db.Column(db.String(128))
def hash_password(self, password) :
self.password =pwd_context.hash(password)
def verify_password(self, password) :
return pwd_context.verify(password, self.password)
Traceback:
Traceback (most recent call last):
File "main.py", line 3, in <module>
from databases import User
File "/home/paulsteven/stack/databases.py", line 1, in <module>
from main import db
File "/home/paulsteven/stack/main.py", line 3, in <module>
from databases import User
ImportError: cannot import name 'User'
This is a regular case of cyclic imports conflict.
The traceback gives you a clear steps:
How it goes in steps:
you run main.py
the control flow starts importing features/libraries till it gets the 3rd line
from databases import User.
it goes to the databases module to find the needed User class. But ... the User may use the outer scope features (and it does require db.Model), so the control flow needs to scan databases module from the start. This reflects the 2nd step from traceback ("/home/paulsteven/stack/databases.py", line 1)
from the position of previous step being at database.py the control flow encounters from main import db - that means it should turn back to the main(main.py) module!
control flow returned to the main module start scanning again from the 1st line - till it finds from databases import User again. This reflects the traceback's 3rd step (File "/home/paulsteven/stack/main.py", line 3)
and you run into cycle ...
What is right way to solve the issue?
Keep all DB context/DB models in separate module(s).
Follow the sequence of objects relations and how they depend on each other:
---> Application instantiated first (app)
---> then DB framework instance is created db = SQLAlchemy(app) depending on app
---> then custom DB models created (like User(db.Model)) depending on db instance
main.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# from databases import User <--- shouldn't be here
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/data_log.db'
db = SQLAlchemy(app)
if __name__ == '__main__':
from databases import User # after instantiating `db` import model(s)
db.create_all()
app.run(host='0.0.0.0', port=5001)