In Flask is it possible to import views using the create_app() pattern without using Blueprints? - flask

I have a very small Flask app that is laid out as follows:
tinker/
main.py
/my_package
init.py
views.py
When I do tinker>python main.py everything runs fine. Here are the contents of each file:
main.py:
from my_package import app
app.run()
my_package/init.py:
from flask import Flask
app = Flask(__name__)
from my_package import views
my_package/views.py:
from my_package import app
#app.route('/')
def home():
return 'Ola!!!!!'
While all the above code runs fine when I try to modify it slightly by using a a create_app() code pattern, as in the below, views.py throws the following exception: "ImportError: cannot import name 'app' from 'my_package' " Is there a way to fix the problem without using Blueprints?
main.py:
from my_package import create_app
app = create_app()
app.run()
my_package/init.py:
from flask import Flask
def create_app():
app = Flask(__name__)
from my_package import views
return app
my_package/views.py:
from my_package import app
#app.route('/')
def home():
return 'Ola!!!!!'

You import the views within application context, then in the views you can use current_app.
in mypackage/__init__.py:
def create_app():
app = Flask(__name__)
with app.app_context():
from . import views
in mypackage/views.py:
from flask import current_app
#current_app.route('/')
def index():
return 'hello, world!'

init.py needs to be renamed to __init__.py
Move app = Flask(__name__) outside of the create_app method
Change to from . import app in views.py

Related

how to add app object in flask's main file

I want to add app object once in main.py which can be used everywhere, but route does not work in this way. What is the issue here?
main.py
from flask import Flask
app = Flask(__name__)
if __name__ == "__main__":
app.run(debug=True)
routes.py
from main import app
#app.route("/", methods = ["GET"])
def home():
return "hi"
However, if declare app = Flask(name) in routes.py and import app in main.py it is working all fine. Working scenario.
main.py
from routes import app
if __name__ == "__main__":
app.run(debug=True)
routes.py
from flask import Flask, jsonify, request
app = Flask(__name__)
#app.route("/", methods = ["GET"])
def home():
return "hi"
my objective is to define app in main.py and import it in other files, but getting issues.
main.py is not even aware that routes.py exists. Import your routes.py file after initializing your app.
# main.py
from flask import Flask
app = Flask(__name__)
import routes # needed
if __name__ == "__main__":
app.run(debug=True)
# routes.py
from __main__ import app
#app.route("/")
def home():
return "hi"

Simple Flask example with pytest and application factory does not work

I am new to flask and I have set up a simple flask example and two tests using pytest(see here). When I let run only one test it works, but if I run both tests it does not work.
Anyone knows why? I think I am missing here some basics of how flask works.
code structure:
app/__init__.py
from flask import Flask
def create_app():
app = Flask(__name__)
with app.app_context():
from app import views
return app
app/views.py
from flask import current_app as app
#app.route('/')
def index():
return 'Index Page'
#app.route('/hello')
def hello():
return 'Hello World!'
tests/conftest.py
import pytest
from app import create_app
#pytest.fixture
def client():
app = create_app()
yield app.test_client()
tests/test_app.py
from app import create_app
def test_index(client):
response = client.get("/")
assert response.data == b"Index Page"
def test_hello(client):
response = client.get("/hello")
assert response.data == b"Hello World!"
The problem is with your registration of the routes in app/views.py when you register them with current_app as app. I'm not sure how you would apply the application factory pattern without using blueprints as the pattern description in the documentation implies they are mandatory for the pattern:
If you are already using packages and blueprints for your application [...]
So I adjusted your code to use a blueprint instead:
app/main/__init__.py:
from flask import Blueprint
bp = Blueprint('main', __name__)
from app.main import views
app/views.py -> app/main/views.py:
from app.main import bp
#bp.route('/')
def index():
return 'Index Page'
#bp.route('/hello')
def hello():
return 'Hello World!'
app/__init__.py:
from flask import Flask
def create_app():
app = Flask(__name__)
# register routes with app instead of current_app:
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
Then your tests work as intended:
$ python -m pytest tests
============================== test session starts ==============================
platform darwin -- Python 3.6.5, pytest-6.1.0, py-1.9.0, pluggy-0.13.1
rootdir: /Users/oschlueter/github/simple-flask-example-with-pytest
collected 2 items
tests/test_app.py .. [100%]
=============================== 2 passed in 0.02s ===============================

flask NoAppException but flask run works

I have the following structure:
app_dir/
| myapi/
| __init__.py
| myapi_app.py
where myapi_app.py is
from myapi import create_app, db
app = create_app()
and myapi/__init__.py is
import logging
import os
from logging.handlers import RotatingFileHandler
from flask import Flask, request, current_app
from flask_sqlalchemy import SQLAlchemy
from myapi.config import Config
db = SQLAlchemy()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
...
return app
When I set FLASK_APP=myapi_app.py and run flask run from the app_dir directory, the flask service starts. However, when I make a request, I get the following error: flask.cli.NoAppException: Could not import "myapi_app". Where am I going wrong?
Your problem is that you are setting $FLASK_APP to the file in which the app variable is stored, you should instead set it to the python object path, e.g.
FLASK_APP=myapi_app:app
However, this is not necessary, as you could also just do:
FLASK_APP=myapi
as Flask will look for a create_app function in the package on its own.

