系统框架
.
|-- app
| |-- admin
| | |-- forms
| | | |-- admin.py
| | | |-- auth.py
| | | |-- __init__.py
| | | |-- main.py
| | | |-- movie.py
| | | |-- preview.py
| | | |-- role.py
| | | `-- tag.py
| | |-- __init__.py
| | |-- utils.py
| | `-- views
| | |-- admin.py
| | |-- auth.py
| | |-- collect.py
| | |-- comment.py
| | |-- __init__.py
| | |-- logs.py
| | |-- main.py
| | |-- movie.py
| | |-- preview.py
| | |-- role.py
| | |-- tag.py
| | `-- user.py
| |-- home
| | |-- forms.py
| | |-- __init__.py
| | |-- utils.py
| | `-- views.py
| |-- __init__.py
| |-- models.py
| |-- static
| | |-- asset
| | |-- css
| | |-- js
| | |-- fonts
| | |-- img
| | `-- upload
| | |-- movieImg
| | |-- previewImg
| | `-- userFaceImg
| `-- templates
| |-- admin
| | |-- admin
| | | |-- add.html
| | | `-- list.html
| | |-- aside.html
| | |-- auth
| | | |-- add.html
| | | |-- edit.html
| | | `-- list.html
| | |-- base.html
| | |-- collect
| | | `-- list.html
| | |-- comment
| | | `-- list.html
| | |-- login.html
| | |-- logs
| | | |-- admin_log.html
| | | |-- operate_log.html
| | | `-- user_log.html
| | |-- movie
| | | |-- add.html
| | | |-- edit.html
| | | `-- list.html
| | |-- preview
| | | |-- add.html
| | | |-- edit.html
| | | `-- list.html
| | |-- pwd.html
| | |-- role
| | | |-- add.html
| | | |-- edit.html
| | | `-- list.html
| | |-- tag
| | | |-- add.html
| | | |-- edit.html
| | | `-- list.html
| | `-- user
| | |-- list.html
| | `-- view.html
| |-- home
| | |-- base.html
| | |-- comments.html
| | |-- index.html
| | |-- login.html
| | |-- moviecollect.html
| | |-- play.html
| | |-- pwd.html
| | |-- register.html
| | |-- user.html
| | |-- userlog.html
| | `-- usermenu.html
| `-- macro
| `-- pages.html
|-- config.py
`-- manage.py
后台蓝图的创建
在admin的模块包__init__.py中,创建蓝图连接,导出所有的视图函数
from flask import Blueprint
admin=Blueprint('admin',__name__)
from app.admin.views.main import *
from app.admin.views.tag import *
from app.admin.views.movie import *
from app.admin.views.preview import *
from app.admin.views.user import *
from app.admin.views.comment import *
from app.admin.views.collect import *
from app.admin.views.logs import *
from app.admin.views.auth import *
from app.admin.views.role import *
from app.admin.views.admin import *
在app中的__init__中,添加注册后台的蓝图
from app.admin import admin as admin_blueprint
# 注册admin蓝图, url_prefix='/admin'添加前缀/admin
app.register_blueprint(admin_blueprint, url_prefix='/admin')
主要的:继承的base.html(后台管理的),
{% extends 'bootstrap/base.html' %}
{% block doc %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Mosaddek">
<meta name="keyword" content="FlatLab, Dashboard, Bootstrap, Admin, Template, Theme, Responsive, Fluid, Retina">
<link rel="shortcut icon" href="/static/img/favicon.html">
<title>微电影-{% block title %} {% endblock %}</title>
<!-- Bootstrap core CSS -->
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/bootstrap-reset.css" rel="stylesheet">
<!--external css-->
<link href="/static/assets/font-awesome/css/font-awesome.css" rel="stylesheet"/>
<!-- Custom styles for this template -->
<link href="/static/css/style.css" rel="stylesheet">
<link href="/static/css/style-responsive.css" rel="stylesheet"/>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 tooltipss and media queries -->
<!--[if lt IE 9]>
<script src="/static/js/html5shiv.js"></script>
<script src="/static/js/respond.min.js"></script>
<![endif]-->
</head>
<body>
<section id="container">
<!--header start-->
<header class="header white-bg">
<div class="sidebar-toggle-box">
<div data-original-title="Toggle Navigation" data-placement="right" class="icon-reorder tooltips"></div>
</div>
<!--logo start-->
<a href="#" class="logo">微电影<span>后台管理系统</span></a>
<!--logo end-->
<div class="top-nav ">
<ul class="nav pull-right top-menu">
<li>
<input type="text" class="form-control search" placeholder="Search">
</li>
<!-- user login dropdown start-->
<li class="dropdown">
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<img alt="" src="/static/img/avatar1_small.jpg">
<span class="username">西部开源技术中心</span>
<b class="caret"></b>
</a>
<ul class="dropdown-menu extended logout">
<div class="log-arrow-up"></div>
<li><a href="#"><i class=" icon-suitcase"></i>配置</a></li>
<li><a href="{{ url_for('admin.pwd') }}"><i class="icon-cog"></i> 修改密码</a></li>
<li><a href="#"><i class="icon-bell-alt"></i> 会员中心</a></li>
<li><a href="{{ url_for('admin.logout') }}"><i class="icon-key"></i> 登出</a></li>
</ul>
</li>
<!-- user login dropdown end -->
</ul>
</div>
</header>
<!--header end-->
{% include 'admin/aside.html' %}
<!--main content start-->
<section id="main-content">
<section class="wrapper" style="margin-left: 20px;">
{#让每个页面都可以获取闪现信息闪现#}
{% for item in get_flashed_messages() %}
<div class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
aria-hidden="true">×</span></button>
{{ item }}
</div>
{% endfor %}
{# 参考 路径导航: https://v3.bootcss.com/components/#breadcrumbs #}
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 首页</a></li>
<li class="active">控制面板</li>
</ol>
{% block content %}
<!-- page start-->
Page content goes here
<!-- page end-->
{% endblock %}
</section>
</section>
<!--main content end-->
</section>
<!-- js placed at the end of the document so the pages load faster -->
<script src="/static/js/jquery.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/jquery.scrollTo.min.js"></script>
<script src="/static/js/jquery.nicescroll.js" type="text/javascript"></script>
<!--common script for all pages-->
<script src="/static/js/common-scripts.js"></script>
</body>
</html>
{% endblock %}
册边栏的页面实现:aside.html
<!--sidebar start-->
<aside style="margin-right: 100px">
<div id="sidebar" class="nav-collapse ">
<!-- sidebar menu start-->
<ul class="sidebar-menu">
<li class="">
<a class="" href="{{ url_for('admin.index') }}">
<i class="icon-dashboard"></i>
<span>电脑信息</span>
</a>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-book"></i>
<span>标签管理</span>
<span class="label label-danger pull-right">2</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.tag_add') }}">增加标签</a></li>
<li><a class="" href="{{ url_for('admin.tag_list') }}">标签列表</a></li>
</ul>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-cogs"></i>
<span>电影管理</span>
<span class="label label-danger pull-right">2</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.movie_add') }}">增加电影</a></li>
<li><a class="" href="{{ url_for('admin.movie_list') }}">电影列表</a></li>
</ul>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-tasks"></i>
<span>预告管理</span>
<span class="label label-danger pull-right">2</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.preview_add') }}">添加预告</a></li>
<li><a class="" href="{{ url_for('admin.preview_list') }}">预告列表</a></li>
</ul>
</li>
<li class="">
<a class="" href="{{ url_for('admin.user_list') }}">
<i class="icon-dashboard"></i>
<span>会员管理</span>
</a>
</li>
<li class="">
<a class="" href="{{ url_for('admin.comment_list') }}">
<i class="icon-dashboard"></i>
<span>评论管理</span>
</a>
</li>
<li class="">
<a class="" href="{{ url_for('admin.collect_list') }}">
<i class="icon-dashboard"></i>
<span>收藏管理</span>
</a>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-th"></i>
<span>日志管理</span>
<span class="label label-danger pull-right">3</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.logs_operate_log') }}">管理员操作日志</a></li>
<li><a class="" href="{{ url_for('admin.logs_admin_log') }}">管理员登录日志</a></li>
<li><a class="" href="{{ url_for('admin.logs_user_log') }}">会员登录日志</a></li>
</ul>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-envelope"></i>
<span>权限管理</span>
<span class="label label-danger pull-right">2</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.auth_add') }}">添加权限</a></li>
<li><a class="" href="{{ url_for('admin.auth_list') }}">权限列表</a></li>
</ul>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-glass"></i>
<span>角色管理</span>
<span class="label label-danger pull-right">2</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.role_add') }}">添加角色</a></li>
<li><a class="" href="{{ url_for('admin.role_list') }}">角色列表</a></li>
</ul>
</li>
<li class="sub-menu">
<a href="javascript:;" class="">
<i class="icon-user"></i>
<span>管理员管理</span>
<span class="label label-danger pull-right">2</span>
<span class="arrow"></span>
</a>
<ul class="sub">
<li><a class="" href="{{ url_for('admin.admin_add') }}">添加管理员</a></li>
<li><a class="" href="{{ url_for('admin.admin_list') }}">管理员列表</a></li>
</ul>
</li>
</ul>
<!-- sidebar menu end-->
</div>
</aside>
<!--sidebar end-->
实现各个页面的分页显示,运用html中函数的方法:宏,即macro包中的pages.html
{% macro paginate(PageObj, viewFun) %}
<div class="col-md-12 text-center">
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="{{ url_for(viewFun, page=1) }}" aria-label="First">
<span aria-hidden="true">首页</span>
</a>
</li>
{% if PageObj.has_prev %}
<li>
<a href="{{ url_for(viewFun, page=PageObj.prev_num) }}" aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
{% else %}
<li class="disabled">
<a aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
{% endif %}
<li><a href="#">{{ PageObj.page }} / {{ PageObj.pages }}</a></li>
{% if PageObj.has_next %}
<li>
<a href="{{ url_for(viewFun, page=PageObj.next_num) }}" aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
{% else %}
<li class="disabled">
<a aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
{% endif %}
<li>
<a href="{{ url_for(viewFun, page=PageObj.pages) }}" aria-label="Last">
<span aria-hidden="true">尾页</span>
</a>
</li>
</ul>
</nav>
</div>
{% endmacro %}
admin包里实现各种函数以及装饰器的模块:utils.py中
from functools import wraps
from flask import session, flash, redirect, url_for, request, abort
from app import db
from app.models import AdminOplog, Admin, Auth
def is_admin_login(f):
"""用来判断用户是否登录成功"""
@wraps(f)
def wrapper(*args, **kwargs):
# 判断session对象中是否有seesion['admin'],
# 如果包含信息, 则登录成功, 可以访问主页;
# 如果不包含信息, 则未登录成功, 跳转到登录界面;;
if session.get('admin', None):
return f(*args, **kwargs)
else:
flash("管理员必须登录才能访问%s" % (f.__name__))
return redirect(url_for('admin.login'))
return wrapper
def write_adminlog(content):
"""将操作日志写入数据库中"""
adminOplog = AdminOplog(
admin_id=session.get('admin_id'),
content=content,
ip=request.remote_addr
)
db.session.add(adminOplog)
db.session.commit()
def permission_control(f):
"""判断管理员是否有权限操作,(如果是超级管理员, 则全部可以操作) 如果没有权限抛出403"""
@wraps(f)
def wrapper(*args, **kwargs):
admin = Admin.query.get_or_404(session.get('admin_id'))
if not admin.is_super: # 如果不是超级用户, xxxx
# 获取当前用户拥有的权限, 默认是字符串'1,2,3'
auths = admin.role.auths
# 获取所有的权限列表;
all_auth = Auth.query.all()
# 获取管理员可以访问的路由地址
admin_urls = []
auths = map(int, auths.split(',')) # 权限id号
for auth in all_auth:
for auth_id in auths:
# 若管理员有全部权限中的某一项,则添加到该管理员的可访问路由地址中
if auth_id == auth.id:
admin_urls.append(auth.url)
print("管理员可以访问的路由地址:", admin_urls)
print("管理员正在访问的url路由地址:", request.url_rule)
if str(request.url_rule) not in admin_urls:
abort(404)
return f(*args, **kwargs)
return wrapper
forms模块包中分别创建各页面的表单,便于管理;views包以及templates中admin的页面实现的html文件也分区域便于管理
一.(1)主页面的实现。主页,登录页面以及登出,和更改密码的表单
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, FileField, TextAreaField
from wtforms.validators import DataRequired, Length, EqualTo, Email, Regexp
from flask_wtf.file import FileAllowed
class BaseForm(FlaskForm):
username = StringField(
label="用户名",
validators=[
DataRequired()
]
)
password = PasswordField(
label="密码",
validators=[
DataRequired(),
# Length(6, 12, message="密码长度必须为6-12")
]
)
class LoginForm(BaseForm):
submit = SubmitField(
label="登录"
)
class PwdForm(FlaskForm):
old_pwd = PasswordField(
label="旧密码",
validators=[
DataRequired()
],
# <input name="xxx" placeholder="">
render_kw = {
'placeholder' : "请输入旧密码"
}
)
new_pwd = PasswordField(
label="新密码",
validators=[
DataRequired()
],
render_kw={
'placeholder': "请输入新密码"
}
)
submit = SubmitField(
label="修改密码"
)
(2)对应的视图函数
from flask import session, flash, request, redirect, url_for, render_template
from werkzeug.security import generate_password_hash
from app import db
from app.admin import admin
from app.admin.forms.main import LoginForm, PwdForm
from app.admin.utils import is_admin_login
from app.models import Admin, Adminlog
@admin.route('/')
def index():
return render_template('admin/base.html')
@admin.route('/login/', methods=['POST', 'GET'])
def login():
form = LoginForm()
if form.validate_on_submit():
name = form.username.data
password = form.password.data
admin = Admin.query.filter_by(name=name).first()
if admin and admin.verify_password(password):
# session信息的保存
session['admin_id'] = admin.id
session['admin'] = admin.name
flash("管理员%s登录成功" % (admin.name))
remote_ip = request.remote_addr
# 将登录信息写到日志中;
adminlog = Adminlog(admin_id=admin.id,
ip=remote_ip,
area='xxx内网IP')
db.session.add(adminlog)
db.session.commit()
# 从index蓝图里面寻找index函数;
return redirect(url_for('admin.index'))
else:
flash("管理员登录失败")
return redirect(url_for('admin.login'))
return render_template('admin/login.html',
form=form)
@admin.route('/logout/')
@is_admin_login
def logout():
session.pop('admin_id', None)
session.pop('admin', None)
return redirect(url_for('admin.login'))
# 修改密码
@admin.route('/pwd/', methods=['GET', 'POST'])
def pwd():
form = PwdForm()
if form.validate_on_submit():
# 获取当前登录用户的密码
admin = Admin.query.filter_by(name=session.get('admin')).first()
# 判断用户的旧密码是否正确
if admin.verify_password(form.old_pwd.data):
# ********数据库里面的是password
admin.password = generate_password_hash(form.new_pwd.data)
db.session.add(admin)
db.session.commit()
flash("密码更新成功")
else:
flash("旧密码错误, 请重新输入")
return redirect(url_for('admin.pwd'))
return render_template('admin/pwd.html', form=form)
(3)对应的templates中改组的html文件
主页即为base页面
登录页面的实现:login.html
登录前必须创建一个超级用户,页面是不能创建用户的
在数据库的操作的时候,已经添加该命令,查看基于flask的微电影的数据库创建那节
{% extends 'bootstrap/base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}
登录
{% endblock %}
{% block content %}
<div class="container">
<div class="col-lg-8 col-lg-offset-2">
<div class="panel panel-success">
<div class="panel-heading">
<h1 class="panel-title"><span class="glyphicon glyphicon-log-in">
</span> 登录</h1>
</div>
<div class="panel-body">
{{ wtf.quick_form(form) }}
</div>
</div>
</div>
</div>
{% endblock %}
更改密码的页面实现:pwd.html
{% extends 'admin/base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}
修改密码
{% endblock %}
{% block content %}
{# 右侧用户中心 #}
<div class="col-lg-11">
{# 面板中心 #}
<div class="panel panel-warning">
{# 面板头部 #}
<div class="panel-heading">
<h3 class="panel-title">
<span class="glyphicon glyphicon-lock"></span> 修改密码
</h3>
</div>
{# 面板主体 #}
<div class="panel-body">
{{ wtf.quick_form(form) }}
</div>
</div>
</div>
{% endblock %}