pallets-eco / flask-admin

Simple and extensible administrative interface framework for Flask
https://flask-admin.readthedocs.io
BSD 3-Clause "New" or "Revised" License
5.8k stars 1.58k forks source link

Custom blueprint for static content #1849

Closed jm66 closed 3 years ago

jm66 commented 5 years ago

My current application already has an admin blueprint and I intent to implement flask-admin with bp admin_ui and url=/admin-ui. However, if I don not replace admin.static with admin_ui.static in flask_admin/templates/bootstrap3/admin/static.html I get #1530 error and cannot load the index view.

I'm using the application factory pattern as follows:

# flask admin
admin_ui = Admin(
    endpoint='admin_ui', url='/admin-ui',
    template_mode='bootstrap3',
)

def create_app(config_name=None, main=True, is_celery=False):
.
.
.
        # Admin UI
        admin_ui.init_app(app)
        admin_ui.template_mode = 'bootstrap3'
        admin_ui.name = app.config['APP_NAME'] + ' Admin UI'
.
.

       admin_ui.index_view = ApiAdminIndexView(
            url='/admin-ui', endpoint='admin_ui'
        )

Any ideas or thoughts are appreciated. Thanks.

bekab95 commented 5 years ago

I don't know the answer but are you talking about dynamic content admin and separate admin for static content ?

jm66 commented 5 years ago

It could be the same endpoint. What I'm looking for is to serve flask-admin from a given "endpoint", i.e. /admin-ui and also flask-admin static content from admin_ui.static(/admin-ui/static) instead of admin.static (/admin/static) which is set by default in static.html.

bekab95 commented 5 years ago

I need to know the idea behind static content and UI, I needed such feature when you can fill static content and manage it from flask-admin alongside dynamic content

jm66 commented 5 years ago

@ufo911 please, correct me if I'm wrong:

By creating the admin interface Admin(name="Example: Simple Views", template_mode='bootstrap3', endpoint='flask_admin', url='/flask-admin'), flask-admin will be available at /flask-admin. Then, at this point there's no /admin url or admin endpoint, thus a 500 werkzeug.routing.BuildError is thrown. See the following example based on flask-admin/examples/simple:

from flask import Flask
from flask_admin import AdminIndexView
import flask_admin as admin

# Create custom admin view
class MyAdminView(admin.BaseView):
    @admin.expose('/')
    def index(self):
        return self.render('myadmin.html')

class AnotherAdminView(admin.BaseView):
    @admin.expose('/')
    def index(self):
        return self.render('anotheradmin.html')

    @admin.expose('/test/')
    def test(self):
        return self.render('test.html')

# Create flask app
app = Flask(__name__, template_folder='templates')
app.debug = True

# Flask views
@app.route('/')
def index():
    return '<a href="/flask-admin/">Click me to get to Admin!</a>'

# Create admin interface
admin = admin.Admin(
    name="Example: Simple Views", template_mode='bootstrap3',
    endpoint='flask_admin', url='/flask-admin',
    )
admin.index_view = AdminIndexView()
admin.add_view(MyAdminView(name="view1", category='Test'))
admin.add_view(AnotherAdminView(name="view2", category='Test'))
admin.init_app(app)

if __name__ == '__main__':

    # Start app
    app.run()

Error:

werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'admin.static' with values ['filename', 'v']. Did you mean 'flask_admin.static' instead?

Ideally, if I set endpoint='flask_admin', url='/flask-admin', the static template flask_admin/templates/bootstrap3/admin/static.html will take whatever the endpoint is set in order to successfully resolve {{ get_url('admin.static', *varargs, **kwargs) }}.

bekab95 commented 5 years ago

As I know, when you init flask-admin it creates blueprint for each view. you are creating two admins for app and that seems unclear.

jm66 commented 5 years ago

@ufo911 would you mind pointing where I am creating two admins? I'm just adding a few lines to the flask-admin/examples/simple/app.py example, specifically these:

admin = admin.Admin(
    name="Example: Simple Views", template_mode='bootstrap3',
    endpoint='flask_admin', url='/flask-admin',
    )
bekab95 commented 5 years ago

you are exposing "/" in two ModelView and that is the problem

jackwardell commented 4 years ago

I have the same problem.

Is the issue not that the endpoint registered at the blueprint level is flask_admin whereas the jinja2 snippet is looking for the endpoint admin?

I am doing the same:

flask_admin = Admin(app, name='flask_admin', template_mode='bootstrap4', endpoint='flask_admin', url='/flask-admin')

Keep getting thrown:

werkzeug.routing.BuildError: Could not build url for endpoint 'admin.static' with values ['filename', 'v']. Did you mean 'flask_admin.static' instead?

This jinja2 macro in the traceback is as follows:

{% macro url() -%}
    {{ get_url('admin.static', *varargs, **kwargs) }}
{%- endmacro %}

where get_url is defined as:

def get_url(endpoint, **kwargs):
    """
        Alternative to Flask `url_for`.
        If there's current administrative view, will call its `get_url`. If there's none - will
        use generic `url_for`.

        :param endpoint:
            Endpoint name
        :param kwargs:
            View arguments
    """
    view = get_current_view()

    if not view:
        return url_for(endpoint, **kwargs)

    return view.get_url(endpoint, **kwargs)

I don't think this is right, the 'admin' endpoint is not what was registered as the endpoint when initializing the Admin class