python flask ImportError: No module named views.login

I have a app named flaskr. When I want to import views.login` from views. it gives me error:
File "C:\Projects\flaskr\flaskr.py", line 28, in <module>
from flaskr.views.login import login
ImportError: No module named views.login
Before I put all the methods inside the flaskr.py file. I want to move each functions to different views, like login, show_entries, log_out, just like MVC has different views.
flaskr.py
from sqlite3 import dbapi2 as sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
import os
app = Flask(__name__)
app.config.from_object(__name__)
from flaskr.views.login import login
app.register_blueprint(login)
if __name__ == '__main__':
app.run(debug = True)
login.py
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
from jinja2 import TemplateNotFound
login = Blueprint('login', __name__,template_folder='../template')
#app.route('/login')
def login():
return render_template('login.html')
Create folder named app or whatever.
Create __init__.py file in app:
from sqlite3 import dbapi2 as sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
import os
app = Flask(__name__)
app.config.from_object(__name__)
from app import views
app.register_blueprint(views.login)
Move app.run method into separate start.py file in root directory
from app import app
if __name__ == '__main__':
app.run(debug = True)
Create folder views in app/. Create __init__.py in views
Now you could have structure like this:
your_project_name/
|app/
|__init__.py
|views/
|__init__.py
|login.py
start.py
Sorry, if there are have mistakes.

How do I add flask-admin to a Blueprint?

for example:
from flask import Flask
from flask.ext.admin import Admin, BaseView, expose
class MyView(BaseView):
#expose('/')
def index(self):
return self.render('index.html')
app = Flask(__name__)
admin = Admin(app)
admin.add_view(MyView(name='Hello'))
app.run()
but, if I need a new file, called 'views.py', how can I add a view into views.py to admin?
Do I need to use a blueprint?
For my project I actually made a child class of Blueprint that supports flask admin:
from flask import Blueprint
from flask_admin.contrib.sqla import ModelView
from flask_admin import Admin
class AdminBlueprint(Blueprint):
views=None
def __init__(self,*args, **kargs):
self.views = []
return super(AdminBlueprint, self).__init__('admin2', __name__,url_prefix='/admin2',static_folder='static', static_url_path='/static/admin')
def add_view(self, view):
self.views.append(view)
def register(self,app, options, first_registration=False):
admin = Admin(app, name='microblog', template_mode='adminlte')
for v in self.views:
admin.add_view(v)
return super(AdminBlueprint, self).register(app, options, first_registration)
For details you may like to read my blog here: http://blog.sadafnoor.me/blog/how-to-add-flask-admin-to-a-blueprint/
I am very late for this question, but anyway... My guess is that you want to use the Application Factory pattern and use the Flask-Admin. There is a nice discussion about the underlying problems. I used a very ugly solution, instantiating the Flask-Admin in the init.py file:
from flask_admin.contrib.sqla import ModelView
class UserModelView(ModelView):
create_modal = True
edit_modal = True
can_export = True
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
db.init_app(app)
# import models here because otherwise it will throw errors
from models import User, Sector, Article
admin.init_app(app)
admin.add_view(UserModelView(User, db.session))
# attach blueprints
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')
return app
You don't need a blueprint for that. In views.py add an import for the admin object you defined in your main project:
from projectmodule import admin
from flask.ext.admin import BaseView, expose
class MyView(BaseView):
#expose('/')
def index(self):
return self.render('index.html')
admin.add_view(MyView(name='Hello'))
and in your main projectmodule file use:
from flask import Flask
from flask.ext.admin import Admin
app = Flask(__name__)
admin = Admin(app)
# import the views
import views
app.run()
e.g. you add import views after the line that sets admin = Admin(app).
I have an flask app with one blueprint (and login/logout to admin).
This is the best solution I found to implement flask admin with some custom features.
My structure as follows:
my_app
main
__init__.py
routes.py
static
templates
__init__.py
config.py
models.py
run.py
Customized admin index view from models.py
from flask_admin import AdminIndexView
class MyAdminIndexView(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('main.home'))
Main init.py as follows:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.menu import MenuLink
from my_app.config import Config
# create extensions
db = SQLAlchemy()
admin = Admin()
def create_app(config_class=Config): # default configutation
app = Flask(__name__)
app.config.from_object(Config)
#initialize extensions
db.init_app(app)
...
# customized admin views
from my_app.models import MyAdminIndexView
admin.init_app(app,index_view=MyAdminIndexView())
admin.add_link(MenuLink(name='Home', url='/'))
admin.add_link(MenuLink(name='Logout', url='/logout'))
#blueprint
from my_app.main.routes import main
app.register_blueprint(main)
return app
I think this is the most elegant solution I came up so far.
In order to keep clean the __init__.py root file:
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from app.config import Config
from flask_admin import Admin
db = SQLAlchemy()
admin = Admin(template_mode="bootstrap3")
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
admin.init_app(app)
from app.admin import bp
app.register_blueprint(bp, url_prefix='/admin')
return app
Then in the __init__.py of the Blueprint admin app
# app/admin/__init__.py
from flask import Blueprint
from app import admin, db
from app.models import User
from flask_admin.contrib.sqla import ModelView
bp = Blueprint('admin_app', __name__)
admin.name = 'Admin panel'
admin.add_view(ModelView(User, db.session))
# all the rest stuff