Import Handlers - App Route with Flask - python

My File Directory:
app/
app.py
app/server/
views.py
I don't get any import errors with views, but I am not able to URL route to Views - I can only do it from app.py - how can I fix this issue? I've been stuck on this for 6 hours.
Code from app.py - how I import views
sys.path.append(os.path.join(os.path.abspath('.'), 'server'))
import views
And my url routing seems fine, so I am not sure where the problem lies:
#app.route("/login/", methods=['GET', 'POST'])
def login():
doSomething()
I feel the problem is more to do with url routing than importing files though.

Try from views import * instead of import views.
Also, instead of doing sys.path.append, add an empty file named __init__.py to the server directory, and you should be able to do something like from server.views import *.
Solution: Also make sure your view import is towards the bottom of your app file, below the app initialization and config and such.

Related

Why is flask rendering the wrong template [duplicate]

I have a Flask app with blueprints. Each blueprint provides some templates. When I try to render the index.html template from the second blueprint, the first blueprint's template is rendered instead. Why is blueprint2 overriding blueprint1's templates? How can I render each blueprint's templates?
app/
__init__.py
blueprint1/
__init__.py
views.py
templates/
index.html
blueprint2/
__init__.py
views.py
templates/
index.html
blueprint2/__init__.py:
from flask import Blueprint
bp1 = Blueprint('bp1', __name__, template_folder='templates', url_prefix='/bp1')
from . import views
blueprint2/views.py:
from flask import render_template
from . import bp1
#bp1.route('/')
def index():
return render_template('index.html')
app/__init__.py:
from flask import Flask
from blueprint1 import bp1
from blueprint2 import bp2
application = Flask(__name__)
application.register_blueprint(bp1)
application.register_blueprint(bp2)
If I change the order the blueprints are registered, then blueprint2's templates override blueprint1's.
application.register_blueprint(bp2)
application.register_blueprint(bp1)
This is working exactly as intended, although not as you expect.
Defining a template folder for a blueprint only adds the folder to the template search path. It does not mean that a call to render_template from a blueprint's view will only check that folder.
Templates are looked up first at the application level, then in the order blueprints were registered. This is so that an extension can provide templates that can be overridden by an application.
The solution is to use separate folders within the template folder for templates related to specific blueprints. It's still possible to override them, but much harder to do so accidentally.
app/
blueprint1/
templates/
blueprint1/
index.html
blueprint2/
templates/
blueprint2/
index.html
Point each blueprint at its templates folder.
bp = Blueprint('bp1', __name__, template_folder='templates')
When rendering, point at the specific template under the templates folder.
render_template('blueprint1/index.html')
See Flask issue #1361 for more discussion.
I vaguely remember having trouble with something like this early on. You haven't posted all of your code, but I have four suggestions based on what you've written. Try the first, test it, and then if it still is not working, try the next ones, but independently test them to see if they work:
First, I cant't see your views.py file, so be sure you're importing the appropriate blueprint in your views.py files:
from . import bp1 # in blueprint1/views.py
from . import bp2 # in blueprint2/views.py
Second, you may need to fix the relative import statements in __init__.py as follows (note the period preceding the subfolders):
from .blueprint1 import blueprint1 as bp1
from .blueprint2 import blueprint2 as bp2
Third, since you're hardcoding the path to your templates in your render_template function, try removing template_folder='templates' from your blueprint definition.
Fourth, it looks like you named the url_prefix for your blueprint as "/bp1" when you registered it. Therefore, if the hard coded link to your file system still does not work:
render_template('blueprint1/index.html')
then also try this and see what happens:
render_template('bp1/index.html')
Again, I can't see your full code, but I hope this helps.

How to add views to a blueprint in separate files

