I am trying to develop an API with different "submodules". For example there is one called todo and another one called newsletter.
What I want to do is, I'd like to be able to run the modules themselves during development and I'd like to be able to run the whole API with it's submodules on the server.
My current folder structure looks like that
api
- api
- todo
- todo
- __init__.py
- routes.py
- utils.py
- ...
- README.md
- requirements.txt
- newsletter
- ...
- run.py
The aim is to be able to run this during development:
cd api/todo/todo
python3 run.py
And this on the server
python3 run.py
The routes should be relative:
During the production the path for one submodule should be like that
/add
But on the server they should always include the name of submodule
/todo/add
Moreover I'd like to be able to put the code of every submodule in one GitHub repository, so that other persons will be able to run them on themselves.
I am currently stuck on importing the modules. Can I fix the path problem by using Flasks Blueprints?
I would appreciate any help very much!
You can use the following project structure:
app
api
-todo
-__init__.py
-other_apis.py
-newsletter
-__init__.py
-other_apis.py
__init__.py
In the app.api.todo.__init__.py:
from flask import Blueprint
todo = Blueprint("todo", __name__)
In the app.api.newsletter.__init__.py:
from flask import Blueprint
newsletter = Blueprint("newsletter", __name__)
In the app.__init__.py:
from flask import FLask
app = Flask(__name__)
from app.api.todo import todo
from app.api.newsletter import newsletter
app.register_blueprint(todo, url_prefix="/api/todo")
app.register_blueprint(newsletter, url_prefix="/api/newsletter")
if __name__ == "__main__":
app.run()
And you can change which blueprint is registered and what url prefix bound to blueprint with environment variable.
Related
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
I am taking over a Flask application that has a user module, but does not have a landing page. The structure of the project is:
|-application.py
|-manage.py
|-settings.py
|-/templates
|----base.html
|----index.html
|----navbar.html
|----/user
|--------views.py
application.py:
from flask import Flask
....
def create_app(**config_overrides):
app = Flask(__name__)
app.config.from_pyfile('settings.py')
app.config.update(config_overrides)
db.init_app(app)
from user.views import user_app
app.register_blueprint(user_app)
return app
user/views.py:
from flask import Blueprint, render_template, request, redirect, session, url_for, abort
...
user_app = Blueprint('user_app', __name__)
#user_app.route('login', methods = ('GET','POST'))
def login():
....
I placed index.html in the templates folder.
Should I place a view.py in the root directory where I would put a route to an index.html?
You can add additional routes anywhere you want.
However, since the package uses a create_app() app factory, you can't register those routes with an #app.route() decorator; the app is not created in a way you can just import.
So yes, creating a views.py module is a good organisational idea, but do create a Blueprint() there too, and register that blueprint in the create_app() function with the Flask() app instance.
In views.py:
from flask import Blueprint
bp = Blueprint('main', __name__)
#main.route('/')
def index():
# produce a landing page
and in create_app() in application.py, add
import views
app.register_blueprint(views.bp)
(I use a convention of using the bp variable name for all my blueprints, and then just importing the module and registering the module.bp attribute).
It's the explicit import and app.register_blueprint() call that ties any of the blueprints used in a Flask project into the final app's routes. Blueprints can share the same prefix, including having no prefix.
One thing to note: here the views module is now a top-level module next to application.py. It'd be better if everything was moved into a package, giving you more freedom over what names you use. All modules in a single package are namespaced, kept separate from other top-level modules such as json and time and flask, so there won't be clashes when you want to use the same name for one of the additional modules in your project.
You'd move everything but manage.py into a subdirectory, with a project-appropriate name, and move application.py to __init__.py. Imports can then use from . import ... to import from the current package, etc.
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('/')
...
this is my project structure:
- app.py
- views/
- admin/
- __init__.py
- note.py
- album.py
in views/admin/__init__.py I created a blueprint:
admin_bp = Blueprint('admin_bp', __name__, url_prefix='/admin')
and I'd like to use this blueprint in both note.py and album.py
what I've tried:
# note.py
from views.admin import admin_bp
#admin_bp.route('/note/list')
def list_notes():
pass
But it seems that the url rule is not generated at all
thanks.
Are you loading the blueprint in app.py?
from admin import admin_bp
app.register_blueprint(admin_bp)
Ensure that you are importing note.py & album.py inside admin/__init__.py.
This should then load the URLs.
If that fails it may be worth printing the contents of the URL map:
print app.url_map
Regards
How can I bundle assets using Flask-Assets that exist outside of Flasks default static/ directory?
I have npm install downloading assets into bower_components/
I have other javascripts that exist in javascripts/
I am using Flasks app factory pattern, and no matter how I've tried configuring Flask-Assets - I cannot get around the assets instance not bound to an application, and no application in current context exception.
Any help would be appreciated, especially if you can just give me an example on how to manage raw + packaged assets outside your apps static/ directory :P
app structure
app/
static/
__init__.py
assets.py
javascripts/
app.js
bower_components/
jquery.js
jquery,pjax,js
app/assets.py
from flask.ext.assets import Bundle, Environment
js = Bundle(
'bower_components/jquery.js',
'bower_components/jquery.pjax.js',
'javascripts/app.js'
filters='jsmin',
output='static/packed.js'
)
assets = Environment()
assets.register('js_all', js)
app/init.py
from flask import Flask
from app.assets import assets
app = Flask(__name__)
assets.init_app(app)
I checked Flask-Assets source and found this in the docstring of FlaskResolver class:
If a Environment.load_path is set, it is used to look up source files, replacing the Flask system. Blueprint prefixes are no longer resolved.
So you need to do the following in app/init.py:
from os.path import abspath, join
app = Flask(__name__)
assets.load_path = abspath(join(app.root_path, '..'))
assets.init_app(app)