Wrong dashboard while adding flask-admin to project

前端 未结 2 2276
庸人自扰
庸人自扰 2021-02-19 18:32

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

2条回答
  •  逝去的感伤
    2021-02-19 18:49

    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

    • The app in the repo has already a blueprint named admin living in /admin
    • You want to implement flask-admin in the app, but it clashes with the existing blueprint

    You can achieve this doing two things:

    1. Change the current 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

    1. 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

     [ admin.index>,
      dbview.index>]
    

    This way you can confirm that your view lives where it should. Hope this helps.

提交回复
热议问题