I have a huge application that was getting hard to update its views. To 'fix' this, I had separate the views into a few files, using blueprints. The problem is that the blueprints are also getting very big, because the long documentation that each view has and the different verifications that each view requires.
I had tried to do an import like this:
Where I have a main file that contains the Flask application (which imports the blueprint), a file that contains the blueprint and a file the imports the blueprint and configure the views in it. The problem is that with this approach the views are not rendered, because flow reasons.
The main file, in the root of a folder:
from flask import Flask
from source import test
application = Flask(__name__)
application.register_blueprint(test)
application.run()
The blueprint file, inside a subfolder in the root folder:
from flask import Blueprint
test = Blueprint('test', __name__)
The view file, inside the same subfolder as the blueprint file:
from .test import test
#test.route('/home', methods=['GET', 'POST'])
def home():
return 'home'
I had also tried to add the blueprint decorator to a declared function, this way the views are add to the blueprint in the blueprint file, but I don't think this is a good approach or a scalable approach - and it didn't work ^ - ^.
I expect to create a blueprint in a file, import the blueprint in other files and add views to the blueprint and then import the blueprint and add it to the Flask application.
You need to import the views content in blueprint file.
I have created the scenario and able to get the view. Additionally, I have updated the naming convention.
Folder structure:
.
├── app.py
└── blueprints
├── example_blueprint.py
├── example_views.py
└── __init__.py
app.py:
from flask import Flask
from blueprints.example_blueprint import bp
app = Flask(__name__)
app.register_blueprint(bp)
blueprints/example_blueprint.py:
from flask import Blueprint
bp = Blueprint('bp', __name__,
template_folder='templates')
from .example_views import *
blueprints/example_views.py:
from .example_blueprint import bp
#bp.route('/home', methods=['GET', 'POST'])
def home():
return 'home'
blueprints/__init__.py: Blank file
Output:
Running the application:
export FLASK_APP=app.py
export FLASK_ENV=development
flask run
requirements.txt:
Click==7.0
Flask==1.0.3
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
pkg-resources==0.0.0
Werkzeug==0.15.4
Reference:
Flask documentation on Blueprints
In root folder change main file:
from flask import Flask
from source.listener import test
application = Flask(__name__)
application.register_blueprint(test)
application.run()
The blueprint file, inside a subfolder in the root folder:
listener.py
from flask import Blueprint
from source.view import home
test = Blueprint('test', __name__)
test.add_url_rule('/home', view_func=home,methods=['GET', 'POST'])
The view file, inside the same subfolder as the blueprint file:
from flask import request
def home():
if request.method == 'POST':
user = request.form['name']
return "Welcome "+user
else:
return 'home'
Get Request O/P:
Home
Post Request O/P:
Welcome username
The view module isn't discovered since only the Blueprint object is imported.
From the organization of your Blueprint and particularly the import that you have shared in your main file, I can deduct the existence of an __init__.py in the blueprint folder that exports the blueprint object.
Importing the views in that file should have the app discover the views registered in the blueprint.
i.e.
blueprint/__init__.py:
from .test import test
from . import views

Flask blueprints cannot import module

I'm learning Blueprints for Flask, but I am having trouble with importing the correct modules. This is my setup:
Folder structure:
- app.py
templates/
nomad/
- __init__.py
- nomad.py
app.py
from flask import Flask
from nomad.nomad import nblueprint
app = Flask(__name__)
app.register_blueprint(nblueprint)
nomad.py
from flask import render_template, Blueprint, abort
from app import app
nblueprint = Blueprint('nblueprint', __name__, template_folder='templates')
# Routes for this blueprint
#app.route ....
__init__.py is empty
The error I'm getting: ImportError: cannot import name nblueprint. I know my import statement is probably wrong, but what should it be and why?
EDIT:
If I remove from app import app, then I can successfully import nblueprint in app.py. But I need app in nomad.py because it needs to handle routes. Why is that line causing issues with importing, and how would I get around this?
Blueprints is for define application route so you don't need to use app instance and blueprint in same place for route defination.
#nomad.py
#nblueprint.route('/')
You are getting error because while you register the blueprint at the same time you use app instance. So as you said when you remove the from app ... it solve the problem.
The recommend way is define your view for that blueprint in blueprint package in your example nomad package, it should be like this:
...
nomad/
__init__.py
views.py
#nomad/__init__.py
nblueprint = Blueprint(...)
#nomad/views.py
from . import nblueprint
#nblueprint.route('/')
...

