I have a very simple flask app that looks like this:
from flask import Flask
def create_app():
app = Flask(__name__, instance_relative_config=True)
app.config.from_object('config.settings')
app.config.from_pyfile('settings.py', silent=True)
#app.route('/')
def home():
return 'Hello World!'
return app
In my settings.py file I have the following:
DEBUG = True
SECRET_KEY = mysecretkey
FLASK_APP = app
FLASK_ENV = development
My directory structure looks like this:
requirements.txt
.gitignore
app/
-- __init__.py
-- app.py
At first I had the app factory in app.py, and flask run didn't work, but it does if the app factory is in __init__.py. I tried changing the FLASK_APP variable to app:app to note that it's in the app.py file but that didn't work either.
If I wanted, how could I arrange to run create_app() from app.py?
Thank you.
Set the FLASK_APP env variable to app:create_app since you create and return the app from this function.
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 run my flask app with "python app.py" instead of "flask run" command.
My goal is to launch the app on cpanel server and just about every tutorial requires the applications to be called using the "python" method.
Here is my folder structure:
project
webapp
init.py
templates
static
auth.py
main.py
app.py <-------------- I want this to be called with python instead of flask run command outside the folder
Here is my init_.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = '9OLWxND4o83j4iuopO'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
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))
# blueprint for auth routes in our app
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non-auth parts of app
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
And app.py is:
from webapp import app
I'm a newbie in flask, any help is appreciated
Insert the call to create_app at the end of init.py:
if __name__ == '__main__':
create_app().run(host='0.0.0.0', port=5000, debug=True)
The if statement avoid calling the app many times. It can only be called directly. Flask default host is 127.0.0.1 (localhost). Use 0.0.0.0 at production for better traffic monitoring. Default port is also 5000, so it's up to you to include. For better readability, you should explicit it.
Then call it
python webapp/init.py
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 trying to implement Flask-PyMongo with blueprints and an application factory and keep getting AttributeError: 'Flask' object has no attribute 'db'
My directory structure looks like
myapp/
myapp.py
config.py
/app
__init__.py
/v1
__init__.py
endpoints.py
In my python script that starts the Flask app I have:
import os
from app import create_app
app = create_app('dev')
In my top level init.py I have:
mongo = PyMongo()
def create_app(config_name):
app = Flask(__name__)
mongo.init_app(app)
app.config.from_object(config[config_name])
from app.v1 import psapi as psapi_bp
app.register_blueprint(psapi_bp, url_prefix='/api')
if not os.path.exists('logs'):
os.mkdir('logs')
In my endpoints.py I have a route that looks like
#myapp.route('/addentry', methods=['POST'])
def addentry():
username = request.json['username']
userid = current_app.db.user_entry.insert({'username':username})
return jsonify({'userid':userid})
I feel like there is something small that I am missing but I am not seeing it.
You need to call db on your mongo object, not on the app object
to those who may be facing this problem again :
you should first define mongo oustside create_app to have access to it from inside other files.
then init_app with that like the following:
from flask import Flask, current_app
from flask_pymongo import PyMongo
mongo = PyMongo()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=False)
app.config.from_object(app_config[config_name])
# INIT EXTENSIONS ----------------------
mongo.init_app(app)
return app
then in any file you can import mongo from above file. for example:
from ../factory import mongo
I'm using Flask-Script and I've got a manage.py that looks like this.
from mypackage import create_app
from flask.ext.script import Manager
app = create_app()
manager = Manager(app)
if __name__ == '__main__':
manager.run()
I'll start my app with python manage.py runserver --debug
From within manage.py, how can I find out that runserver was called with --debug?
I've tried app.debug but that returns False and manager.get_options() returns an empty list.
The code you've provided is fine-- here's a mypackage.py file to demonstrate that:
from flask import Flask, Blueprint, current_app
test = Blueprint('user', __name__, url_prefix='/')
#test.route('/')
def home():
return str(current_app.debug)
def create_app():
app = Flask(__name__)
app.register_blueprint(test)
return app
Adding --debug reflects accurately (True) when you access the index page.