Flask-admin 自定义后台模板
可能有些人不喜欢原始的管理后台,虽然看起来还挺干净简练的,不是我要的样子,可以自定义吗?
答案当然是可以的。
最好是自己通过github下载flask-admin源码,然后自己查看一下后台的源码走向。
通过这张图,我们也可以了解到模板中,最底层的admin/base.html,其他模板都是通过继承去根据宏去改写具体的显示的。
admin/master.html文件里就是直接引用base.html 没有其他的东西:
{% extends admin_base_template %}
如果我们要改写这个后台的模板,是不是我们只要拿到相应的标签就可以改造了,标签主要就是组件及其数据的html,说白就是wTF在后台生成的代码嵌到模板上,当然,你也可以完全改写了,那也就没有必要用flask-admin的意义了。
我们在base.html 里面看到引入两个其他文件:
{% import 'admin/layout.html' as layout with context -%}
{% import 'admin/static.html' as admin_static with context %}
layout.html
文件是最关键的布局文件
layout.html
主要是定义了菜单的宏:菜单的icon,菜单的遍历显示,菜单的扩展链接,菜单的提示信息(增删改后的提示信息)
还有一个重要的lib.html文件是一个库文件,预定义一些样式和组件,也是可以直接拿来用的。
在base.html 可以看到:
{% block main_menu %}
<ul class="nav navbar-nav">
{{ layout.menu() }}
</ul>
{% endblock %}
就是菜单直接嵌入layout.html的菜单,所以我们可以直接改base.html 包括layout.html 也给修改成我们的就是实现后台模板的整体修改。
可以直接在
Template目录建立目录admin,创建mybase.html,mylayout.html
然后注册模板到flask-admin:
admin = Admin(app, name='cleanblog', template_mode='bootstrap3', base_template='admin/mybase.html')
只需要两步就能解决问题,其实还有一步就是你要找到一个合适的模板:
我们可以去
https://startbootstrap.com/te…
下载一套自己觉得还可以的bootstrap样式,最好是bootstrap样式的,原因是这样可以减少一些修改设置样式冲突。
我们分几步进行整合
1)寻找模板,并把文件放到static静态目录下:
以startbootstrap-sb-admin-2-gh-pages模板为例:(可以直接百度搜到)
拷贝压缩包的三个目录到static下:dist,js,vendor
2)在template目录建立目录admin并新建文件 mybase.html,和mylayout.html
1.1 mylayout.html
在复制原先的代码进行修改:
{% macro menu(menu_root=None) %}
{% if menu_root is none %}{% set menu_root = admin_view.admin.menu() %}{% endif %}
{%- for item in menu_root %}
{%- if item.is_category() -%}
{% set children = item.get_children() %}
{%- if children %}
{% set class_name = item.get_class_name() %}
{%- if item.is_active(admin_view) %}
<li class="active dropdown">
{% else -%}
<li class="dropdown">
{%- endif %}
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">
{% if item.class_name %}<span class="{{ item.class_name }}"></span> {% endif %}{{ item.name }}<b class="caret"></b>
</a>
<ul class="dropdown-menu">
{%- for child in children -%}
{% set class_name = child.get_class_name() %}
{%- if child.is_active(admin_view) %}
<li class="active{% if class_name %} {{class_name}}{% endif %}">
{% else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{%- endif %}
<a href="{{ child.get_url() }}"{% if child.target %} target="{{ child.target }}"{% endif %}>{{ menu_icon(child) }}{{ child.name }}</a>
</li>
{%- endfor %}
</ul>
</li>
{% endif %}
{%- else %}
{%- if item.is_accessible() and item.is_visible() -%}
{% set class_name = item.get_class_name() %}
{%- if item.is_active(admin_view) %}
<li class="active{% if class_name %} {{class_name}}{% endif %}">
{%- else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{%- endif %}
<a href="{{ item.get_url() }}"{% if item.target %} target="{{ item.target }}"{% endif %}>{{ menu_icon(item) }}{{ item.name }}</a>
</li>
{%- endif -%}
{% endif -%}
{% endfor %}
{% endmacro %}
修改为:
{% macro menu(menu_root=None) %}
{% if menu_root is none %}{% set menu_root = admin_view.admin.menu() %}{% endif %}
{%- for item in menu_root %}
{%- if item.is_category() -%}
{% set children = item.get_children() %}
{%- if children %}
{% set class_name = item.get_class_name() %}
{%- if item.is_active(admin_view) %}
<li class="active">
{% else -%}
<li>
{%- endif %}
<a href="#"><i class="fa fa-bar-chart-o fa-fw"></i> {{ item.name }}<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
{%- for child in children -%}
{% set class_name = child.get_class_name() %}
{%- if child.is_active(admin_view) %}
<li class="active">
{% else %}
<li>
{%- endif %}
<a href="{{ child.get_url() }}" {% if child.target %} target="{{ child.target }}"{% endif %}>{{ menu_icon(child) }}{{ child.name }}</a>
</li>
{%- endfor %}
</ul>
</li>
{% endif %}
{%- else %}
{%- if item.is_accessible() and item.is_visible() -%}
{% set class_name = item.get_class_name() %}
{%- if item.is_active(admin_view) %}
<li class="active{% if class_name %} {{class_name}}{% endif %}">
{%- else %}
<li{% if class_name %} class="{{class_name}}"{% endif %}>
{%- endif %}
<a href="{{ item.get_url() }}"{% if item.target %} target="{{ item.target }}"{% endif %}><i class="fa fa-dashboard fa-fw"></i> {{ menu_icon(item) }}{{ item.name }}</a>
</li>
{%- endif -%}
{% endif -%}
{% endfor %}
{% endmacro %}
主要是根据模板的菜单样式进行修改。
修改之后修改
mybase.html 把所有应的base.html 拿过来修改:
{% block head_css %} {% endblock %}
增加
<!-- MetisMenu CSS -->
<link href="{{ url_for('static', filename='vendor/metisMenu/metisMenu.min.css')}}" rel="stylesheet">
<!-- Custom CSS -->
<link href="{{ url_for('static',
filename='dist/css/sb-admin-2.css')}}" rel="stylesheet">
<!-- Custom Fonts -->
<link href="{{ url_for('static', filename='vendor/font-awesome/css/font-awesome.min.css')}}" rel="stylesheet" type="text/css">
对于body标签下面的代码,全部黏贴来之模板的内容,
在菜单地方黏贴:
{% block menu_links %}
{{ layout.menu_links() }}
{% endblock %}
在容器的地方黏贴:
<div id="page-wrapper">
<!--
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Dashboard</h1>
</div>
</div>
-->
<div class="row">
{% block access_control %}
{% endblock %}
{% block messages %}
{{ layout.messages() }}
{% endblock %}
{# store the jinja2 context for form_rules rendering logic #}
{% set render_ctx = h.resolve_ctx() %}
</div>
<div class="row">
{% block body %}{% endblock %}
</div>
</div>
最后的代码就如下:
{% import 'admin/mylayout.html' as layout with context -%}
{% import 'admin/static.html' as admin_static with context %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% if admin_view.category %}{{ admin_view.category }} - {% endif %}{{ admin_view.name }} - {{ admin_view.admin.name }}{% endblock %}</title>
{% block head_meta %}
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="AI在线 - 博客体">
<meta name="author" content="ouyangm">
<link rel="shortcut icon" href="{{ url_for('static', filename = 'favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename = 'favicon.ico') }}" type="image/x-icon">
{% endblock %}
{% block head_css %}
<link href="{{ admin_static.url(filename='bootstrap/bootstrap3/swatch/{swatch}/bootstrap.min.css'.format(swatch=config.get('FLASK_ADMIN_SWATCH', 'default')), v='3.3.5') }}" rel="stylesheet">
{%if config.get('FLASK_ADMIN_SWATCH', 'default') == 'default' %}
<link href="{{ admin_static.url(filename='bootstrap/bootstrap3/css/bootstrap-theme.min.css', v='3.3.5') }}" rel="stylesheet">
{%endif%}
<link href="{{ admin_static.url(filename='admin/css/bootstrap3/admin.css', v='1.1.1') }}" rel="stylesheet">
<!-- MetisMenu CSS -->
<link href="{{ url_for('static', filename='vendor/metisMenu/metisMenu.min.css')}}" rel="stylesheet">
<!-- Custom CSS -->
<link href="{{ url_for('static',
filename='dist/css/sb-admin-2.css')}}" rel="stylesheet">
<!-- Custom Fonts -->
<link href="{{ url_for('static', filename='vendor/font-awesome/css/font-awesome.min.css')}}" rel="stylesheet" type="text/css">
{% if admin_view.extra_css %}
{% for css_url in admin_view.extra_css %}
<link href="{{ css_url }}" rel="stylesheet">
{% endfor %}
{% endif %}
<style>
body {
padding-top: 4px;
}
</style>
{% endblock %}
{% block head %}
{% endblock %}
{% block head_tail %}
{% endblock %}
</head>
<body>
<div id="wrapper">
<!-- Navigation -->
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/index.html"> AI在线 - 博客体 </a>
</div>
<!-- /.navbar-header -->
<ul class="nav navbar-top-links navbar-right">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-tasks fa-fw"></i> <i class="fa fa-caret-down"> 扩展功能 </i>
</a>
<!--
<ul class="dropdown-menu dropdown-user">
<li><a href="#"><i class="fa fa-user fa-fw"></i> User Profile</a>
</li>
<li><a href="#"><i class="fa fa-gear fa-fw"></i> Settings</a>
</li>
<li class="divider"></li>
<li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
</li>
</ul>
-->
{% block menu_links %}
{{ layout.menu_links() }}
{% endblock %}
<!-- /.dropdown-messages -->
</li>
<!-- /.dropdown -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-envelope fa-fw"></i> <i class="fa fa-caret-down"> </i>
</a>
<ul class="dropdown-menu dropdown-tasks">
<li>
<a href="#">
<div>
<p>
<strong>Task 1</strong>
<span class="pull-right text-muted">40% Complete</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
<span class="sr-only">40% Complete (success)</span>
</div>
</div>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center" href="#">
<strong>See All Tasks</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!-- /.dropdown-tasks -->
</li>
<!-- /.dropdown -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-bell fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-alerts">
<li>
<a href="#">
<div>
<i class="fa fa-comment fa-fw"></i> New Comment
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-twitter fa-fw"></i> 3 New Followers
<span class="pull-right text-muted small">12 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-envelope fa-fw"></i> Message Sent
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-tasks fa-fw"></i> New Task
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-upload fa-fw"></i> Server Rebooted
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center" href="#">
<strong>See All Alerts</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!-- /.dropdown-alerts -->
</li>
<!-- /.dropdown -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#"><i class="fa fa-user fa-fw"></i> User Profile</a>
</li>
<li><a href="#"><i class="fa fa-gear fa-fw"></i> Settings</a>
</li>
<li class="divider"></li>
<li><a href="/admin/loginout"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
</li>
</ul>
<!-- /.dropdown-user -->
</li>
<!-- /.dropdown -->
</ul>
<!-- /.navbar-top-links -->
<div class="navbar-default sidebar" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav" id="side-menu">
<li class="sidebar-search">
<div class="input-group custom-search-form">
<input type="text" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<i class="fa fa-search"></i>
</button>
</span>
</div>
<!-- /input-group -->
</li>
{% block main_menu %}
{{ layout.menu() }}
{% endblock %}
<!-- /.nav-second-level
<li>
<a href="index.html"><i class="fa fa-dashboard fa-fw"></i> Dashboard</a>
</li>
<li>
<a href="#"><i class="fa fa-bar-chart-o fa-fw"></i> Charts<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li>
<a href="flot.html">Flot Charts</a>
</li>
<li>
<a href="morris.html">Morris.js Charts</a>
</li>
</ul>
</li>
-->
</ul>
</div>
<!-- /.sidebar-collapse -->
</div>
<!-- /.navbar-static-side -->
</nav>
<div id="page-wrapper">
<!--
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Dashboard</h1>
</div>
</div>
-->
<div class="row">
{% block access_control %}
{% endblock %}
{% block messages %}
{{ layout.messages() }}
{% endblock %}
{# store the jinja2 context for form_rules rendering logic #}
{% set render_ctx = h.resolve_ctx() %}
</div>
<div class="row">
{% block body %}{% endblock %}
</div>
</div>
<!-- /#page-wrapper -->
</div>
{% block tail_js %}
<script src="{{ admin_static.url(filename='vendor/jquery.min.js', v='2.1.4') }}" type="text/javascript"></script>
<script src="{{ admin_static.url(filename='bootstrap/bootstrap3/js/bootstrap.min.js', v='3.3.5') }}" type="text/javascript"></script>
<script src="{{ admin_static.url(filename='vendor/moment.min.js', v='2.9.0') }}" type="text/javascript"></script>
<script src="{{ admin_static.url(filename='vendor/select2/select2.min.js', v='3.5.2') }}" type="text/javascript"></script>
<!-- sb-admin-theme -->
<script src="{{ url_for('static', filename='vendor/metisMenu/metisMenu.min.js') }}"></script>
<script src="{{ url_for('static', filename='dist/js/sb-admin-2.js') }}"></script>
<!-- Metis Menu Plugin JavaScript -->
{% if admin_view.extra_js %}
{% for js_url in admin_view.extra_js %}
<script src="{{ js_url }}" type="text/javascript"></script>
{% endfor %}
{% endif %}
{% endblock %}
{% block tail %}
{% endblock %}
</body>
</html>
展示出来的样式: