Structuring Flask using Blueprints error - python

I'm attempting to break a small app into units and use the Blueprint pattern in Flask. However I seem to have trouble in getting the app running.
Here is my structure:
\myapp
login.py
\upload
__init__.py
views.py
Here is login.py:
import sys, os
from flask import Flask, Blueprint, request
from flask import render_template, session
from .upload import views
app = Flask(__name__)
app.register_blueprint(views)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
print app.url_map
print app.blueprints
app.run(debug = True)
for __init__.py
from flask import Flask
app.register_blueprint('upload', __name__)
and in views.py
from flask import Flask, Blueprint, request, redirect, url_for, render_template
import views
upload = Blueprint('upload', __name__)
#upload.route('/uploaded', methods=['GET', 'POST'])
def upload_file():
...
Looking at the logs on heroku, here is the error:
from .upload import views
2015-09-05T10:59:00.506513+00:00 app[web.1]: ValueError: Attempted relative import in non-package
Have a structured my package and blueprint correctly? I used the documentation, but I think I'm missing something here.

There are three problems with your code:
You are using a relative import in login.py to include views, but given the folder structure and the fact that you use login.py as starting point, it cannot work here. Simply use from upload import views instead.
The __init__.py references an unknown variable, app. You actually don't need anything in this file, remove everything.
You try to register a module as a blueprint via app.register_blueprint(views) in login.py. This cannot work, a module is not a blueprint. Instead, import the upload variable defined in the views module, that is a blueprint: app.register_blueprint(views.upload).
Changing that should get you started. Two side notes:
You have an import in views.py that should probably not be there: import views. This should be harmless however.
I answered a question about Flask blueprints some days ago, and gave an example about how to use them. Maybe would you find the answer useful in your case as well (in particular the part where the blueprint definition is moved to the __init__.py file defining the blueprint).

Related

Getting 404 not found on Flask app deployed on PythonAnywhere

