后台管理

实现后台管理系统使用flask sqlalchemy结合mysql数据库进行增删改查操作、分页的使用、路由装饰器定义、模板中变量调用、登录会话机制、上传文件、flask wtforms表单使用。

管理员登录

models进行重构,将数据库的配置信息放在 app/__init__.py文件中

from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqlconnector://root:123456@127.0.0.1:3306/movie'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SECRET_KEY'] = 'cb34xxxxxxxxxxxxxxxxxxbae30d90f6' db = SQLAlchemy(app)

models文件中直接引入db

from app import db

定义登陆表单字段

app/admin/forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, ValidationError from app.models import Admin class LoginForm(FlaskForm):
'''
管理员登陆表单
'''
account = StringField(
label='账号',
validators=[
DataRequired("请输入账号!")
],
description="账号",
render_kw={
"class": "form-control",
"placeholder": "请输入账号!",
"required": "required"
}
)
pwd = PasswordField(
label='密码',
validators=[
DataRequired("请输入密码!")
],
description="密码",
render_kw={
"class": "form-control",
"placeholder": "请输入密码!",
"required": "required"
}
)
submit = SubmitField(
'登录',
render_kw={
"class": "btn btn-primary btn-block btn-flat",
}
) def validate_account(self, field):
account = field.data
admin = Admin.query.filter_by(name=account).count()
if admin == 0:
raise ValidationError("账号不存在!")

render_kw里的样式是前端代码中的

编写试图函数

# 装饰器用来进行访问控制
def admin_login_req(func):
@wraps(func)
def decorated_function(*args, **kwargs):
if session.get('admin', None) is None:
return redirect(url_for('admin.login', next=request.url))
return func(*args, **kwargs)
return decorated_function
@admin.route('/login/', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
data = form.data
admin = Admin.query.filter_by(name=data['account']).first()
if not admin.check_pwd(data['pwd']):
flash("账号或密码错误! ")
return redirect(url_for('admin.login'))
session['admin'] = data['account']
return redirect((request.args.get('next') or url_for('admin.index')))
return render_template('admin/login.html', form=form) @admin.route('/logout/')
@admin_login_req
def logout():
session.clear()
return redirect(url_for('admin.login'))

在每一个需要进行登陆才能操作的视图函数中加入装饰器,像logout视图一样

Admin模型中添加密码校验函数

    def check_pwd(self, pwd):
from werkzeug.security import check_password_hash
return check_password_hash(self.pwd, pwd)

修改模板app/templates/admin/login.html

    <div class="login-box-body">
{% for message in get_flashed_messages() %}
<p class="login-box-msg" style="color: red">{{ message }}</p>
{% endfor %} <form action="" method="post" id="form-data">
<div class="form-group has-feedback">
{{ form.account }}
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
{% for err in form.account.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %} </div>
<div class="form-group has-feedback">
{{ form.pwd }}
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
{% for err in form.pwd.errors %}
<div class="col-md-12" id="input_pwd" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="row">
<div class="col-xs-8">
</div>
<div class="col-xs-4">
{{ form.submit }}
{{ form.csrf_token }}
</div>
</div>
</form>
</div>

标签管理

创建一个表单form

app/admin/forms.py

class TagForm(FlaskForm):
name = StringField(
label='名称',
validators=[
DataRequired("请输入标签!")
],
description="名称",
render_kw={
"class": "form-control",
"id": "input_name",
"placeholder": "请输入标签名称!"
}
)
submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary"
}
)
添加标签

视图函数

@admin.route('/tag/add/', methods=['GET', 'POST'])
@admin_login_req
def tag_add():
form = TagForm()
if form.validate_on_submit():
data = form.data
tag = Tag.query.filter_by(name=data['name']).count()
if tag == 1:
flash("标签已存在!", 'error')
return redirect(url_for('admin.tag_add'))
tag = Tag(
name=data['name']
)
db.session.add(tag)
db.session.commit()
flash("标签添加成功!", 'info')
return redirect(url_for('admin.tag_add'))
return render_template('admin/tag_add.html', form=form)

修改前端代码

<form role="form" method="post">
<div class="box-body">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
{% for message in get_flashed_messages(category_filter=['error']) %}
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-ban"></i> 操作失败!</h4>
{{ message }}
</div>
{% endfor %} <div class="form-group">
<label for="input_name">{{ form.name.label }}</label>
{{ form.name }}
{% for err in form.name.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.submit }}
{{ form.csrf_token }}
</div>
</form>
标签列表

视图函数

