Flask blueprint doesn't work without prefix - python

Hi I have a Flask app structured in following way and I have problem with blueprints setup. Whatever I do, they only work with url_prefix set up. It works currently as /main/verify but as it is a small app I would love to have an endpoint like /verify. What's interesting I managed to make it work with / route, but for the same configuration it didn't work for the /verify. I am pretty clueless right now, I can live with it as it is, but I really wonder what am I doing wrong.
Here is the code:
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
from main import main
app.register_blueprint(main)
return app
main/__init__.py
from flask import Blueprint
main = Blueprint('main', __name__, url_prefix='/main')
from . import views
main/views.py
from flask import request, jsonify
from . import main
#main.route('/')
def index():
return "Hello world"
#main.route('/verify')
def verify():
url = request.args['url']
query = request.args['query']
return jsonify({ ... })

As I see you didn't register blueprint without prefix. If you need to register endpoints without prefix you must create a new instance of Blueprint
main = Blueprint('main', __name__, url_prefix='/main')
# main endpoints(with prefix /main)...
#main.route('/')
def index_main():
return "Hello world from /main/"
# routes without any prefix
default = Blueprint('default', __name__)
#default.route('/')
def index():
return "Hello world from /"
app = Flask(__name__)
app.register_blueprint(main)
app.register_blueprint(default)
Hope this helps.

Related

Passing python objects from main flask app to blueprints

I am trying to define a mongodb object inside main flask app. And I want to send that object to one of the blueprints that I created. I may have to create more database objects in main app and import them in different blueprints. I tried to do it this way.
from flask import Flask, render_template
import pymongo
from admin_component.bp1 import bp_1
def init_db1():
try:
mongo = pymongo.MongoClient(
host='mongodb+srv://<username>:<passwrd>#cluster0.bslkwxdx.mongodb.net/?retryWrites=true&w=majority',
serverSelectionTimeoutMS = 1000
)
db1 = mongo.test_db1.test_collection1
mongo.server_info() #this is the line that triggers exception.
return db1
except:
print('Cannot connect to db!!')
app = Flask(__name__)
app.register_blueprint(bp_1, url_prefix='/admin') #only if we see /admin in url we gonna extend things in bp_1
with app.app_context():
db1 = init_db1()
#app.route('/')
def test():
return '<h1>This is a Test</h1>'
if __name__ == '__main__':
app.run(port=10001, debug=True)
And this is the blueprint and I tried to import the init_db1 using current_app.
from flask import Blueprint, render_template, Response, request, current_app
import pymongo
from bson.objectid import ObjectId
import json
bp_1 = Blueprint('bp1', __name__, static_folder='static', template_folder='templates')
print(current_app.config)
db = current_app.config['db1']
But it gives this error without specifying more details into deep.
raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
Can someone point out what am I doing wrong here??
The idea you are attempting is correct; however it just needs to be done a little differently.
First, start by declaring your mongo object in your application factory:
In your app/__init__.py:
import pymongo
from flask import Flask
mongo = pymongo.MongoClient(
host='mongodb+srv://<username>:<passwrd>#cluster0.bslkwxdx.mongodb.net/?retryWrites=true&w=majority',
serverSelectionTimeoutMS = 1000
)
# Mongo is declared outside of function
def create_app(app):
app = Flask(__name__)
return app
And then in your other blueprint, you would call:
from app import mongo # This right here will get you the mongo object
from flask import Blueprint
bp_1 = Blueprint('bp1', __name__, static_folder='static', template_folder='templates')
db = mongo

Flask Restplus - The requested URL was not found on the server

I have a flask application and I'm trying to use flask-restplus and blueprints. Unfortunately my api endpoint always returns The requested URL was not found on the server. even though I can see that it exists in the output of app.url_map.
The project is laid out as follows:
- app.py
- api
- __init__.py
- resources.py
app.py
from api import api, api_blueprint
from api.resources import EventListResource, EventResource
app = Flask(__name__)
app.register_blueprint(api_blueprint)
db.init_app(flask_app)
app.run()
api/__init__.py
from flask_restplus import Api
from flask import Blueprint
api_blueprint = Blueprint("api_blueprint", __name__, url_prefix='/api')
api = Api(api_blueprint)
api/resources.py
from flask_restplus import Resource
from flask import Blueprint
from . import api, api_blueprint
#api_blueprint.route('/events')
class EventListResource(Resource):
def get(self):
"stuff"
return items
def post(self):
"stuff"
db.session.commit()
return event, 201
The application starts without issue and I can see that '/api/events' appears in app.url_map so I'm not really sure why the url can't be found. Any help appreciated, thanks!
Flask-RESTPlus provides a way to use almost the same pattern as Flaskā€™s blueprint. The main idea is to split your app into reusable namespaces.
You can do it this way:
app.py
from flask_restplus import Api
from api import api_namespace
app = Flask(__name__)
api = Api(app)
db.init_app(flask_app)
from api import api_namespace
api.add_namespace(api_namespace, path='/api')
app.run()
api/init.py
from flask_restplus import Namespace
api_namespace = Namespace('api_namespace')
api/resources.py
from flask_restplus import Resource
from api import api_namespace
#api_namespace.route('/events')
class EventListResource(Resource):
def get(self):
"stuff"
return items
def post(self):
"stuff"
db.session.commit()
Here is the link to documentation:
https://flask-restplus.readthedocs.io/en/stable/scaling.html

Extend a blueprint in Flask, splitting it into several files