I've rummaged through maybe 50 different answers to this and still I haven't manage to fix it... I'm pretty new to flask and python.
I have an app which was running great locally but I've struggled with deploying on python anywhere. Initially I had a few import modules issues, now it runs but doesn't return any html template, despite not seeing any other issue. The main issue I had was that it couldn't find the "routes" app from wsgi, and I sort of fixed adding the app = Flask(name) line on routes.py (the short blueprint object is not callable).
routes.py:
from flask import Blueprint, render_template, request, redirect, send_file
import pyqrcode
from pyqrcode import QRCode
import subprocess
from extensions import db
from models import Link
app = Flask(__name__)
short = Blueprint('short', __name__, url_prefix='/')
#short.route('/index')
def index():
return render_template('index.html')
init.py
from flask import Flask
from extensions import db
from routes import short
def create_app(config_file='settings.py'):
app = Flask(__name__)
app.config.from_pyfile(config_file)
db.init_app(app)
app.register_blueprint(short)
return app
wsgi.py
import sys
# add your project directory to the sys.path
project_home = u'/home/b297py/mysite'
if project_home not in sys.path:
sys.path = [project_home] + sys.path
# import flask app but need to call it "application" for WSGI to work
from routes import app as application
For the purpose of testing, I've placed all the html templates both in the root directory and in the specific /template directory but it just didn't fix the issue.
In wsgi.py you are not calling create_app so you are never registering the blueprint. You should replace :
from routes import app as application
by something like :
from package_name import create_app
application = create_app()
(Example: https://www.pythonanywhere.com/forums/topic/12889/#id_post_50171)
Also as you mentioned, the fix adding app = Flask(__name__) to routes.pyallows you to bypass create_app (so you should remove it if you want to stick to the create_app approach).

How to run Flask app by flask run with blueprint template

In a Python authorization app, in my main py I have the following code:
# main.py
from flask import Blueprint, render_template
from flask_login import login_required, current_user
theapp = Blueprint('main', __name__)
#theapp.route('/')
def index():
return render_template('index.html')
When I try:
FLASK_APP=main.py
FLASK_DEBUG=1
flask run
I get the following error:
Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.
Basically a Blueprint is a way for you to organize your flask application into smaller and reusable applications. I am not sure why you have used it here in the main.py.
You could do that some other file, for example, you have a set of endpoints to implement login functionality in a separate file then what you should be doing is:
Assume you have a login.py .Sample Code looks like follows:
from flask import Blueprint
bp = Blueprint('login_bp', __name__)
def login_bp():
return bp
And the following code goes into you main.py , you need to start the Flask Server using .run()
from flask import Flask
from flask import Blueprint, render_template
from login import login_bp #Assume you have a module login and I am importing login_bp from login.py
theapp = Flask(__name__) #Creating Flask instance
theapp.register_blueprint(login_bp()) # Registering Blueprint here
#theapp.route('/')
def index():
return render_template('index.html')
theapp.run(host="0.0.0.0", port=2019, debug=True) #Starting the Flask Server
Hope this works, please do look out for documents and code example to get deeper insights.

How to access functions in packages in Flask? [duplicate]

My flask application currently consists of a single test.py file with multiple routes and the main() route defined. Is there some way I could create a test2.py file that contains routes that were not handled in test.py?
#app.route('/somepath')
def somehandler():
# Handler code here
I am concerned that there are too many routes in test.py and would like to make it such that I can run python test.py, which will also pick up the routes on test.py as if it were part of the same file. What changes to I have to make in test.py and/or include in test2.py to get this to work?
You can use the usual Python package structure to divide your App into multiple modules, see the Flask docs.
However,
Flask uses a concept of blueprints for making application components and supporting common patterns within an application or across applications.
You can create a sub-component of your app as a Blueprint in a separate file:
simple_page = Blueprint('simple_page', __name__, template_folder='templates')
#simple_page.route('/<page>')
def show(page):
# stuff
And then use it in the main part:
from yourapplication.simple_page import simple_page
app = Flask(__name__)
app.register_blueprint(simple_page)
Blueprints can also bundle specific resources: templates or static files. Please refer to the Flask docs for all the details.
You can use simple trick which is import flask app variable from main inside another file, like:
test_routes.py
from __main__ import app
#app.route('/test', methods=['GET'])
def test():
return 'it works!'
and in your main files, where you declared flask app, import test-routes, like:
app.py
from flask import Flask, request, abort
app = Flask(__name__)
# import declared routes
import test_routes
It works from my side.
This task can be accomplished without blueprints and tricky imports using Centralized URL Map
app.py
import views
from flask import Flask
app = Flask(__name__)
app.add_url_rule('/', view_func=views.index)
app.add_url_rule('/other', view_func=views.other)
if __name__ == '__main__':
app.run(debug=True, use_reloader=True)
views.py
from flask import render_template
def index():
return render_template('index.html')
def other():
return render_template('other.html')
I would like to recommend flask-empty at GitHub.
It provides an easy way to understand Blueprints, multiple views and extensions.
If you need split blueprint to separate files you can use snippet:
# app.py
from blueprint_module import blueprint
app = Flask(__name__)
app.register_blueprint(blueprint)
# blueprint_module\__init__.py
from flask import Blueprint
blueprint = Blueprint('my_blueprint', __name__)
from . import page
# blueprint_module\page.py
from . import blueprint
#blueprint.route("/url", methods=['GET'])
def hello():
return 'hello world'
Dividing the app into blueprints is a great idea. However, if this isn't enough, and if you want to then divide the Blueprint itself into multiple py files, this is also possible using the regular Python module import system, and then looping through all the routes that get imported from the other files.
I created a Gist with the code for doing this:
https://gist.github.com/Jaza/61f879f577bc9d06029e
As far as I'm aware, this is the only feasible way to divide up a Blueprint at the moment. It's not possible to create "sub-blueprints" in Flask, although there's an issue open with a lot of discussion about this:
https://github.com/mitsuhiko/flask/issues/593
Also, even if it were possible (and it's probably do-able using some of the snippets from that issue thread), sub-blueprints may be too restrictive for your use case anyway - e.g. if you don't want all the routes in a sub-module to have the same URL sub-prefix.

Order of registering Flask Blueprints

I ran into a strange issue (maybe not so strange for experienced in flask).
I have a flask application running in the context of Google App Engine's dev_appserver.py
I have a blueprint in my flask application
# rest_server.py
rest_api = Blueprint('rest_api', __name__)
app = Flask(__name__)
app.register_blueprint(rest_api, url_prefix='/api') # [1] DOESN'T WORK
#rest_api.route("/")
def hello():
return "Hello World"
app.register_blueprint(rest_api, url_prefix="/api") # [2] WORKS AS EXPECTED
I have the following in my app.yaml
-url: "/api/.*"
script: rest_server.app
When I hit localhost:8080/api/ when I register blueprint at position [1], I get an error saying there is no matching endpoint.
However, when I register bluerpint at [2], any position after the decorator, it works.
Is it required to register the blueprint after all the decorators?
Yes, it's required to register blueprints only after all their routes have been declared, at least if you want to use those routes. (If you don't mind the routes not being available, it doesn't look like there's actually any problem with declaring new routes after registering the blueprint.)
If you want to know why: basically, blueprint url rules are only registered on the application when Flask.register_blueprint is called. If you add routes after registering the blueprint, they just get added to the list of things to do when the blueprint is registered (Blueprint.deferred_functions), they don't get retroactively added to any existing applications that the blueprint was registered to in the past.
Though you have registered your blueprint, it is not actually registered!
the point is that your application is not aware of existence rest_server.py
You have to register it in the same file in which you have the following code:
app = Flask(__name__)
This should solve your problem.
I'd like to show the pattern of using blueprints I use.
(It is useful for a better organization of your code) :
Blueprint Pattern
your application can look like this:
/yourapplication
runserver.py
/application #your application is a package containing some blueprints!
__init__.py
models.py
/hello #(blueprint name)
__init__.py
views_file1.py
views_file2.py
your runserver.py should look like this:
# runserver.py
from application import app
app.run()
In this example, hello is a package and one of your blueprints:
# application/hello/__init__.py
from flask import Blueprint
hello = Blueprint('main', __name__)
# import views of this blueprint:
from application.hello import views_file1, views_file2
Import and register your blueprints in application/__ init__.py. your application/__ init__.py should look like this:
# application/__init__.py
from flask import Flask
from .hello import hello as hello_blueprint
app = Flask(__name__)
app.register_blueprint(hello_blueprint)
from application.models import * #your models (classes, or *)

How does python import order affect names?

I'm doing a flask tutorial (http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world) and I came upon a behaviour that I couldn't explain.
The main directory structure of the tutorial is :
microblog
|
|---- app
| |---- __init__.py
| |---- views.py
|
|---- flask
|---- run.py
and the contents of the files are :
microblog/run.py
#!flask/bin/python
from app import app
app.run(debug=True)
microblog/app/init.py
from flask import Flask
app = Flask(__name__)
from app import views
microblog/app/views.py
from app import app
#app.route("/")
#app.route("/index")
def index():
return "Hello World!"
everything works but if I transpose these two lines:
app = Flask(__name__)
from app import views
in views.py and then I execute run.py I get:
ImportError: cannot import name app
Why does that happen?
Because you're trying to import from the newly created variable app. If you want to import variable modules, then use importlib package:
my_module = importlib.import_module(app, 'view')
Contrary to what the other answer says, this is a circular import problem. app.__init__ tries to import app.views, which tries to import the app.app Flask created in app.__init__. If the Flask is created before app.__init__ imports app.views, app.views finds app.app. If the Flask is created after the import, it isn't there yet when app.views tries to find it.
Circular imports cause all sorts of horrible problems. It might be difficult, but the best way to handle them is generally to reorganize your code so there aren't circular imports.

Categories

Resources