@admin.route('/tag/list/<int:page>/')
@admin_login_req
def tag_list(page=1):
if page <= 0:
page = 1
page_data = Tag.query.order_by(
Tag.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/tag_list.html', page_data=page_data)

修改前端代码

<div class="box-body table-responsive no-padding">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>名称</th>
<th>添加时间</th>
<th>操作事项</th>
</tr>
{% for tag in page_data.items %}
<tr>
<td>{{ tag.id }}</td>
<td>{{ tag.name }}</td>
<td>{{ tag.addtime }}</td>
<td>
<a href="{{ url_for('admin.tag_edit', id=tag.id) }}" class="label label-success">编辑</a>
&nbsp;
<a href="{{ url_for('admin.tag_del', id=tag.id) }}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

当标签较多时,需要对标签进行分页

分页http://www.pythondoc.com/flask-sqlalchemy/api.html?highlight=paginate#id4

新建一个分页的macro

app/templates/ui/admin_page.html

{% macro pagination(data, url) -%}
{% if data %}
<ul class="pagination pagination-sm no-margin pull-right">
<li><a href="{{ url_for(url, page=1) }}">首页</a></li> {% if data.has_prev %}
<li><a href="{{ url_for(url, page=data.prev_num) }}">上一页</a></li>
{% else %}
<li class="disabled"><a href="#">上一页</a></li>
{% endif %} {% for v in data.iter_pages() %}
{% if v == data.page %}
<li class="active"><a href="#">{{ v }}</a></li>
{% else %}
<li><a href="{{ url_for(url, page=v) }}">{{ v }}</a></li>
{% endif %}
{% endfor %} {% if data.has_next %}
<li><a href="{{ url_for(url, page=data.next_num) }}">下一页</a></li>
{% else %}
<li class="disabled"><a href="#">下一页</a></li>
{% endif %} <li><a href="{{ url_for(url, page=data.pages) }}">尾页</a></li>
</ul> {% endif %}
{%- endmacro %}

在标签列表中使用这个macro

{% extends 'admin/admin.html' %}
{% from 'ui/admin_page.html' import pagination %} ... <div class="box-footer clearfix">
{{ pagination(page_data, 'admin.tag_list') }}
</div>
删除标签

视图函数

@admin.route('/tag/del/<int:id>/')
@admin_login_req
def tag_del(id=None):
tag = Tag.query.filter_by(id=id).first_or_404()
db.session.delete(tag)
db.session.commit()
flash('删除标签成功!', 'info')
return redirect(url_for('admin.tag_list', page=1))

修改标签列表中删除按钮的a标签

<a href="{{ url_for('admin.tag_del', id=tag.id) }}" class="label label-danger">删除</a>
修改标签

视图函数

@admin.route('/tag/edit/<int:id>/', methods=['GET', 'POST'])
@admin_login_req
def tag_edit(id=None):
form = TagForm()
tag = Tag.query.get_or_404(id)
if form.validate_on_submit():
data = form.data
tag_count = Tag.query.filter_by(name=data['name']).count()
if tag.name != data['name'] and tag_count == 1:
flash("标签已存在!", 'error')
return redirect(url_for('admin.tag_edit', id=id))
tag.name=data['name']
db.session.add(tag)
db.session.commit()
flash("标签修改成功!", 'info')
return redirect(url_for('admin.tag_list', page=1))
return render_template('admin/tag_edit.html', form=form, tag=tag)

新建app/templates/admin/tag_edit.html,用来进行标签的修改

代码和添加标签中的几乎一致,只是需要显示标签的名字

<div class="form-group">
<label for="input_name">{{ form.name.label }}</label>
{{ form.name(value=tag.name) }}
{% for err in form.name.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %}
</div>

电影管理

新建电影表单

app/admin/forms.py

class MovieForm(FlaskForm):
title = StringField(
label='片名',
validators=[
DataRequired("请输入片名!")
],
description="片名",
render_kw={
"class": "form-control",
"id": "input_title",
"placeholder": "请输入片名!"
}
)
url = FileField(
label='文件',
validators=[
DataRequired("请上传文件!")
],
description="文件",
)
info = TextAreaField(
label='简介',
validators=[
DataRequired("请输入简介!")
],
description="简介",
render_kw={
"class": "form-control",
"rows": "10",
"id": "input_info",
}
) logo = FileField(
label='封面',
validators=[
DataRequired("请上传封面!")
],
description="封面",
)
star = SelectField(
label='星级',
validators=[
DataRequired("请选择星级!")
],
coerce=int,
choices=[(1, '1星'), (2, '2星'), (3, '3星'), (4, '4星'), (5, '5星')],
description="星级",
render_kw={
"class": "form-control",
}
)
tag_id = SelectField(
label='标签',
validators=[
DataRequired("请选择标签!")
],
coerce=int,
choices=[(v.id, v.name) for v in tags],
description="标签",
render_kw={
"class": "form-control",
}
)
area = StringField(
label='地区',
validators=[
DataRequired("请输入地区!")
],
description="地区",
render_kw={
"class": "form-control",
"placeholder": "请输入地区!"
}
)
length = StringField(
label='片长',
validators=[
DataRequired("请输入片长!")
],
description="片长",
render_kw={
"class": "form-control",
"placeholder": "请输入片长!"
}
)
release_time = StringField(
label='上映时间',
validators=[
DataRequired("请选择上映时间!")
],
description="上映时间",
render_kw={
"class": "form-control",
"id": "input_release_time",
"placeholder": "请选择上映时间!"
}
)
submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary"
}
) def validate_title(self, field):
title = field.data
num = Movie.query.filter_by(title=title).count()
if num > 0:
raise ValidationError("该电影已存在!")

在app初始化文件中定义上传文件的目录

app.config['UP_DIR'] = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'static/uploads/')
添加电影

视图函数

文件名称检测

from werkzeug.utils import secure_filename

