[Python] Debugging admin_base_template undefined using Flask Admin and Flask-security to...

Discussão em 'Python' iniciado por Stack, Março 3, 2025.

  1. Stack

    Stack Membro Participativo

    Attempting to build a site using Python and Flask. I had made some basic pages before tackling an admin page for the uploading of content. Currently I am using Flask-Admin v 2.0.0a0 and Flask-Security 5.6.0. The problem I have is using the flask-admin views and attempting to integrate flask-security with the security_context_processor decorator. Admin page is returning and I cannot view the db items (since I am not logged in) but when I manually go to login page I receive a jinja error: jinja2.exceptions.UndefinedError: 'admin_base_template' is undefined

    A majority of this is pulled from the flask-admin/flask-security working example from HERE but I am at a loss for what is going wrong

    The route is admin/login/ which is set in config.py as such:

    # Flask Security Config
    # Flask-Security URLs, overridden because they don't put a / at the end
    SECURITY_LOGIN_URL = "/login/"
    SECURITY_POST_LOGIN_VIEW = "/admin/"
    # Flask-Security config
    SECURITY_URL_PREFIX = "/admin"


    Below is the gist of the code and application structure:

    Directory Structure
    AppFolder
    |
    |- app.py
    |- config.py
    |- templates
    |- base.html
    |- index.html
    |- admin <
    | | - index.html
    | | - user_edit.html
    | | - post_edit.html
    |- security <
    | - login_user.html
    | - _macros.html
    | - _messages.html



    app.py (relevant parts)

    ## App and App Config
    app = Flask(__name__)
    app.config.from_pyfile("config.py")
    db = SQLAlchemy(app)
    admin = Admin(app, name='demo', theme=Bootstrap4Theme(swatch='solar'))

    # Define models
    roles_users = db.Table(
    "roles_users",
    db.Column("user_id", db.Integer(), db.ForeignKey("user.id")),
    db.Column("role_id", db.Integer(), db.ForeignKey("role.id")),
    )


    class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(255))
    last_name = db.Column(db.String(255))
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship(
    "Role", secondary=roles_users, backref=db.backref("users", lazy="dynamic")
    )
    fs_uniquifier = db.Column(db.String(64), unique=True, nullable=False)

    class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30))
    description = db.Column(db.String(255))

    def __str__(self):
    return self.name

    class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(75), nullable=False)
    content = db.Column(db.String(255), nullable=False)
    created = db.Column(db.DateTime, default=datetime.utcnow)


    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    security = Security(app, user_datastore)

    class UserView(ModelView):
    def is_accessible(self):
    return (
    current_user.is_active
    and current_user.is_authenticated
    and current_user.has_role("superuser")
    )

    def _handle_view(self, name, **kwargs):
    if not self.is_accessible():
    if current_user.is_authenticated:
    # permission denied
    abort(403)
    else:
    # login
    return redirect(url_for("security.login", next=request.url))
    edit_modal = True


    class PostView(ModelView):
    def is_accessible(self):
    return (
    current_user.is_active
    and current_user.is_authenticated
    and current_user.has_role("superuser")
    )

    def _handle_view(self, name, **kwargs):
    if not self.is_accessible():
    if current_user.is_authenticated:
    # permission denied
    abort(403)
    else:
    # login
    return redirect(url_for("security.login", next=request.url))
    edit_modal = True

    admin.add_view(UserView(User, db.session))
    admin.add_view(PostView(Post, db.session))

    def security_context_processor():
    return dict(
    admin_base_template=admin.theme.base_template,
    admin_view=admin.index_view,
    theme=admin.theme,
    h=admin_helpers,
    )



    login_user.html

    {% extends 'admin/master.html' %}

    {% block body %}
    <h1>Login</h1>
    {% endblock %}



    STACK TRACE

    127.0.0.1 - - [26/Feb/2025 14:33:10] "GET /admin/login HTTP/1.1" 308 -
    [2025-02-26 14:33:10,735] ERROR in app: Exception on /admin/login/ [GET]
    Traceback (most recent call last):
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask_security\decorators.py", line 471, in decorated
    return current_app.ensure_sync(fn)(*args, **kwargs)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask_security\views.py", line 233, in login
    return _security.render_template(
    ~~~~~~~~~~~~~~~~~~~~~~~~~^
    cv("LOGIN_USER_TEMPLATE"),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
    **_ctx("login"),
    ^^^^^^^^^^^^^^^^
    )
    ^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask_security\utils.py", line 1189, in default_render_template
    return render_template(*args, **kwargs)
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\templating.py", line 150, in render_template
    return _render(app, template, context)
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\templating.py", line 131, in _render
    rv = template.render(context)
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\jinja2\environment.py", line 1295, in render
    self.environment.handle_exception()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\jinja2\environment.py", line 942, in handle_exception
    raise rewrite_traceback_stack(source=source)
    File "C:\Users\Me\DemoApp\templates\security\login_user.html", line 1, in top-level template code
    {% extends 'admin/master.html' %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask_admin\templates\bootstrap4\admin\master.html", line 1, in top-level template code
    {% extends admin_base_template %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\templating.py", line 65, in get_source
    return self._get_source_fast(environment, template)
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\flask\templating.py", line 96, in _get_source_fast
    return loader.get_source(environment, template)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
    a2\loaders.py", line 197, in get_source
    pieces = split_template_path(template)
    File "C:\Users\Me\DemoApp\env\Lib\site-packages\jinja2\loaders.py", line 30, in split_template_path
    for piece in template.split("/"):
    ^^^^^^^^^^^^^^
    jinja2.exceptions.UndefinedError: 'admin_base_template' is undefined
    127.0.0.1 - - [26/Feb/2025 14:33:10] "GET /admin/login/ HTTP/1.1" 500 -


    I had similar errors with the post_edit and user_edit templates which resolved after adding {% extends 'admin/<ModelName>/edit.html' %} into the mentioned html pages. From what I understand the login template is where it should be and it should only extend admin/master.html. I also tried by copying the login_user.html from the linked project above along with the macros/messages html in security folder and it still gives me the same error. I am kind of at a loss and would like to understand what I am missing as far as the admin_base_template error. Please halp

    Edit

    I am unsure what this means but after copying over the login_user.html from the source project and adding the decorator on security.context_processor it fails on the third line but boils down to the same error. I removed the line but it would fail on whatever I put there pointing first to the 3rd line then to the stack trace error of extends admin_base_template ... admin_base_template undefined.

    For reference the line that I see changing in the stack trace is {% include "security/_messages.html" %} of login_user.html but if I remove that or add an empty newline it still says line 3.

    Continue reading...

Compartilhe esta Página