Why doesn't this cause circular import

I have a flask app.
app.py
app = Flask(__name__)
from views import *
if __name__=="__main__":
app.run()
views.py
from app import app
#app.route('/')
def home():
return "Homepage"
So, here app.py is importing everything form views.py and views need app which is defined in app.py. But still its not causing circular import. Why?
I run this application using:
python app.py
This looks similar to the Larger Applications document which Flask allows you to do when creating apps.
From the docs:
Circular Imports
Every Python programmer hates them, and yet we just added some: circular imports (That’s when two modules depend on each other. In this case views.py depends on __init__.py). Be advised that this is a bad idea in general but here it is actually fine. The reason for this is that we are not actually using the views in __init__.py and just ensuring the module is imported and we are doing that at the bottom of the file.
If we try to follow what the program does, it is something like that:
app = Flask(__name__) # OK
from views import * # Goes into views.py
from app import app # Looks into app.py, finds it, import it
# Defines home
#app.route('/')
def home():
return "Homepage"
# import home and app, overriding app in app.py
# But views.app is the same as app.app, so it is still
# the same object
# Run main
if __name__=="__main__":
app.run()
I bet it computes something like that. Since app is defined before being imported, it's ok.

Split Python Flask app into multiple files

I'm having trouble understanding how to split a flask app into multiple files.
I'm creating a web service and I want to split the api's into different files (AccountAPI.py, UploadAPI.py, ...), just so I don't have one huge python file.
I've read that you can do this with Blueprints, but I'm not entirely sure that route is the right one for me.
Ultimately I want to run one Main python file and include other files so that when it runs, they are considered one big file.
For example if I have Main.py and AccountAPI.py I want to be able to do this:
Main.py:
from flask import Flask
import AccountAPI
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
AccountAPI.py:
#app.route("/account")
def accountList():
return "list of accounts"
I know with this example it obviously won't work, but is it possible to do something like that?
Thanks
Yes, Blueprints are the right way to do it. What you are trying to do can be achieved like this:
Main.py
from flask import Flask
from AccountAPI import account_api
app = Flask(__name__)
app.register_blueprint(account_api)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
AccountAPI.py
from flask import Blueprint
account_api = Blueprint('account_api', __name__)
#account_api.route("/account")
def accountList():
return "list of accounts"
If this is an option, you might consider using different URL prefixes for the different APIs/Blueprints in order to cleanly separate them. This can be done with a slight modification to the above register_blueprint call:
app.register_blueprint(account_api, url_prefix='/accounts')
For further documentation, you may also have a look at the official docs.
Using Blueprint you can add your routes in the routes directory.
Structure
app.py
routes
__init__.py
index.py
users.py
__init__.py
from flask import Blueprint
routes = Blueprint('routes', __name__)
from .index import *
from .users import *
index.py
from flask import render_template
from . import routes
#routes.route('/')
def index():
return render_template('index.html')
users.py
from flask import render_template
from . import routes
#routes.route('/users')
def users():
return render_template('users.html')
app.py
from routes import *
app.register_blueprint(routes)
If you want to add a new route file, say accounts.py, you just need to create the file accounts.py in the routes directory, just like index.py and users.py, then import it in the routes.__init__.py file
from .accounts import *
If you are using blueprints and want to route / redirect to a url of your blueprint inside a template you are using you need to use the correct url_for statement.
In your case if you would like to open the url account of your blueprint you have to state it like this in your template:
href="{{ url_for('account_api.account') }}"
and for the main app it would look like this:
redirect(url_for('account_api.account'))
Otherwise the werkzeug library will throw an error.
One another way to do this can be with lazy loading, where you would explicitly attach view functions on need basis.

Categories