zoukankan      html  css  js  c++  java
  • Flask开发微电影网站(五)

    后台管理页面是系统管理员登录后对网站进行管理的前端页面

    后台登录页面,如下图所示

    管理员登录后的页面,如下图所示

    管理员登录后,在右上角显示的管理员信息,如下图所示

    管理员登录后,在页面中间部分的左侧显示管理菜单

    管理菜单包括控制面板,标签管理,电影管理,预告管理,会员管理,评论管理,收藏管理,日志管理,权限管理,角色管理,管理员管理等菜单,每个菜单下有子菜单进行细分管理控制

    管理员可以使用菜单对网站进行管理

    在上面的图片中,可以看到,后台管理页面的顶部部分都是一样的,所以可以把后台管理页面顶部单独定义一个文件admin.html,让其他的页面继承admin.html

    后台管理页面的中间部分中,管理员点击子菜单进行管理,每个子菜单显示的显示,其左侧部分又都是相同的,所以也可以把中间部分的左侧菜单也单独定义一个文件grid.html,让每个子菜单显示的页面都包含grid.html文件

    1. 定义后台管理页面的左侧菜单部分

    在templates的admin目录下创建grid.html,用来保存后台管理页面的左侧菜单部分代码

    <ul class="sidebar-menu">
        <li class="header">管理菜单</li>
        <li class="treeview" id="g-1">
            <a href="#">
                <i class="fa fa-home" aria-hidden="true"></i>
                <span>首页</span>
                <span class="label label-primary pull-right">1</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-1-1">
                    <a href="{{ url_for('admin.index') }}">
                        <i class="fa fa-circle-o"></i> 控制面板
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-2">
            <a href="#">
                <i class="fa fa-tags" aria-hidden="true"></i>
                <span>标签管理</span>
                <span class="label label-primary pull-right">2</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-2-1">
                    <a href="{{ url_for('admin.tag_add') }}">
                        <i class="fa fa-circle-o"></i> 添加标签
                    </a>
                </li>
                <li id="g-2-2">
                    <a href="{{ url_for('admin.tag_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 标签列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-3">
            <a href="#">
                <i class="fa fa-file-video-o" aria-hidden="true"></i>
                <span>电影管理</span>
                <span class="label label-primary pull-right">2</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-3-1">
                    <a href="{{ url_for('admin.movie_add') }}">
                        <i class="fa fa-circle-o"></i> 添加电影
                    </a>
                </li>
                <li id="g-3-2">
                    <a href="{{ url_for('admin.movie_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 电影列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-4">
            <a href="#">
                <i class="fa fa-film" aria-hidden="true"></i>
                <span>预告管理</span>
                <span class="label label-primary pull-right">2</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-4-1">
                    <a href="{{ url_for('admin.preview_add') }}">
                        <i class="fa fa-circle-o"></i> 添加预告
                    </a>
                </li>
                <li id="g-4-2">
                    <a href="{{ url_for('admin.preview_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 预告列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-5">
            <a href="#">
                <i class="fa fa-users" aria-hidden="true"></i>
                <span>会员管理</span>
                <span class="label label-primary pull-right">1</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-5-1">
                    <a href="{{ url_for('admin.user_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 会员列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-6">
            <a href="#">
                <i class="fa fa-comments" aria-hidden="true"></i>
                <span>评论管理</span>
                <span class="label label-primary pull-right">1</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-6-1">
                    <a href="{{ url_for('admin.comment_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 评论列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-7">
            <a href="#">
                <i class="fa fa-heart" aria-hidden="true"></i>
                <span>收藏管理</span>
                <span class="label label-primary pull-right">1</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-7-1">
                    <a href="{{ url_for('admin.moviecol_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 收藏列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-8">
            <a href="#">
                <i class="fa fa-file-text" aria-hidden="true"></i>
                <span>日志管理</span>
                <span class="label label-primary pull-right">3</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-8-1">
                    <a href="{{ url_for('admin.oplog_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 操作日志列表
                    </a>
                </li>
                <li id="g-8-2">
                    <a href="{{ url_for('admin.adminloginlog_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 管理员登录日志列表
                    </a>
                </li>
                <li id="g-8-3">
                    <a href="{{ url_for('admin.userloginlog_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 会员登录日志列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-9">
            <a href="#">
                <i class="fa fa-lock" aria-hidden="true"></i>
                <span>权限管理</span>
                <span class="label label-primary pull-right">2</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-9-1">
                    <a href="{{ url_for('admin.auth_add') }}">
                        <i class="fa fa-circle-o"></i> 添加权限
                    </a>
                </li>
                <li id="g-9-2">
                    <a href="{{ url_for('admin.auth_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 权限列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-10">
            <a href="#">
                <i class="fa fa-user-secret" aria-hidden="true"></i>
                <span>角色管理</span>
                <span class="label label-primary pull-right">2</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-10-1">
                    <a href="{{ url_for('admin.role_add') }}">
                        <i class="fa fa-circle-o"></i> 添加角色
                    </a>
                </li>
                <li id="g-10-2">
                    <a href="{{ url_for('admin.role_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 角色列表
                    </a>
                </li>
            </ul>
        </li>
        <li class="treeview" id="g-11">
            <a href="#">
                <i class="fa fa-user-circle" aria-hidden="true"></i>
                <span>管理员管理</span>
                <span class="label label-primary pull-right">2</span>
            </a>
            <ul class="treeview-menu">
                <li id="g-11-1">
                    <a href="{{ url_for('admin.admin_add') }}">
                        <i class="fa fa-circle-o"></i> 添加管理员
                    </a>
                </li>
                <li id="g-11-2">
                    <a href="{{ url_for('admin.admin_list',page=1) }}">
                        <i class="fa fa-circle-o"></i> 管理员列表
                    </a>
                </li>
            </ul>
        </li>
    </ul>
    

    2. 定义后台管理页面的顶端部分

    templates的admin目录下创建admin.html,用来保存后台管理页面的顶端部分代码

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>微电影管理系统</title>
        <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
        <link rel="shortcut icon" href="{{ url_for('static',filename='base/images/logo.png') }}">
        <link rel="stylesheet" href="{{ url_for('static',filename='admin/bootstrap/css/bootstrap.min.css') }}">
        <link rel="stylesheet" href="{{ url_for('static',filename='fonts/css/font-awesome.min.css') }}">
        <link rel="stylesheet" href="{{ url_for('static',filename='ionicons/css/ionicons.min.css') }}">
        <link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/AdminLTE.min.css') }}">
        <link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/skins/_all-skins.min.css') }}">
        <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='admin/plugins/datepicker/datepicker3.css') }}">
        <style>
            *{
                font-family:"Microsoft YaHei";
            }
            .table>tbody>tr>td, .table>tbody>tr>th, .table> tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th{
                vertical-align:middle;
                text-align:center;
            }
        </style>
        {% block css %}
    
        {% endblock %}
    </head>
    <body class="hold-transition skin-blue sidebar-mini">
    <div class="wrapper">
        <header class="main-header">
            <a href="{{ url_for('admin.index') }}" class="logo">
                <span class="logo-mini"><img src="{{ url_for('static',filename='base/images/logo.png') }}" style="height:40px;40px;">电影系统</span>
                <span class="logo-lg"><img src="{{ url_for('static',filename='base/images/logo.png') }}" style="height:40px;40px;">微电影管理系统</span>
            </a>
            <nav class="navbar navbar-static-top">
                <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
                    <span class="sr-only">下拉菜单</span>
                </a>
    
                <div class="navbar-custom-menu">
                    <ul class="nav navbar-nav">
                        <li class="dropdown user user-menu">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                                <img src="{{ url_for('static',filename='admin/dist/img/' + logo) }}"
                                     class="user-image" alt="User Image">
                                <span class="hidden-xs">{{ session.get("admin") }}</span>
                            </a>
                            <ul class="dropdown-menu">
                                <li class="user-header">
                                    <img src="{{ url_for('static',filename='admin/dist/img/' + logo) }}"
                                         class="img-circle" alt="User Image">
                                    <p>
                                        {{ session.get("admin") }}
                                        <small>{{ online_time }}</small>
                                    </p>
                                </li>
                                <li class="user-footer">
                                    <div class="pull-left">
                                        <a href="{{ url_for('admin.pwd') }}" class="btn btn-default btn-flat">修改密码</a>
                                    </div>
                                    <div class="pull-right">
                                        <a href="{{ url_for('admin.login') }}" class="btn btn-default btn-flat">退出系统</a>
                                    </div>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </div>
            </nav>
        </header>
        <aside class="main-sidebar">
            <section class="sidebar">
                <div class="user-panel">
                    <div class="pull-left image">
                        <img src="{{ url_for('static',filename='admin/dist/img/' + logo) }}" class="img-circle"
                             alt="User Image">
                    </div>
                    <div class="pull-left info">
                        <p>用户 {{ session.get("admin") }}</p>
                        <a href="#"><i class="fa fa-circle text-success"></i> 在线</a>
                    </div>
                </div>
                <form action="#" method="get" class="sidebar-form">
                    <div class="input-group">
                        <input type="text" name="q" class="form-control" placeholder="搜索...">
                        <span class="input-group-btn">
                            <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i
                                    class="fa fa-search"></i>
                            </button>
                        </span>
                    </div>
                </form>
                {% include 'admin/grid.html' %}
            </section>
        </aside>
        <div class="content-wrapper">
        <!--内容-->
            {% block content %}
    
            {% endblock %}
        <!--内容-->
        </div>
        <footer class="main-footer">
            <div class="pull-right hidden-xs">
                <b>版本</b> 1.0
            </div>
            <strong>版权 &copy; 2017-2018 归<a href="">xxx</a>.</strong> 所有
        </footer>
        <div class="control-sidebar-bg"></div>
    </div>
    <script src="{{ url_for('static',filename='admin/plugins/jQuery/jQuery-2.2.0.min.js') }}"></script>
    <script src="{{ url_for('static',filename='admin/bootstrap/js/bootstrap.min.js') }}"></script>
    <script src="{{ url_for('static',filename='admin/plugins/slimScroll/jquery.slimscroll.min.js') }}"></script>
    <script src="{{ url_for('static',filename='admin/plugins/fastclick/fastclick.js') }}"></script>
    <script src="{{ url_for('static',filename='admin/dist/js/app.min.js') }}"></script>
    <script src="{{ url_for('static',filename='admin/dist/js/demo.js') }}"></script>
    <script src="//cdn.bootcss.com/holder/2.9.4/holder.min.js"></script>
    <script src="{{ url_for('static',filename='admin/plugins/datepicker/bootstrap-datepicker.js') }}"></script>
    <script src="{{ url_for('static',filename='admin/plugins/datepicker/locales/bootstrap-datepicker.zh-CN.js') }}" charset="UTF-8"></script>
    
    {% block js %}
    
    {% endblock %}
    
    </body>
    </html>
    

    在admin.html页面中,包含了左侧菜单部分的文件grid.html

    3. 定义后台管理页面所需要的上下文处理器

    在上面的后台管理页面顶端部分的代码中,使用了logo这个变量,所以要在视图函数中定义上下文处理器来封装这个变量logo

    app的admin目录下的views.py文件中定义上下文处理器context_processor

    import datetime
    
    from . import admin
    from app.models import Admin
    
    # 上下文应用处理器
    # 封装全局变量,并将其展现到模版里
    @admin.context_processor
    def tpl_extra():
        try:
            admin = Admin.query.filter_by(name=session["admin"]).first()		# 从session中获取admin的值,并在数据库中进行查询
        except:
            admin = None
        data=dict(
            online_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            logo="user3-128x128.jpg",
            admin=admin,
        )
        return data
    

    4. 定义后台管理页面的登录控制装饰器

    既然是后台管理页面,就不能让普通用户登录进行管理操作,所以可以定义一个登录装饰器,对每个后台管理视图函数进行装饰,使得管理员用户必须登录后才能访问后台管理页面

    from functools import wraps
    from flask import render_template, redirect, url_for, session
    
    from app.models import Admin, Auth, Role
    
    # 定义装饰器,必须登录后才能访问后台管理页面
    def admin_login_req(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if "admin" not in session:			# 如果session中没有admin变量则重定向到登录页面
                return redirect(url_for("admin.login", next=request.url))
            return f(*args, **kwargs)
    	 return decorated_function
    

    5. 定义后台管理页面的权限控制装饰器

    对于后台管理权限来说,每个后台管理员的角色不同,能拥有的管理权限也不同,能打开的后台管理页面自然也不同

    所以也需要对后台管理员的权限进行控制,不同角色的管理员只能打开自己权限内的管理页面

    from functools import wraps
    from flask import session
    
    from app.models import Admin, Auth, Role
    
    # 权限控制装饰器
    def admin_auth(func):
        @wraps(func)
        def decorated_function(*args, **kwargs):
            admin = Admin.query.join(Role).filter(
                Role.id == Admin.role_id,
                Admin.id == session.get("admin_id")
            ).first()
            auths = admin.role.auths
            if auths:
                auths = list(map(lambda v: int(v), auths.split(",")))
                auth_list = Auth.query.all()
                urls = [v.url for v in auth_list for val in auths if val == v.id]
                rule = request.url_rule
                if str(rule) not in urls:
                    abort(404)
                return func(*args, **kwargs)
            abort(404)
        return decorated_function
  • 相关阅读:
    Mysql登录错误:ERROR 1045 (28000): Plugin caching_sha2_password could not be loaded
    Docker配置LNMP环境
    Docker安装mysqli扩展和gd扩展
    Docker常用命令
    Ubuntu常用命令
    单例模式的优缺点和使用场景
    ABP 多租户数据共享
    ABP Core 后台Angular+Ng-Zorro 图片上传
    ERROR Error: If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions.
    AbpCore 执行迁移文件生成数据库报错 Could not find root folder of the web project!
  • 原文地址:https://www.cnblogs.com/renpingsheng/p/9129656.html
Copyright © 2011-2022 走看看