I have a small Flask app which uses MongoEngine.
my project structure:
/myproject
-application.py
-config.py
/my_app
-models.py
-views.py
my application.py:
#!/usr/bin/env python
from flask.ext.mongoengine import MongoEngine
from config import app
import os
app.debug = True
# get config settings
if __name__ == '__main__':
app.config.from_object('config')
else:
app.config.from_object('heroku_config')
# wrap app in mongengine
db = MongoEngine(app)
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
my models.py:
from application import db
from flask import url_for
# declare model classes
...
I am deploying on heroku. If my Procfile reads:
web: python application.py
It works fine. When I try to switch to Gunicorn:
web: gunicorn application:app
When I start gunicorn it complains by way of an import error:
ImportError: cannot import name db
Why is this an issue now? I'm guessing it's a path problem but I can't see why so.
I assume you're registering blueprints or something like that in application.py, which in turn imports the model, right?
You didn't supply the view file or how you're using the view file and if my guess isn't correct my answer below won't be either.
If my guess is correct it is probably because of a circular import.
You could create a db.py file that contains these lines (move from application.py):
from flask.ext.mongoengine import MongoEngine
db = MongoEngine(app)
and then import that file into your models (from db import db).
That means the flow would look something like this: db -> model -> view -> app instead of app (db) -> model -> view -> app.
Circular imports creates all kinds of annoying problems, try to avoid them whenever possible.
If you are using an init style flask module then the following works (derived from the pallet flask tutorial v Flask 2.0.1).
https://www.palletsprojects.com/p/flask/
web: env FLASK_APP=flaskr gunicorn -b '0.0.0.0':${PORT} 'flaskr:create_app()'
Where create_app is the "app" called from
flaskr/init.py
Related
I've been trying to deploy my Flask app to Heroku for over a day, watching/reading several tutorials, and digging through all the stackoverflow questions i could find and still haven't found a solution for my issue. When i deploy my app, I get the error "gunicorn.errors.AppImportError: Failed to find attribute 'app' in 'app'." I've changed my Procfile many times to get heroku to run my app but i always get the same error.
This is how my app is structured:
enter image description here
My Procfile includes this statement:
web: gunicorn app:app --preload
I am thinking my issues could be how im creating my app, but could not find a solution. My main app file looks like this:
from venv import create
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os.path import join, dirname, realpath
from flask_login import LoginManager
db = SQLAlchemy()
def create_app():
app = Flask(__name__, static_folder='static')
app.debug = True
app.config['SECRET_KEY'] = 'abcde12568901fghij'
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'
app.config['SQLALCHEMY_DATABASE_URI'] = '[removed for privacy]'
app.config['UPLOAD_DIRECTORY'] = join(dirname(realpath(__file__)), 'uploads/')
app.config['MAX_CONTENT_LENGTH'] = 16*1024*1024 #16mb
app.config['ALLOWED_EXTENSIONS'] = ['.jpg','.jpeg','.png','.gif','.mp4']
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
from models import User
#login_manager.user_loader
def load_user(user_id):
# since the user_id is just the primary key of our user table, use it in the query for the user
return User.query.get(int(user_id))
from auth import auth
app.register_blueprint(auth)
from views import main
app.register_blueprint(main)
return app
if __name__ == '__main__':
db.create_all(app=create_app())
Screenshot of full logs:
enter image description here
Any help would be greatly appreciated, thanks all!
app:app tells Gunicorn to look for a variable called app in your app.py file (strictly speaking, in your app module), but you don't have a variable with that name.
Instead, you have a function create_app() that returns your app object. Gunicorn allows you to use that directly:
The variable name can also be a function call. In that case the name will be imported from the module, then called to get the application object. This is commonly referred to as the "application factory" pattern.
Update your Procfile accordingly:
web: gunicorn 'app:create_app()' --preload
Do you have another file in your root directory that is creating the app or is the code above the file that you run to run the app? This will normally just be a Python file with the name of your project, and this will have something like app = create_app().
Then your Procfile needs to look for the app in that file.
For example if that file was called mainApp.py you would then use
web: gunicorn mainApp:app --preload
I'm trying to test my database how it behaves in a many-to-many relationships. I'm struggling to access the application context of the Flask app.
I ran the Python terminal in the parent folder of the app and followed the steps found on SO and elsewhere. I could manage (i think) to import the app, create it, push the context, import the db. However, whenever I want to import models I'm prompted with a:
Error ModuleNotFoundError: No module named 'db'
Despite the fact that db is definately defined:
This is the screenshot of the complete process.
The folder structure is:
- app
--__int__.py
This is the app/init.py file:
from flask import Flask,Blueprint
from flask_sqlalchemy import SQLAlchemy
from app.config import Config
from mailjet_rest import Client
db = SQLAlchemy()
mailjet = Client(auth=(Config.MJ_APIKEY_PUBLIC, Config.MJ_APIKEY_PRIVATE), version='v3.1')
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
from app.views.users import users
from app.views.data import data
from app.views.admin import admin
app.register_blueprint(users,url_prefix='/users')
app.register_blueprint(data,url_prefix='/data')
app.register_blueprint(admin,url_prefix='/admin')
# with app.app_context():
# db.create_all()
return app
I'd greatly appreciate any input!
Thank you,
Matija
The solution was quite simple. I ought to import models from app.models and not from db.
The steps I took:
Rename the folder to app
Ran Flask shell command on the app level
Imported app
Import models from app.models
I have been learning python recently and practiced a couple of tutorials and its been going fine, till I have divided my application to sub modules to make it easier to maintain using blueprints, after doing so the application crashed and throw the following error: OperationalError: (sqlite3.OperationalError) no such table, here is how im dividing my application:
-instance
-flask.cfg
-app
- static // Folder for css
- templates // Folder for common html files
-__init__.py // to init the app
-module1
-__init__.py // to register module blueprint
-subModule1
-subModule1 Group1
-templates
-htmls files
-__init__.py file //to register group1 blueprint
-Group1Form
-Group1Model
-Group1View
-subModule1 Group2
-templates
-htmls files
-__init__.py file //to register group2 blueprint
-Group2Form
-Group2Model
-Group2View
-subModule2
....
-main.py
The application run fine when I use flask run but I have an issue when I use db.session.add() method with the exception that the table was not found. I have tried many solutions to this issue but no luck. here is some links for the same issue:
OperationalError: (sqlite3.OperationalError) no such table: user
https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/
Python sqlite3.OperationalError: no such table:
'No application found. Either work inside a view function or push an application context.'
Here is the flask.cfg file:
import os
BASEDIR = os.path.abspath(os.path.dirname(__file__))
SECRET_KEY = os.urandom(32)
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.abspath('app.db')
And here is how I am initializing the app in the main __init__.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app(config_filename=None):
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile(config_filename)
initialize_extensions(app)
register_blueprints(app)
def create_app(config_filename=None):
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile(config_filename)
initialize_extensions(app)
register_blueprints(app)
return app
def initialize_extensions(app):
db.init_app(app)
with app.app_context():
db.create_all()
def register_blueprints(app):
from app.module1.config.university import university_blueprint
app.register_blueprint(university_blueprint)
from app.module1.config.department import department_blueprint
app.register_blueprint(department_blueprint)
from app.module1.authors.author import author_blueprint
app.register_blueprint(author_blueprint)
from app.module1.authors.publications import publications_blueprint
app.register_blueprint(publications_blueprint)
can you move db.init_app() inside app.app_context() function
with app.app_context():
db.init_app()
I figured out the issue, I was suppose to place:
with app.app_context():
db.create_all()
after registering the blueprints
Creating custom commands in flask needs access to the app, which is generally created in app.py like this:
import click
from flask import Flask
app = Flask(__name__)
#app.cli.command("create-user")
#click.argument("name")
def create_user(name):
...
However, in order not to bloat my app.py, I want to put my custom commands in a separate file e.g. commands.py, but this doesn't work because the entrypoint to my project is app.py, so I'll have to import app in commands.pyand import my commands in app.py which results in a circular import error.
How can I create custom commands in separate files ?
One way to achieve this would be using blueprints
I have tested it using Flask 1.1.1, so be sure to check the documentation of the correct version that you have.
Here is the general idea:
Create one or more Blueprints in a different file, let's say it's called commands.py
Then import the new blueprints and register them to your app
==> app.py <==
from flask import Flask
from commands import usersbp
app = Flask(__name__)
# you MUST register the blueprint
app.register_blueprint(usersbp)
==> commands.py <==
import click
from flask import Blueprint
usersbp = Blueprint('users', __name__)
#usersbp.cli.command('create')
#click.argument('name')
def create(name):
""" Creates a user """
print("Create user: {}".format(name))
Upon executing flask users you should get a response like the following:
flask users
Usage: flask users [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
create Creates a user
just import it in your app factory
dir tree
my_app
L app.py
L commands.py
commands.py
#app.cli.command('resetdb')
def resetdb_command():
"""Here info that will be shown in flask --help"""
pass
app.py
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
with app.app_context():
from . import routes
from . import commands # <----- here
return app
$ export FLASK_APP=my_app/app.py
$ flask resetdb
but there have to be better way ;) of which I am unaware right now
If you're using an app factory (you have a create_app() function), then there isn't even an app variable for you to import.
The best way to keep your code organized is to define the function somewhere else, and then register it when building the application instance.
E.g.
my_app/
| main.py
| app/
| | __init__.py
| | commands.py
commands.py
def foo():
print("Running foo()")
init.py
def create_app():
app = Flask(__name__)
...
from .commands import foo
#app.cli.command('foo')
def foo_command():
foo()
...
I have this layout:
baseapp.py
from flask import Flask
app = Flask("CmdAttempt")
app.py
from .baseapp import app
def main():
app.run(
port=5522,
load_dotenv=True,
debug=True
)
if __name__ == '__main__':
main()
commands.py
import click
from .baseapp import app
#app.cli.command("create-super-user")
#click.argument("name")
def create_super_user(name):
print("Now creating user", name)
if __name__ == '__main__':
from .app import main
main()
In the console where you run the commands first define the FLASK_APP to be commands.py, then run the commands that you define.
set FLASK_APP=commands.py
export FLASK_APP=commands.py
flask create-super-user me
You can either use a separate terminal for built-in commands or clear the FLASK_APP variable before issuing them. In Linux is even easier because you can do
FLASK_APP=commands.py flask create-super-user me
What worked for me in case you are not using app factory pattern, similar to #quester:
app.py
import os
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL")
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
migrate = Migrate(app, db)
with app.app_context():
# needed to make CLI commands work
from commands import *
commands.py
from app import app
#app.cli.command()
def do_something():
print('hello i am so nice I posted this even though I have 100 other things to do')
I am using Flask foundation to begin with my new flask app.
The init.py file has a method:
def create_app(object_name, env="prod"):
"""
An flask application factory, as explained here:
http://flask.pocoo.org/docs/patterns/appfactories/
Arguments:
object_name: the python path of the config object,
e.g. sservice.settings.ProdConfig
env: The name of the current environment, e.g. prod or dev
"""
app = Flask(__name__)
app.config.from_object(object_name)
app.config['ENV'] = env
#init the cache
cache.init_app(app)
debug_toolbar.init_app(app)
#init SQLAlchemy
db.init_app(app)
login_manager.init_app(app)
# Import and register the different asset bundles
assets_env.init_app(app)
assets_loader = PythonAssetsLoader(assets)
for name, bundle in assets_loader.load_bundles().iteritems():
assets_env.register(name, bundle)
# register our blueprints
from controllers.main import main
app.register_blueprint(main)
return app
that is imported in manage.py.
But what If I need to use this app variable to access the application configuration in modules within the application? I can't use current_app outside request contexts. Creating one is ugly.
I need to have a app variable in my models.py file:
In models.py
# how to import? Below doesn't work
from appname import app
# access config
print(app.config)
I can't call this method create_app, because it should be only called once to create the application. Not anytime you need to import the app. How should I solve this?
I only want to use create_app() exactly once outside the package to give it the wsgi server, but I don't want to use it within the package.
What is working now for me:
Wherever there is no current_app (outside of request contexts I guess) just use something like this
app = Flask(__name__)
app.config.from_object('appname.settings_file.DevConfig')
print(app.config)