In flask, I have a blueprint that is getting a bit too long and I'd like to split it into several files, using the same route /games
I tried extending the class, but it doesn't work?
# games.py
from flask import Blueprint
bp = Blueprint('games', __name__, url_prefix='/games')
#bp.route('/')
def index():
...
.
# games_extend.py
from .games import bp
#bp.route('/test')
def test_view():
return "Hi!"
Am I doing something wrong or is there a better way?
You can make it work using absolute path names (packages), here's how:
app.py
from __future__ import absolute_import
from flask import Flask
from werkzeug.utils import import_string
api_blueprints = [
'games',
'games_ext'
]
def create_app():
""" Create flask application. """
app = Flask(__name__)
# Register blueprints
for bp_name in api_blueprints:
print('Registering bp: %s' % bp_name)
bp = import_string('bp.%s:bp' % (bp_name))
app.register_blueprint(bp)
return app
if __name__ == '__main__':
""" Main entrypoint. """
app = create_app()
print('Created app.')
app.run()
bp/init.py
bp/games.py
from __future__ import absolute_import
from flask import Blueprint, jsonify
bp = Blueprint('games', __name__, url_prefix='/games')
#bp.route('/')
def index():
return jsonify({'games': []})
bp/games_ext.py
from .games import bp
#bp.route('/test')
def test_view():
return "Hi!"
Start your server using: python -m app
Then send Get queries to /games/ and /games/test/ endpoints. Worked for me.
Cheers !
In latest version of Flask, it supports Nested Blueprints
They can now be successfully divided into multiple files and imported into the parent one. Additionally, note the url_prefix parameter which can be used to divide files based on functionality but with same routes in different files.

Flask python app failing to get app object after initializing

app_instance.py
from app import FlaskApp
app = None
def init_instance(env):
global app
app = FlaskApp(env)
def get_instance():
assert app is not None
return app
FlaskApp class is pretty much like this
class FlaskApp(object):
def __init__(self, env):
self.oauth_manager = .... bla bla ..
self.clients_manager = .. bla bla ..
app = Flask(__name__)
app.config.from_object(env)
app = app_wrapper.wrap(app, app.config['NUM_PROXY_SERVERS'])
self.app = app
self.api = Api(self.app, prefix='/v3', default_mediatype='application/json')
self.define_routes()
# Initialize the DB
self.db = Database(self.app)
fmt = "%(asctime)s - %(request_id)s - %(name)s - %(levelname)s - %(message)s"
logging.basicConfig(format=fmt, level=self.app.config.get('LOG_LEVEL'))
request_id.init(app, prefix='MY_API_', internal=False)
def run_server(self):
self.app.run(host=self.app.config['HOST'], port=self.app.config['PORT'], debug=self.app.config['DEBUG'])
def define_routes(self):
# Configure Api Resources
self.api.add_resource(VersionListController, '/my/route', endpoint='versions')
more routes here
self.api.init_app(self.app)
in my app controller
def is_valid_oauth_token(request):
from mobile_module import app_instance
app = app_instance.get_instance()
# more code here
I'm running the app on localhost and getting
assert app is not None
AssertionError
How can "fix" this code? should I be importing from mobile_module import app_instance in every route access? suggestions please
I should state that this app works in production well behind a Nginx
I guess my question is more about python (how to make this work) and less in flask.
The problem is not related to get_instance or init_instance(create_app etc.).
Flask has different states. App will work in out of request context when you initialize app instance(FlaskApp(env)).
As I see in your example, you try to get a application in context of request(def is_valid_oauth_token(request)). It means that is not initialization of application. This is processing while a request is active. This is other state of application - app was created and work in context of some request. In this case you can get application instance using from flask import current_app.
To better understanding how it works/use I recommend to read about flask._app_ctx_stack, app_context() and flask.g.
Hope this helps.
I think the best way to devellop a flask app simple is to follow the official documentation about simple flask project structure here
you need to organize your floder like this :
/yourapplication
/yourapplication
__init__.py
/static
style.css
/templates
layout.html
index.html
login.html
...
and then create your application in init.py file like as follow:
from flask import Flask
def create_app():
"""this method will initialise the flask Ap instance """
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
return app
in your yourapplication directory add the run.py to run the app with the following code :
from yourapplication import create_app
app = create_app()
if __name__ == '__main__':
app.run()
and if you want to use your controller you can do this:
from yourapplication import create_app
def is_valid_oauth_token(request):
app = create_app()
# more code here
this is called application factory design-pattern.
And in addition if you want to put it in production you will need to use WSGI configuration find more here

Flask, Blueprint, current_app

I am trying to add a function in the Jinja environment from a blueprint (a function that I will use into a template).
Main.py
app = Flask(__name__)
app.register_blueprint(heysyni)
MyBluePrint.py
heysyni = Blueprint('heysyni', __name__)
#heysyni.route('/heysyni'):
return render_template('heysyni.html', heysini=res_heysini)
Now in MyBluePrint.py, I would like to add something like :
def role_function():
return 'admin'
app.jinja_env.globals.update(role_function=role_function)
I will then be able to use this function in my template. I cannot figure out how I can access the application since
app = current_app._get_current_object()
returns the error:
working outside of request context
How can I implement such a pattern ?
The message error was actually pretty clear :
working outside of request context
In my blueprint, I was trying to get my application outside the 'request' function :
heysyni = Blueprint('heysyni', __name__)
app = current_app._get_current_object()
print(app)
#heysyni.route('/heysyni/')
def aheysyni():
return 'hello'
I simply had to move the current_app statement into the function. Finally it works that way :
Main.py
from flask import Flask
from Ablueprint import heysyni
app = Flask(__name__)
app.register_blueprint(heysyni)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
Ablueprint.py
from flask import Blueprint, current_app
heysyni = Blueprint('heysyni', __name__)
#heysyni.route('/heysyni/')
def aheysyni():
# Got my app here
app = current_app._get_current_object()
return 'hello'

Categories

Resources