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.
Related
I have been following the flask mega tutorial form Miguel grinberg and the very first "Hello World!" program is confusing me.
More specifically it is the import of the routes module from the init.py module that is confusing me.
Below is the init.py file:
#__init__.py file:
from flask import Flask
app = Flask(__name__)
from app import routes
# above line is the source of confusion.
Below is the routes.py file
from app import app
#app.route('/')
#app.route('/index')
def index():
return "Hello, world!"
Now if I understand correctly, app is an object of class Flask. when we do "from app import app" in routes.py, I understand that we are importing the app object created in init.py file.
The code then follows is registering a route for this object.
So my question is why do we need to import this routes module in init.py?
I mean in routes module, the app object has been imported and a route has been registered on it. So this should reflect on the app object created in init.py. So why do we need to import it?
I know that it does not work if we remove the import routes statement. But want to know why.
Edit: Though I have a programming background, I am new to python. So it might be misunderstanding on how python files are executed when projects are executed. Also I think this has to do something with python being an interpreted language.
When you import anything in python, it actually runs the entire file that you are importing. The __init__.py file does not have any information about the routes so by importing it you are essentially providing that information to the app object. In addition, this routes file is never directly ran so that is the only way the views are actually created.
Hope this helps!
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 *)
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).
My project structure is like below
run.py
lib/
mysite/
conf/
__init__.py (flask app)
settings.py
pages/
templates/
index.html
views.py
__init__.py
This is mysite.conf.__init__
from flask import Flask
app = Flask(__name__)
app.debug = True
My idea is to now import app to every other module to use it to create views. Here in this case there is a module pages.
In pages.views I have some code like
from flask import render_template
from mysite.conf import app
#app.route('/')
def index():
return render_template('index.html')
The index.html is placed in pages/templates
When I run this app from run.py which is like below
from mysite.conf import app
app.run()
I'm getting template not found error.
How to fix it? and why is this happening!
I'm basically a django guy, and facing a lot of inconvenience with importing the wsgi object every time to create a view in every module! It kinda feels crazy -- Which in a way encourages circular imports. Is there any way to avoid this?
Flask expects the templates directory to be in the same folder as the module in which it is created; it is looking for mysite/conf/templates, not mysite/pages/templates.
You'll need to tell Flask to look elsewhere instead:
app = Flask(__name__, template_folder='../pages/templates')
This works as the path is resolved relative to the current module path.
You cannot have per-module template directories, not without using blueprints. A common pattern is to use subdirectories of the templates folder instead to partition your templates. You'd use templates/pages/index.html, loaded with render_template('pages/index.html'), etc.
The alternative is to use a Blueprint instance per sub-module; you can give each blueprint a separate template folder, used for all views registered to that blueprint instance. Do note that all routes in a blueprint do have to start with a common prefix unique to that blueprint (which can be empty).
I ran in to this problem as well being brand new to Flask.
The solution for my situation was to create an __init__.py file in the main app directory so as to turn app/ in to a module since, as Martijn Pieters pointed out, flask expects templates to be in the main module directory by default. And to restate from his answer, you can reassign the default directory when instantiating the Flask class, e.g. Flask(__name__, template_folder=any/relative/path/from/app/dir/or/absolute/path/youd/like)
A simple directory structure should therefore look like this:
app/
run.py
templates/
sample_template.html
__init__.py # <---- This was the missing file in my case.
... where app.py might look like this:
from flask import Flask, render_template
app = Flask(__name__) # or e.g. Flask(__name__, template_folder='../otherdir')
#app.route("/")
def home():
return "Hello world"
#app.route("/hello/again")
def hello_again():
return render_template("hello_again.html")
if __name__ == "__main__":
app.run()
I'm pretty sure you made a mistaking spelling "template" on main folder. Just rename it
or:
do something like this (template_folder = 'the name of the folder your file belongs to')
from flask import Blueprint
from flask import render_template
views = Blueprint('views',__name__,template_folder='tamplate')
#views.route('/')
def home():
return render_template("home.html")
I have been learning flask/ python from this tutorial http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
This blog is pretty good and it explain very well. In the first tutorial, if you notice,
he asks us to create a init.py file, a views.py file and a main run.py file.
root
/microblog
/apps
/__init__.py
views.py
I created the two files. He asks us to create a run.py file and put it in the root file. then
chmod a+x run.py
./run.py
It says the file does not exist.
If I,
python run.py
It says App module not defined.
I cannot figure out the problem, I put the run.py file in all the files, it doesnt not work what so ever.
I will also include the code so that it would be easier to answer instead of going to the above link
init.py
from flask import Flask
app = Flask(__name__)
from app import views
views.py
from app import app
#app.route('/')
#app.route('/index')
def index():
return 'Hello world'
run.py
#!flask/bin/python
from app import app
app.run(debug = True)
My questions:
Where should I put the run.py file?
Why are we creating different files? Why cant all of them be in one
full file?
init.py -->
he is importing flask which is normal. then assigning app =
(name). why is that? Then why is he importing views from apps?
views.py -->
from app import app? is app an existing module here or the one we
just created? what does #app.route('/') or
#app.route('/index')do?
Can some one put the code together and explain it?
It says App module not defined
You misspelled package name: you have apps in your directory tree and you try to import app
Where should I put the run.py file?
Anywhere you want as long app is in PYTHONPATH. Or you can put it inside microblog directory.
he is importing flask which is normal. then assigning app = (name). why is that?
# Create reference to flask WSGI application object
app = Flask(__name__)
Why? Because you need application to run. See official docs: Flask object
Then why is he importing views from apps?
from app import views
means: From package named app import module named views
Naming convention could be probably different but if you don't see the difference you should probably spend more learning python basics before starting with more sophisticated stuff.
from app import app? is app an existing module here or the one we just created? what > does #app.route('/') or #app.route('/index')do?
#app.route('/')
def index():
return 'Hello world'
Short answer: if app receives request for url '/' responds using function foo
For more see official docs: add_url_rule and URL Route Registrations
Update
Why are we creating different files? Why cant all of them be in one full file?
Actually nothing stops you from putting everything inside one file but most of the time it is really bad idea. If you ask about reasoning in this specific example it is mostly about separating modules that have different responsibilities.