For the past two days I've been trying to intergrate flask-admin to my already existing flask application. But the problem is that I keep getting the same error:
builtins.AssertionError
AssertionError: A name collision occurred between blueprints <flask.blueprints.Blueprint object at 0x000001D8F121B2B0> and <flask.blueprints.Blueprint object at 0x000001D8ECD95A90>. Both share the same name "admin". Blueprints that are created on the fly need unique names.
and that error comes from this block of lines:
Main flask application:
app.route("/admin")
def admin():
if not session.get('logged_in'):
return redirect(url_for('login'))
return adminScreen.adminPage()
admin.py
def adminPage():
admin=Admin(app)
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Role, db.session))
admin.add_view(ModelView(PointOfSale, db.session))
return admin
And what I want to do is to manage the users that I already have in my database by using the functions that flask-admin provide.
So my question is; is there a simple way to route flask-admin to my pre-existing flask application?
P.S I already know that there is this post from May of 2018, but I have no idea how to implement the solution that was provided.
You don't have to create an app.route("/admin") yourself. That is provided by the built-in blueprint from flask-admin.
In order to use blueprints correctly you should update your app to use app factory instead global variable. Otherwise you cannot have multiple instances of the application.
In existing project it may require some work to do but it's worth it.
Example factory may looki like this:
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
You can find more information here:
http://flask.pocoo.org/docs/1.0/patterns/appfactories/
Related
In my Python Flask app I have Blueprint Routes defined that correspond to API endpoints,
# Submit Agreement (Insert or Update)
#bp.route('submitAgreement', methods=['POST'])
#auth.login_required
def submitAgreement():
#...code...
# Get Existing Agreement
#bp.route('fetchAgreement', methods=['POST'])
#auth.login_required
def fetchAgreement():
#...code...
I need to define a common route pass-through or filter that will perform authorization prior to executing the code. The authorization needs to be, if the URL contains the param id=.., check that that ID belongs to the logged-in user.
Is there a way to define a custom "aspect" or filter with this code in Python Flask?
Flask offers an
#app.before_request decorator
You can substitute app for bp to apply the function you define to just the blueprint.
I have a site built with Flask. It has several sections, each with a dedicated blueprint. The templates in each blueprint extend a base template, which has the basic layout for each page, including a navigation bar with tabs for each section.
I'd like to have the base template highlight the current tab, so it needs to know which blueprint's view is handling the request.
One way I came up with to do this is to add a before_request handler to each blueprint and store the name in g:
bp = Blueprint('blog', __name__, url_prefix='/blog')
#bp.before_request
def set_bp_name():
g.section = 'blog'
But Flask must know which blueprint is handling a request (if any) and the blueprint, of course, knows its own name. Is there a way for the template to fetch the current blueprint's name that doesn't require modifying each blueprint?
Yes. Quite simply: request.blueprint.
The request object is one of a few (along with g) that Flask makes available to all templates. It contains the blueprint property, which is the name of the blueprint handling the current request.
I'm currently working on a web app where I'm using Flask and the Flask-User extension to handle authorization. At the moment I have something like this:
#application.route('/dummy')
#roles_required('Admin')
#login_required
def dummy():
in my views.py file and something like this:
{% if current_user.is_authenticated and current_user.has_roles('Admin') %}
in my templates.
Now, there's been a few times where I've changed my mind in terms of role names and then had to search through the whole project to find and replace those usages. I wanted to define something like a ADMIN_ROLE global that can be accessed inside my views.py or any templates. I'd then just change a config file whenever I wanted to change a role's name.
I tried using my config.py setting ADMIN_ROLE = "Admin" and writing #roles_required(current_app.config['ADMIN_ROLE']) but that gives me the following error:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.
so that should be wrong. What would be the most correct way to accomplish what I'm trying?
As it says, you can only access config from within the app context. Normally, you do this:
with current_app.app_context():
admin_role = current_app.config['ADMIN_ROLE']
Because you're doing this in a decorator, I don't believe there's anyway to do that. I would suggest just using a separate module. Now, it doesn't appear that you can use python import statements in jinja, so we'll still use app.config for that. Basically we'll create a module with the desired roles and then import that into the config file and your routes file.
roles.py
ADMIN = "Admin"
USER = "User"
config.py
from roles import ADMIN, USER
ADMIN_ROLE = ADMIN
USER_ROLE = USER
routes.py
from roles import ADMIN, USER
#application.route('/dummy')
#roles_required(ADMIN)
#login_required
def dummy():
views.py
{% if current_user.is_authenticated and current_user.has_roles(app.config['ADMIN_ROLE']) %}
Any help on how to use login_view for each blueprint? I did a search on Google, your blogs, and every possible sources but didn't find any working examples.
I have 4 blueprints as below:
admin(__init__, route.py)
customer(__init__, route.py)
partners(__init__, route.py)
auth(__init__, route.py)
auth is going to handle as a central point for different type(social+regular) of authentication.
And I am using #login_required for all the possible routes under different profiles.
But the problem is; login_manager.login_view only allows me to setup only one login view. I want to have separate login_views so that my respective authorization can be redirected to respective blueprints and so on and I can have a clear control on who(role) is logging in and it's respective route.
I only found something
#LoginManager.login_view blueprint_login_views
that when unauthorized() is called it can first check blueprint_login_views and if not set then login_views is checked and then "HTTP 401 (Unauthorized) error" is raised if nothing is set. But there is no working example how to set blueprint_login_views through login_manager. Please help.
OP's original answer properly formatted:
I myself could solve this now. I removed "login_manager.login_view"
and added the below block in app/init.py after the blueprints are
loaded.
login_manager.blueprint_login_views = {
'partners': '/partner/login',
'customers': '/customer/login',
'admin' : '/admin/login',
}
The answer above works great. If you have two tables that you need to query from for each blueprint authentication, you can do:
#login_manager.user_loader
def load_user(user_id):
x = Users.query.get(str(user_id))
if x == None:
x = Admins.query.get(str(user_id))
return x
This resides where you declare the flask app instance typically init.py file(not empty)
I have a flask application that looks somewhat like this:
app.py
blueprints/
www.py
shop.py
app.py imports blueprint objects from each of the files in the blueprints directory and registers them with the Flask object in app.py with an appropriate subdomain (also imported from the file). Each blueprint registers error handlers, however these are only invoked when a view manually calls abort(), not by general errors (i.e. calling a non existent URL on the subdomain managed by shop.py invokes the error handler on app.py instead.)
Is there any way to force flask to pass errors to the blueprint that is handling the subdomain in which that error is occurring?
Flask's documentation says that this is not possible for 404s and 500s. If you need this functionality you might be able to use a wildcard route in your blueprint to handle 404s:
#a_blueprint.route("<path:invalid_path>")
def missing_resource(invalid_path):
return "There isn't anything at " + invalid_path, 404
You can use current_app and put it in the blueprints. Something like:
shop.py
from flask import current_app
#current_app.errorhandler(404)
def page_not_found(e):
return redirect(url_for('shop.index'))