I\'m trying to extend the flask-base project https://github.com/hack4impact/flask-base/tree/master/app. This uses the the application factory pattern in app/init.py and
Use url instead of endpoint
adm = Admin(name='test',url='/db')
You should be initializing Admin and registering views and blueprints inside create_app. Check if this works for you.
# app factory
def create_app(config_name):
# configure current app
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
# wrap app with extensions
...
# admin.init_app(app) does not work and flask-admin
# should be instantiated inside create_app()
# see https://github.com/flask-admin/flask-admin/issues/910#issuecomment-115003492
# for details
admin = Admin(app, name='MyAPP')
...
# import models
from .models.user import User
# more imports happening here
# import flask-admin views to be used in the admin panel
from .admin.views import MyView
# register admin view forms
admin.add_view(MyView(name='MyCustomView', endpoint='db'))
# register blueprints
# ...
# implementation of the app factory pattern
return app
EDIT:
What I believe is happening is that
admin living in /adminflask-admin in the app, but it clashes with the existing blueprintYou can achieve this doing two things:
blueprint name in the repo to something different from admin, since flask-admin clashes with it. (Reading from your github issue it seems the are a lot of hardcoded internals for admin.static, which makes changing the current admin blueprint easier.the anatomy of a Blueprint is kinda like this
# app/myblueprint/__init__.py
from flask import Blueprint
# a random blueprint
myblueprint = Blueprint(name='mycustomblueprint',
import_name=__name__, # name of the file
static_folder='static', # a folder inside app/myblueprint/static
template_folder='templates', # a folder inside app/myblueprint/templates
static_url_path='/static', # this is what mycustomblueprint.static will point to, and if the name is admin it will be admin.static, thus colliding with flask-admin
url_prefix='/myblueprintprefix', # this will be appended to each view inside your blueprint, i.e. a view '/foo' will get converted into '/myblueprintprefix/foo' in your url mappings
subdomain=None,
url_defaults=None,
root_path=None)
from . import views # import the views inside app/myblueprint/views.py
then, you import it inside create_app as
from .myblueprint import myblueprint as my_blueprint
app.register_blueprint(my_blueprint) # notice I've defined url_prefix in the Blueprint definition. You can do it at registration time, it's up to you
tl;dr: change the admin blueprint since it's clashing with flask-admin
flask-admin works based in views, and the pattern to generate admin views is by importing them and passing an url parameter that gets appended to the /admin endpoint (where flask-admin lives).
In this case, you can think of two flavours (more but for the sake of the example it's okay)
ModelView, which you use to create custom CRUD views and takes both a model and a db.session object. BaseView which you use to extend a generic view inside the admin blueprint used by flask-admin. This means, if you want to render your own db.html file inside the flask-admin views, you have to do:
# app/modelviews/mycustomviews.py
from flask_admin import BaseView, expose
class DBView(BaseView): # notice I'm using BaseView and not ModelView
@expose('/')
def index(self):
return self.render('modelviews/db.html') # this file should live in app/templates/modelviews/db.html
and inside create_app
# register admin view forms
from .modelviews import DBView
admin.add_view(DBView(name='MyCustomView', endpoint='db')) # this will show up in your `flask-admin` main view as MyCustomView, and it will live in {host}/admin/db
You can also check in your url_map parameter of the flask app in context that you have. You don't need this bit in your create_app
with app.app_context():
m =app.url_map
I mentioned it because it could help you debug your views inside the python repl. Import your app, and follow the gist I've provided. The url_map should return something like a list of <Rules>
[<Rule '/admin/' (OPTIONS, HEAD, GET) -> admin.index>,
<Rule '/admin/db' (OPTIONS, HEAD, GET) -> dbview.index>]
This way you can confirm that your view lives where it should. Hope this helps.