def change_filename(filename):
fileinfo = os.path.splitext(filename)
filename = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + str(uuid.uuid4().hex) + fileinfo[-1]
return filename
@admin.route('/movie/add/', methods=['GET', 'POST'])
@admin_login_req
def movie_add():
form = MovieForm()
if form.validate_on_submit():
data = form.data
file_url = secure_filename(form.url.data.filename)
file_logo = secure_filename(form.logo.data.filename) if not os.path.exists(app.config['UP_DIR']):
os.makedirs(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'], 6) url = change_filename(file_url)
logo = change_filename(file_logo)
form.url.data.save(app.config['UP_DIR'] + url)
form.logo.data.save(app.config['UP_DIR'] + logo) movie = Movie(
title=data['title'],
url=url,
info=data['info'],
logo=logo,
star=int(data['star']),
playnum=0,
commentnum=0,
tag_id=int(data['tag_id']),
area=data['area'],
release_time=data['release_time'],
length=data['length']
)
db.session.add(movie)
db.session.commit()
flash('电影添加成功!', 'info')
return redirect(url_for('admin.movie_add'))
return render_template('admin/movie_add.html', form=form)

app/templates/admin/movie_add.html

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

{% block content %}
<section class="content-header">
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 电影管理</a></li>
<li class="active">添加电影</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">添加电影</h3>
</div>
<form role="form" method="post" enctype="multipart/form-data">
<div class="box-body">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
<div class="form-group">
<label for="input_title">{{ form.title.label }}</label>
{{ form.title }}
{% for err in form.title.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_url">{{ form.url.label }}</label>
{{ form.url }}
{% for err in form.url.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
<div style="margin-top:5px;">
{# <div id="moviecontainer"></div>#}
</div>
</div>
<div class="form-group">
<label for="input_info">{{ form.info.label }}</label>
{{ form.info }}
{% for err in form.info.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_logo">{{ form.logo.label }}</label>
{{ form.logo }}
{% for err in form.logo.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
{# <img data-src="holder.js/262x166" style="margin-top:5px;" class="img-responsive"#}
{# alt="">#}
</div>
<div class="form-group">
<label for="input_star">{{ form.star.label }}</label>
{{ form.star }}
{% for err in form.star.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_tag_id">{{ form.tag_id.label }}</label>
{{ form.tag_id }}
{% for err in form.tag_id.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_area">{{ form.area.label }}</label>
{{ form.area }}
{% for err in form.area.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_length">{{ form.length.label }}</label>
{{ form.length }}
{% for err in form.length.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_release_time">{{ form.release_time.label }}</label>
{{ form.release_time }}
{% for err in form.release_time.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
电影列表

视图函数

@admin.route('/movie/list/<int:page>/')
@admin_login_req
def movie_list(page=1):
if page <= 0:
page = 1
page_data = Movie.query.join(Tag).filter(
Tag.id == Movie.tag_id
).order_by(
Movie.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/movie_list.html', page_data=page_data)

app/templates/admin/movie_list.html

{% extends 'admin/admin.html' %}
{% from 'ui/admin_page.html' import pagination %}
{% block content %}
<section class="content-header">
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 电影管理</a></li>
<li class="active">电影列表</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">电影列表</h3>
<div class="box-tools">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="table_search" class="form-control pull-right"
placeholder="请输入关键字..."> <div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</div>
</div>
<div class="box-body table-responsive no-padding">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>片名</th>
<th>片长</th>
<th>标签</th>
<th>地区</th>
<th>星级</th>
<th>播放数量</th>
<th>评论数量</th>
<th>上映时间</th>
<th>操作事项</th>
</tr>
{% for data in page_data.items %} <tr>
<td>{{ data.id }}</td>
<td>{{ data.title }}</td>
<td>{{ data.length }}分钟</td>
<td>{{ data.tag.name }}</td>
<td>{{ data.area }}</td>
<td>{{ data.star }}</td>
<td>{{ data.playnum }}</td>
<td>{{ data.commentnum }}</td>
<td>{{ data.release_time }}</td>
<td>
<a href="{{ url_for('admin.movie_edit', id=data.id) }}" class="label label-success">编辑</a>
&nbsp;
<a href="{{ url_for('admin.movie_del', id=data.id) }}"
class="label label-danger">删除</a>
</td>
</tr>
{% endfor %} </tbody>
</table>
</div>
<div class="box-footer clearfix">
{{ pagination(page_data, 'admin.movie_list') }}
</div>
</div>
</div>
</div>
</section>
{% endblock %} {% block js %}
<script>
$(document).ready(function () {
$('#g-3').addClass('active');
$('#g-3-2').addClass('active');
})
</script>
{% endblock %}

修改app/templates/admin/grid.html

<li id="g-3-2">
<a href="{{ url_for('admin.movie_list', page=1) }}">
<i class="fa fa-circle-o"></i> 电影列表
</a>
</li>
删除电影

视图函数

@admin.route('/movie/del/<int:id>/')
@admin_login_req
def movie_del(id=None):
movie = Movie.query.get_or_404(int(id))
db.session.delete(movie)
db.session.commit()
flash('电影删除成功!', 'info')
return redirect(url_for('admin.movie_list', page=1))

修改一下前端删除按钮a标签

修改电影

视图函数

@admin.route('/movie/edit/<int:id>', methods=['GET', 'POST'])
@admin_login_req
def movie_edit(id=None):
form = MovieForm() # # 如果不设置,默认依然会让上传文件
# form.url.flags.required = False
# form.logo.flags.required = False # # 取消校验,可能没有上传文件
# form.url.validators=[]
# form.logo.validators=[]
# 取消后如果没有上传文件,form.url.data是一个str对象
# 上传文件后是才是一个文件对象
# 为了方便,设置必须上传文件 movie=Movie.query.get_or_404(int(id))
if request.method =='GET':
form.info.data = movie.info
form.tag_id.data = movie.tag_id
form.star.data = movie.star
if form.validate_on_submit():
data = form.data
movie_count = Movie.query.filter_by(title=data['title']).count()
if movie_count == 1 and movie.title != data['title']:
flash('该电影已存在!', 'error')
return redirect(url_for('admin.movie_edit', id=id)) if not os.path.exists(app.config['UP_DIR']):
os.makedirs(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'], 6) if form.url.data.filename !='':
file_url = secure_filename(form.url.data.filename)
movie.url = change_filename(file_url)
form.url.data.save(app.config['UP_DIR'] + movie.url) if form.logo.data.filename != '':
file_logo = secure_filename(form.logo.data.filename)
movie.logo = change_filename(file_logo)
form.logo.data.save(app.config['UP_DIR'] + movie.logo) movie.star = data['star']
movie.tag_id = data['tag_id']
movie.info = data['info']
movie.title = data['title']
movie.area = data['area']
movie.length = data['length']
movie.release_time = data['release_time'] db.session.add(movie)
db.session.commit()
flash('电影修改成功!', 'info')
return redirect(url_for('admin.movie_add', id=movie.id))
return render_template('admin/movie_edit.html', form=form, movie=movie)

app/templates/admin/movie_edit.html

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

{% block content %}
<section class="content-header">
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 电影管理</a></li>
<li class="active">修改电影</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">修改电影</h3>
</div>
<form role="form" method="post" enctype="multipart/form-data">
<div class="box-body">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
{% for message in get_flashed_messages(category_filter=['error']) %}
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-ban"></i> 操作失败!</h4>
{{ message }}
</div>
{% endfor %}
<div class="form-group">
<label for="input_title">{{ form.title.label }}</label>
{{ form.title(value=movie.title) }}
{% for err in form.title.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_url">{{ form.url.label }}</label>
{{ form.url }}
{% for err in form.url.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
<div style="margin-top:5px;">
<div id="moviecontainer"></div>
</div>
</div>
<div class="form-group">
<label for="input_info">{{ form.info.label }}</label>
{{ form.info }}
{% for err in form.info.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_logo">{{ form.logo.label }}</label>
{{ form.logo }}
{% for err in form.logo.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
<img src="{{ url_for('static', filename='uploads/'+movie.logo) }}" style="margin-top:5px;" class="img-responsive"
alt="">
</div>
<div class="form-group">
<label for="input_star">{{ form.star.label }}</label>
{{ form.star }}
{% for err in form.star.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_tag_id">{{ form.tag_id.label }}</label>
{{ form.tag_id }}
{% for err in form.tag_id.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_area">{{ form.area.label }}</label>
{{ form.area(value=movie.area) }}
{% for err in form.area.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_length">{{ form.length.label }}</label>
{{ form.length(value=movie.length) }}
{% for err in form.length.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_release_time">{{ form.release_time.label }}</label>
{{ form.release_time(value=movie.release_time) }}
{% for err in form.release_time.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %} {% block js %}
<script src="{{ url_for('static',filename='jwplayer/jwplayer.js') }}"></script>
<script type="text/javascript">
jwplayer.key = "P9VTqT/X6TSP4gi/hy1wy23BivBhjdzVjMeOaQ=="; </script>
<script type="text/javascript">
jwplayer("moviecontainer").setup({
flashplayer: "{{ url_for('static',filename='jwplayer/jwplayer.flash.swf') }}",
playlist: [{
file: "{{ url_for('static', filename='uploads/'+movie.url) }}",
title: "{{ movie.title }}"
}],
modes: [{
type: "html5"
}, {
type: "flash",
src: "{{ url_for('static',filename='jwplayer/jwplayer.flash.swf') }}"
}, {
type: "download"
}],
skin: {
name: "vapor"
},
"playlist.position": "left",
"playlist.size": 200,
height: 250,
width: 387,
}); </script>
<script>
$(document).ready(function () {
$('#input_release_time').datepicker({
autoclose: true,
format: 'yyyy-mm-dd',
language: 'zh-CN',
});
}); </script>
<script>
$(document).ready(function () {
$('#g-3').addClass('active');
$('#g-3-1').addClass('active');
})
</script>
{% endblock %}

修改电影列表中的编辑按钮

<a href="{{ url_for('admin.movie_edit', id=data.id) }}" class="label label-success">编辑</a>

预告管理

创建预告表单

class PreviewForm(FlaskForm):
title = StringField(
label='预告标题',
validators=[
DataRequired("请输入预告标题!")
],
description="预告标题",
render_kw={
"class": "form-control",
"placeholder": "请输入预告标题!"
}
)
logo = FileField(
label='预告封面',
validators=[
DataRequired("请上传预告封面!"),
],
description="预告封面",
)
submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary"
}
) def validate_title(self, field):
title = field.data
num = Preview.query.filter_by(title=title).count()
if num > 0:
raise ValidationError("该预告已存在!")
添加预告

视图函数

@admin.route('/preview/add/', methods=['GET', 'POST'])
@admin_login_req
def preview_add():
form = PreviewForm()
if form.validate_on_submit():
data = form.data
file_logo = secure_filename(form.logo.data.filename) if not os.path.exists(app.config['UP_DIR']):
os.makedirs(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'], 6) logo = change_filename(file_logo)
form.logo.data.save(app.config['UP_DIR']+logo)
preview = Preview(
title=data['title'],
logo=logo
)
db.session.add(preview)
db.session.commit()
flash("预告添加成功!", 'info')
return redirect(url_for('admin.preview_add'))
return render_template('admin/preview_add.html', form = form)

app/templates/admin/preview_add.html

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

{% block content %}
<section class="content-header">
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 预告管理</a></li>
<li class="active">添加预告</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">添加预告</h3>
</div>
<form role="form" method="post" enctype="multipart/form-data">
<div class="box-body">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
{% for message in get_flashed_messages(category_filter=['error']) %}
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-ban"></i> 操作失败!</h4>
{{ message }}
</div>
{% endfor %}
<div class="form-group">
<label for="input_title">{{ form.title.label }}</label>
{{ form.title }}
{% for err in form.title.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_logo">{{ form.logo.label }}</label>
{{ form.logo }}
{% for err in form.logo.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %}
<img data-src="holder.js/700x320" style="margin-top:5px;" class="img-responsive"
alt="">
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %} {% block js %}
<script>
$(document).ready(function () {
$('#g-4').addClass('active');
$('#g-4-1').addClass('active');
})
</script>
{% endblock %}
预告列表

视图函数

@admin.route('/preview/list/<int:page>/')
@admin_login_req
def preview_list(page=1):
if page <= 0:
page = 1
page_data = Preview.query.order_by(
Preview.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/preview_list.html', page_data=page_data)

app/templates/admin/preview_list.html

{% extends 'admin/admin.html' %}
{% from 'ui/admin_page.html' import pagination %}
{% block content %}
<section class="content-header">
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 预告管理</a></li>
<li class="active">预告列表</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">预告列表</h3>
<div class="box-tools">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="table_search" class="form-control pull-right"
placeholder="请输入关键字..."> <div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</div>
</div>
<div class="box-body table-responsive no-padding">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>预告标题</th>
<th>预告封面</th>
<th>添加时间</th>
<th>操作事项</th>
</tr>
{% for data in page_data.items %}
<tr>
<td>{{ data.id }}</td>
<td>{{ data.title }}</td>
<td>
<img src="{{ url_for('static', filename='uploads/'+data.logo) }}"
class="img-responsive center-block" alt="" style="width: 140px">
</td>
<td>{{ data.addtime }}</td>
<td>
<a href="{{ url_for('admin.preview_edit', id=data.id) }}" class="label label-success">编辑</a>
&nbsp;
<a href="{{ url_for('admin.preview_del', id=data.id) }}"
class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box-footer clearfix">
{{ pagination(page_data, 'admin.preview_list') }}
</div>
</div>
</div>
</div>
</section>
{% endblock %} {% block js %}
<script>
$(document).ready(function () {
$('#g-4').addClass('active');
$('#g-4-2').addClass('active');
})
</script>
{% endblock %}

修改app/templates/admin/grid.html

<li id="g-4-2">
<a href="{{ url_for('admin.preview_list', page=1) }}">
<i class="fa fa-circle-o"></i> 预告列表
</a>
</li>
删除预告

视图函数

@admin.route('/preview/del/<int:id>/')
@admin_login_req
def preview_del(id=None):
preview = Preview.query.get_or_404(int(id))
db.session.delete(preview)
db.session.commit()
flash('预告删除成功!', 'info')
return redirect(url_for('admin.preview_list', page=1))
修改预告

视图函数

@admin.route('/preview/edit/<int:id>/', methods=['GET', 'POST'])
@admin_login_req
def preview_edit(id=None):
form = PreviewForm()
preview = Preview.query.get_or_404(int(id)) if request.method == 'GET':
form.title.data = preview.title
if form.validate_on_submit():
data = form.data if not os.path.exists(app.config['UP_DIR']):
os.makedirs(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'], 6) if form.logo.data.filename != '':
file_logo = secure_filename(form.logo.data.filename)
preview.logo = change_filename(file_logo)
form.logo.data.save(app.config['UP_DIR'] + preview.logo) preview.title=data['title']
db.session.add(preview)
db.session.commit() flash('预告修改成功!', 'info')
return redirect(url_for('admin.preview_edit', id=id))
return render_template('admin/preview_edit.html', form=form, preview=preview)

app/templates/admin/preview_edit.html,代码拷贝添加预告,修改部分

<div class="form-group">
<label for="input_title">{{ form.title.label }}</label>
{{ form.title(value=preview.title) }}
{% for err in form.title.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_logo">{{ form.logo.label }}</label>
{{ form.logo }}
{% for err in form.logo.errors %}
<div class="col-md-12" id="input_user" style="color: red">{{ err }}</div>
{% endfor %}
<img src="{{ url_for('static', filename='uploads/'+preview.logo) }}" style="margin-top:5px;" class="img-responsive"
alt="">
</div>

会员管理

会员列表
@admin.route('/user/list/<int:page>/')
@admin_login_req
def user_list(page=1):
if page <= 0:
page = 1
page_data = User.query.order_by(
User.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/user_list.html', page_data=page_data)

app/templates/admin/user_list.html

{% extends 'admin/admin.html' %}
{% from 'ui/admin_page.html' import pagination %} {% block content %}
<section class="content-header">
<h1>微电影管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 会员管理</a></li>
<li class="active">会员列表</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">会员列表</h3>
<div class="box-tools">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="table_search" class="form-control pull-right"
placeholder="请输入关键字..."> <div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</div>
</div>
<div class="box-body table-responsive no-padding">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>昵称</th>
<th>邮箱</th>
<th>手机</th>
<th>头像</th>
{# <th>状态</th>#}
<th>注册时间</th>
<th>操作事项</th>
</tr>
{% for data in page_data.items %} <tr>
<td>{{ data.id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.email }}</td>
<td>{{ data.phone }}</td>
<td>
<img src="{{ url_for('static', filename='uploads/users/'+data.face) }}"
style="width: 50px" class="img-responsive center-block" alt="">
</td>
{# <td>正常/冻结</td>#}
<td>{{ data.addtime }}</td>
<td>
<a class="label label-success"
href="{{ url_for('admin.user_view', id=data.id) }}">查看</a>
{# &nbsp;#}
{# <a class="label label-info">解冻</a>#}
{# &nbsp;#}
{# <a class="label label-warning">冻结</a>#}
&nbsp;
<a href="{{ url_for('admin.user_del', id=data.id) }}"
class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box-footer clearfix">
{{ pagination(page_data, 'admin.preview_list') }}
</div>
</div>
</div>
</div>
</section>
{% endblock %} {% block js %}
<script>
$(document).ready(function () {
$('#g-5').addClass('active');
$('#g-5-1').addClass('active');
})
</script>
{% endblock %}
查看会员
@admin.route('/user/view/<int:id>/')
@admin_login_req
def user_view(id=None):
user = User.query.get_or_404(int(id))
return render_template('admin/user_view.html', user=user)
<table class="table table-hover">
<tbody>
<tr>
<td class="td_bd">编号:</td>
<td>1</td>
</tr>
<tr>
<td class="td_bd">昵称:</td>
<td>{{ user.name }}</td>
</tr>
<tr>
<td class="td_bd">邮箱:</td>
<td>{{ user.email }}</td>
</tr>
<tr>
<td class="td_bd">手机:</td>
<td>{{ user.phone }}</td>
</tr>
<tr>
<td class="td_bd">头像:</td>
<td>
<img src="{{ url_for('static', filename='uploads/users/'+user.face) }}" style="width: 100px" class="img-responsive" alt="">
</td>
</tr>
<tr>
<td class="td_bd">注册时间:</td>
<td>
{{ user.addtime }}
</td>
</tr>
<tr>
<td class="td_bd">唯一标志符:</td>
<td>
{{ user.uuid }}
</td>
</tr>
<tr>
<td class="td_bd">个性简介:</td>
<td>
{{ user.info }}
</td>
</tr>
</tbody>
</table>
删除用户
@admin.route('/user/del/<int:id>/')
@admin_login_req
def user_del(id=None):
user = User.query.get_or_404(int(id))
db.session.delete(user)
db.session.commit()
flash('会员删除成功!', 'info')
return redirect(url_for('admin.user_list', page=1))

评论管理

评论列表
@admin.route('/comment/list/<int:page>/')
@admin_login_req
def comment_list(page=1):
if page <= 0:
page = 1
page_data = Comment.query.join(
Movie
).join(
User
).filter(
Movie.id==Comment.movie_id,
User.id ==Comment.user_id
).order_by(
Comment.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/comment_list.html', page_data=page_data)
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">评论列表</h3>
<div class="box-tools">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="table_search" class="form-control pull-right"
placeholder="请输入关键字..."> <div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</div>
</div>
<div class="box-body box-comments"> {% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
{% for data in page_data.items %} <div class="box-comment">
<img class="img-circle img-sm"
src="{{ url_for('static',filename='uploads/users/'+data.user.face) }}"
alt="User Image">
<div class="comment-text">
<span class="username">
{{ data.user.name }}
<span class="text-muted pull-right">
<i class="fa fa-calendar" aria-hidden="true"></i>
&nbsp;
{{ data.addtime }}
</span>
</span>
关于电影<a>《{{ data.movie.title }}》</a>的评论:{{ data.content }}
<br><a href="{{ url_for('admin.comment_del', id=data.id) }}"
class="label label-danger pull-right">删除</a>
</div>
</div>
{% endfor %}
</div>
<div class="box-footer clearfix">
{{ pagination(page_data, 'admin.preview_list') }}
</div>
</div>
</div>
</div>
</section>
删除评论
@admin.route('/comment/del/<int:id>/')
@admin_login_req
def comment_del(id=None):
comment = Comment.query.get_or_404(int(id))
db.session.delete(comment)
db.session.commit()
flash('评论删除成功!', 'info')
return redirect(url_for('admin.comment_list', page=1))

收藏管理

收藏列表
@admin.route('/moviecol/list/<int:page>/')
@admin_login_req
def moviecol_list(page=1):
if page <= 0:
page = 1
page_data = Moviecol.query.join(
Movie
).join(
User
).filter(
Movie.id==Moviecol.movie_id,
User.id ==Moviecol.user_id
).order_by(
Moviecol.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/moviecol_list.html', page_data=page_data)
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">收藏列表</h3>
<div class="box-tools">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="table_search" class="form-control pull-right"
placeholder="请输入关键字..."> <div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</div>
</div>
<div class="box-body table-responsive no-padding">
{% for message in get_flashed_messages(category_filter=['info']) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功!</h4>
{{ message }}
</div>
{% endfor %}
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>电影</th>
<th>用户</th>
<th>添加时间</th>
<th>操作事项</th>
</tr>
{% for data in page_data.items %}
<tr>
<td>{{ data.id }}</td>
<td>{{ data.movie.title }}</td>
<td>{{ data.user.name }}</td>
<td>{{ data.addtime }}</td>
<td>
{# <a class="label label-success">编辑</a>#}&nbsp;
<a href="{{ url_for('admin.moviecol_del', id=data.id) }}"
class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box-footer clearfix">
{{ pagination(page_data, 'admin.moviecol_list') }}
</div>
</div>
</div>
</div>
</section>
删除收藏
@admin.route('/moviecol/del/<int:id>/')
@admin_login_req
def moviecol_del(id=None):
moviecol = Moviecol.query.get_or_404(int(id))
db.session.delete(moviecol)
db.session.commit()
flash('收藏删除成功!', 'info')
return redirect(url_for('admin.moviecol_list', page=1))

修改密码

新建一个form表单

class PwdForm(FlaskForm):
old_pwd = PasswordField(
label='旧密码',
validators=[
DataRequired("请输入旧密码!"),
],
description='旧密码',
render_kw={
"class": "form-control",
"placeholder": "请输入旧密码!"
}
) new_pwd = PasswordField(
label='新密码',
validators=[
DataRequired("请输入新密码!"),
],
description='新密码',
render_kw={
"class": "form-control",
"placeholder": "请输入新密码!"
}
)
submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary",
}
) def validate_old_pwd(self, field):
from flask import session
pwd = field.data
name = session['admin']
admin = Admin.query.filter_by(name=name).first()
if not admin.check_pwd(pwd):
raise ValidationError("密码输入错误!")
@admin.route('/pwd/', methods=['GET', 'POST'])
@admin_login_req
def pwd():
form = PwdForm()
if form.validate_on_submit():
data = form.data
admin = Admin.query.filter_by(name=session['admin']).first() from werkzeug.security import generate_password_hash
admin.pwd = generate_password_hash(data['new_pwd']) db.session.add(admin)
db.session.commit() flash("密码修改成功,请重新登录!", 'info')
return redirect(url_for('admin.logout'))
return render_template('admin/pwd.html', form=form)

将信息展示出来login.html

        {% for message in get_flashed_messages(category_filter=['info']) %}
<p class="login-box-msg" style="color: green">{{ message }}</p>
{% endfor %}
{% for message in get_flashed_messages(category_filter=['error']) %}
<p class="login-box-msg" style="color: red">{{ message }}</p>
{% endfor %}

运行发现并没有显示密码修改成功,请重新登录!这条提示

是因为flash是基于session的,前面退出的视图函数中我们清除了所有的session

日志管理

@admin.route('/oplog/list/<int:page>/')
@admin_login_req
def oplog_list(page=1):
if page <= 0:
page = 1
page_data = Oplog.query.join(
Admin
).filter(
Admin.id==Oplog.admin_id,
).order_by(
Oplog.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/oplog_list.html', page_data=page_data) @admin.route('/adminloginlog/list/<int:page>/')
@admin_login_req
def adminloginlog_list(page=1):
if page <= 0:
page = 1
page_data = Adminlog.query.join(
Admin
).filter(
Admin.id==Adminlog.admin_id,
).order_by(
Adminlog.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/adminloginlog_list.html', page_data=page_data) @admin.route('/userloginlog/list/<int:page>/')
@admin_login_req
def userloginlog_list(page=1):
if page <= 0:
page = 1
page_data = Userlog.query.join(
User
).filter(
User.id==Userlog.user_id,
).order_by(
Userlog.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/userloginlog_list.html',page_data=page_data)

修改对应的前端文件

在其它视图函数中添加对应到操作日志,例如添加标签

        flash("标签添加成功!", 'info')

        oplog = Oplog(
admin_id=session['admin_id'],
ip=request.remote_addr,
reason='添加标签< {} >'.format(data['name'])
) db.session.add(oplog)
db.session.commit()
return redirect(url_for('admin.tag_add'))

基于角色的访问控制

权限管理

class AuthForm(FlaskForm):
name = StringField(
label='权限',
validators=[
DataRequired("请输入权限!"),
],
description='权限',
render_kw={
"class": "form-control",
"placeholder": "请输入权限!"
}
) url = StringField(
label='权限地址',
validators=[
DataRequired("请输入权限地址!"),
],
description='权限地址',
render_kw={
"class": "form-control",
"placeholder": "请输入权限地址!"
}
)
submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary",
}
)
添加权限
@admin.route('/auth/add/', methods=['GET', 'POST'])
@admin_login_req
def auth_add():
form= AuthForm()
if form.validate_on_submit():
data = form.data
auth = Auth(
name=data['name'],
url=data['url']
) db.session.add(auth)
db.session.commit() flash('权限添加成功!', 'info')
return render_template('admin/auth_add.html',form=form)
权限列表
@admin.route('/auth/list/<int:page>/')
@admin_login_req
def auth_list(page=1):
if page <= 0:
page = 1
page_data = Auth.query.order_by(
Auth.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/auth_list.html',page_data=page_data)
删除权限
@admin.route('/auth/del/<int:id>/')
@admin_login_req
def auth_del(id=None):
auth = Auth.query.get_or_404(int(id))
db.session.delete(auth)
db.session.commit()
flash('权限删除成功!', 'info')
return redirect(url_for('admin.auth_list', page=1))
编辑权限
@admin.route('/auth/edit/<int:id>/', methods=['GET', 'POST'])
@admin_login_req
def auth_edit(id=None):
form = AuthForm()
auth = Auth.query.get_or_404(int(id)) if form.validate_on_submit():
data = form.data
auth.name =data['name']
auth.url=data['url'] db.session.add(auth)
db.session.commit() flash('权限修改成功!', 'info')
return redirect(url_for('admin.auth_edit', id=id))
return render_template('admin/auth_edit.html',form=form, auth=auth)

修改对应的前端文件

角色管理

class RoleForm(FlaskForm):
name = StringField(
label='角色名称',
validators=[
DataRequired("请输入角色名称!"),
],
description='角色名称',
render_kw={
"class": "form-control",
"placeholder": "请输入角色名称!"
}
) auths = SelectMultipleField(
label='权限列表',
validators=[
DataRequired("请选择权限!"),
],
coerce=int,
choices=[(v.id, v.name) for v in auths],
description='权限列表',
render_kw={
"class": "form-control",
}
)
submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary",
}
)
添加角色
@admin.route('/role/add/', methods=['GET', 'POST'])
@admin_login_req
def role_add():
form = RoleForm()
if form.validate_on_submit():
data=form.data
role = Role(
name=data['name'],
auths=','.join(map(lambda v:str(v), data['auths']))
) db.session.add(role)
db.session.commit()
flash('角色添加成功!', 'info')
return render_template('admin/role_add.html',form=form)
角色列表
@admin.route('/role/list/<int:page>/')
@admin_login_req
def role_list(page=1):
if page <= 0:
page = 1
page_data = Role.query.order_by(
Role.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/role_list.html',page_data=page_data)
删除角色
@admin.route('/role/del/<int:id>/')
@admin_login_req
def role_del(id=None):
role = Role.query.get_or_404(int(id))
db.session.delete(role)
db.session.commit()
flash('角色删除成功!', 'info')
return redirect(url_for('admin.role_list', page=1))
修改权限
@admin.route('/role/edit/<int:id>/', methods=['GET', 'POST'])
@admin_login_req
def role_edit(id=None):
form = RoleForm()
role = Role.query.get_or_404(int(id)) if request.method == 'GET':
auths = role.auths
form.auths.data = list(map(lambda x: int(x), auths.split(','))) if form.validate_on_submit():
data=form.data
role.name = data['name']
role.auths = ','.join(map(lambda v:str(v), data['auths'])) db.session.add(role)
db.session.commit()
flash('角色修改成功!', 'info')
return render_template('admin/role_edit.html',form=form,role=role)

修改对应的前端文件

管理员管理

class AdminForm(FlaskForm):
name = StringField(
label='管理员名称',
validators=[
DataRequired("请输入管理员名称!"),
],
description='管理员名称',
render_kw={
"class": "form-control",
"placeholder": "请输入管理员名称!"
}
) pwd = PasswordField(
label='管理员密码',
validators=[
DataRequired("请输入管理员密码!")
],
description="管理员密码",
render_kw={
"class": "form-control",
"placeholder": "请输入管理员密码!",
"required": "required"
}
) repwd = PasswordField(
label='管理员重复密码',
validators=[
DataRequired("请输入管理员重复密码!"),
EqualTo('pwd', message='两次密码不一致!'),
],
description="管理员重复密码",
render_kw={
"class": "form-control",
"placeholder": "请输入管理员重复密码!",
"required": "required"
}
) role_id=SelectField(
label='所属角色',
validators=[
DataRequired("请选择角色!")
],
coerce=int,
choices=[(v.id, v.name) for v in roles],
description="所属角色",
render_kw={
"class": "form-control",
}
) submit = SubmitField(
'编辑',
render_kw={
"class": "btn btn-primary",
}
)
添加管理员
@admin.route('/admin/add/', methods=['GET', 'POST'])
@admin_login_req
def admin_add():
form = AdminForm() from werkzeug.security import generate_password_hash if form.validate_on_submit():
data = form.data
admin = Admin(
name=data['name'],
pwd=generate_password_hash(data['pwd']),
role_id=data['role_id'],
is_super=1,
) db.session.add(admin)
db.session.commit() flash('管理员添加成功!', 'info') return render_template('admin/admin_add.html',form=form)
管理员列表
@admin.route('/admin/list/<int:page>/')
@admin_login_req
def admin_list(page=1):
if page <= 0:
page = 1
page_data = Admin.query.join(
Role
).filter(
Role.id==Admin.role_id
).order_by(
Admin.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/admin_list.html',page_data=page_data)

修改对应的前端代码

访问权限控制

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['admin_id']
).first() auths = admin.role.auths
auths = list(map(lambda x: int(x), 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 print(urls)
print(rule) if str(rule) not in urls:
abort(404)
return func(*args, **kwargs)
return decorated_function

给视图函数添加装饰器,像这样

@admin.route('/tag/list/<int:page>/')
@admin_login_req
@admin_auth
def tag_list(page=1):
...

Flask 构建微电影视频网站(四)的更多相关文章

  1. Python flask 构建微电影视频网站✍✍✍

    Python flask 构建微电影视频网站  整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大 ...

  2. Python flask 构建微电影视频网站☝☝☝

    Python flask 构建微电影视频网站☝☝☝ 1.安装数据库连接依赖包 pip install flask-sqlalchemy 2.创建movie数据库 在CentOS虚拟机,进入MaridD ...

  3. Flask 构建微电影视频网站(一)

    Flask构建电影视频网站 Python MTV模型 Flask微内核 Flask扩展插件配置及使用方法 根据业务开发网站前后台功能 Flask结合MySQL数据库 你将可以独立开发网站 独立部署运维 ...

  4. Python Flask 构建微电影视频网站

    前言 学完本教程,你将掌握: 1.学会使用整形.浮点型.路径型.字符串型正则表达式路由转化器 2.学会使用post与get请求.上传文件.cookie获取与相应.404处理 3.学会适应模板自动转义. ...

  5. Flask 构建微电影视频网站(二)

    搭建前台页面 前台布局搭建 将static中的文件拷贝到项目的static目录下 在app/templates/home下新建home.html,当作基础模板,并修改静态资源链接 <!docty ...

  6. Flask 构建微电影视频网站(八)

    评论收藏及弹幕 实现电影评论添加及列表.数据查询实现统计播放量和评论量.jquery ajax实现收藏电影,flask结合redis消息队列实现电影弹幕,bug处理等功能. 电影评论-统计 class ...

  7. Flask 构建微电影视频网站(三)

    搭建后台页面 视图函数位于admin文件夹下, app/admin/views.py 管理员登录页面搭建 视图函数 @admin.route('/') def index(): return '后台主 ...

  8. Flask 构建微电影视频网站(七)

    电影模块实现 上映预告 @home.route("/animation/") def animation(): """ 首页轮播动画 "&q ...

  9. Flask 构建微电影视频网站(六)

    会员模块实现 会员注册 class RegistForm(FlaskForm): name = StringField( label="昵称", validators=[ Data ...

随机推荐

  1. Java发送电子邮件

    转自 https://blog.csdn.net/xietansheng/article/details/51673073 纯代码, 详情请至原文查看 需要一个javamail的jar包 以下为实现代 ...

  2. 【20190228】JavaScript-数组的操作

    1. 创建数组 var array = new Array(); var array = new Array(5); var array = new Array(1,2,3,"a" ...

  3. Dynamics 365使用Execute Multiple Request删除系统作业实体记录

    摘要: 本人微信公众号:微软动态CRM专家罗勇 ,回复295或者20190112可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me ...

  4. C#判断远程计算机的指定端口是否打开的代码

    如下的内容段是关于C#判断远程计算机的指定端口是否打开的内容,应该能对小伙伴有一些用. using System.Net;if(!string.IsNullOrEmpty(txtPort.Text)) ...

  5. 《Flask Web开发》学习笔记

    第一部分 Flask简介 前言:想熟练掌握一门web框架,为以后即将诞生的测试工具集做准备.为什么选择flask要做熟练掌握的一门框架,而不是其他的,最主要的原因是可以随意定制. 特别提醒:这本书的代 ...

  6. PJSUA2开发文档--第八章 好友(Buddy)类

    8  好友(存在)Buddy PJSUA2的功能是围绕Buddy类为中心展开的.该类表示一个远端好友(伙伴,一个人或一个SIP端点). 8.1 子类化Buddy类 要使用Buddy类,通常应创建子类, ...

  7. MongoDB更需要好的模式设计 及 案例赏析

    一  挑战 设计从来就是个挑战. 当我们第一次接触数据库,学习数据库基础理论时,都需要学习范式,老师也一再强调范式是设计的基础.范式是这门课程中的重要部分,在期末考试中也一定是个重要考点.如果我们当年 ...

  8. Java https ssl证书导入删除

    下载并命名 例如命名github.cer 放进jre的lib\security下 keytool -delete [OPTION]... 选项: -alias <alias> 要处理的条目 ...

  9. [20190409]pre_page_sga=true与连接缓慢的问题.txt

    [20190409]pre_page_sga=true与连接缓慢的问题.txt --//曾经遇到11g下设置pre_page_sga=true启动缓慢的问题(没有使用hugepages).--//链接 ...

  10. Oracle 查询权限视图

    在Oracle中有很多用于查权限的视图,但很多人在需要查权限时会很困惑,不知道该用哪个视图去查,这里我列出几个常见的用于查权限的视图及其用法: 1DBA_ROLE_PRIVS 该视图主要有以下2个作用 ...