目录
8.templates/admin/login.html 修改页面
1.新建项目
进入后界面
运行点击网址
显示结果
这样就没问题了
2.进行项目
1.新建readme.txt文件对整个项目进行文字说明
2.按照文字说明进行步骤
1.导入数据库
1.1 movie.sql文件导入到mysql数据库中
2.新建app包
static,templates放到app包中存放
2.1 static===>存放公共的资源 js/css/jquery/image
2.2 templates===>存储界面文件 html/jsp
2.3 将app.py删除
3.新建manage.py文件
3.1 JSNUMovie文件夹下创建manage.py
见上图
3.2 manage.py文件代替app.py的功能
'''
Manage项目运行的主入口
'''
# 导入上方的app包里面的内容
from app import app
from flask_script import Manager
# 1.设置业务管理文件
manage=Manager(app)
# 2.运行Flask管理模块
if __name__=='__main__':
manage.run()
3.3 flask_script报错
cmd===>pip install flask-script 下载第三方模块
4.app包下 init.py文件添加代码
下载第三方模块
cmd===>pip install flask-sqlalchemy (数据库的驱动功能包)
cmd===>pip install flask-redis (缓存机制功能包)
4.1 设置项目名称
4.2 设置数据连接
4.3 设置项目缓存
4.4 设置DEBUG模式
4.5 数据库连接
4.6 设置缓存机制
4.7 设置蓝图(提高编程效率)
'''
app/__init__.py
1 设置项目名称
2 设置数据连接
3 设置项目缓存
4 设置DEBUG模式
5 数据库连接
6 设置缓存机制
7 设置蓝图(提高编程效率)
cmd===>pip install flask-sqlalchemy (数据库的驱动功能包)
cmd===>pip install flask-redis (缓存机制功能包)
'''
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
# 设置作者
__author__='zq'
'''1.设置名称'''
app=Flask(__name__)
'''2.设置数据库连接'''
# 2.1 设置mysql连接参数
# mysql+mysqlconnector===>msyql数据库+mysql的驱动模块
# root:mysql====>用户名和密码
# 127.0.0.1:3306===>ip地址+3306端口号 localhost公认的本机地址
# movie==>数据库名称
app.config['SQLALCHEMY_DATABASE_URI']=\
'mysql+mysqlconnector://root:123456@127.0.0.1:3306/movie'
# 2.2 设置mysql对象修改与信号发送
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True
'''3.设置项目缓存'''
# 3.1 设置缓存的URL
app.config['REDIS_URL']='redis://127.0.0.1:6379/0'
# 3.2 设置秘钥
app.config['SECRET_KEY']='zpp_movie'
# 3.3 设置上传的目录
# os.path.join ===>目录拼接函数
# os.path.abspath===>绝对路径 E:\PycharmProjects\JSNUMovie
# os.path.dirname(__file__)===>E:\PycharmProjects\JSNUMovie\app\static\uploads\
# __file__ ===>app包
# 后端上传的目录
app.config['UP_DIR']=\
os.path.join(
os.path.abspath(os.path.dirname(__file__)),'static/uploads/')
#前端上传目录
app.config['FC_DIR']=\
os.path.join(
os.path.abspath(os.path.dirname(__file__)),"static/uploads/users"
)
# 4.设置DEBUG模式
app.debug=False
# 5.数据库连接
db=SQLAlchemy(app)
# 6.设置缓存机制
rd=FlaskRedis(app)
'''7.设置蓝图'''
# 调用app包下admin包 导入admin功能 别名 admin_blueprint
# 7.1 设置导入蓝图
from app.admin import admin as admin_blueprint
# 7.2 注册蓝图
# 127.0.0.1:5000/admin/
app.register_blueprint(admin_blueprint,url_prefix='/admin')
5.app包下 新建 admin包
5.1 admin包下__init__.py设置当前模块蓝图的名称
5.2 admin包下 新建views文件
5.3 admin/views login函数
admin下的__init__.py
'''
app/admin/__init__.py
'''
from flask import Blueprint
# 设置当前模块的蓝图 名称 admin
admin=Blueprint('admin',__name__)
import app.admin.views
admin下的views.py
'''
app/admin/views
管理员模块 视图文件
后台登录系统
'''
# 1.登录功能实现
from flask import render_template
from . import admin
@admin.route("/login/",methods=['GET','POST'])
def login():
# 1.测试语句
print("登录模块")
return render_template("admin/login.html")
6.templates文件夹下 新建admin包
6.1 admin包下 新建login.html
运行login.html
7.设置修改运行的文件
7.1 打开右上角Add Configuration....
选择Edit Configurations
选择左上角的+
选择python
修改Name===>MovieManager
添加Parameters===>runserver
添加Script path===>选择JSNUMovie文件夹下manage.py文件
7.2 点击右上角的播放按钮
7.3 打开控制台 127.0.0.1:5000 打开浏览器
7.4 输入URL 127.0.0.1:5000/admin/login
查看是否进入login.html
8.templates/admin/login.html 修改页面
8.1 网站素材 复制粘贴到 static文件夹下
8.2 修改login.html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>后台页面</title>
<!--解决IE浏览器兼容问题-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--width-device-width:页面的可视区域-->
<!--initial-scale=?:显示可视区域缩放级别1.0-->
<!--maximum-scale=?最大缩放值-->
<!--minimum-scale=?最小缩放值-->
<!--use-scalable=yes/no:表示用户可以手动缩放-->
<!--name='viewport':手机端页面虚拟窗口-->
<meta content="width=device-width,initial-scale-1,user-scalable=no" name="viewport">
<link rel="shortct icon" href="{{ url_for('static',filename='base/images/login.png') }}">
<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/plugins/iCheck/square/blue.css') }}">
</head>
<body class="hold-transition login-page" style="text-align: center">
<div class="login-box">
<div class="login-logo">
<b>星空电影管理系统</b>
</div>
<div class="login-box-body">
<!--设置登录信息显示-->
<!--失败-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<p class="login-box-msg" style="color: red">{{ msg }}</p>
{% endfor %}
<!--成功-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<p class="login-box-msg" style="color: green">{{ msg }}</p>
{% endfor %}
<!--设置表单提交-->
<form method="post" id="form-data">
<!--账号-->
<div class="form-group has-feedback" style="height: 30px">
{{ form.account }}
<span class="glyphicon glyphicon-envelope form-control-feedback">
</span>
{% for err in form.account.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--密码-->
<div class="form-group has-feedback" style="height: 30px">
{{ form.pwd }}
<span class="glyphicon glyphicon-envelope form-control-feedback">
</span>
{% for err in form.pwd.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--登录按钮-->
<div class="row">
<div class="col-xs-8"></div>
<div class="col-xs-4">
<!--令牌,保护验证的-->
{{ form.csrf_token }}
{{ form.submit }}
</div>
</div>
</form>
</div>
</div>
<!--加载js文件-->
<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/iCheck/icheck.min.js') }}"></script>
</body>
</html>
9.admin/views文件中
9.1 修改login函数
9.2 新建forms文件
cmd===>pip install flask-wtf
9.3 编写LoginForm类
'''
后台登录 表单
flask_wtf是flask框架的表单验证模块,可以很方便生成表单,也可以当做json数据交互的验证工具
flask框架中内部并没有提供全面的表单验证,所以当我们不借助第三方插件来处理代码会显得混乱
官方推荐的一个表单验证插件就是wtforms
wtform是一个支持多种web框架的form组件,主要用于对用户请求数据进行验证
wtforms按照功能类别分类由以下几个类别:
Forms:主要用于表单验证、字段定义、HTML生成,并把各种验证流程聚集在一起进行验证
Fields:主要负责渲染(生成HTML)和数据转换 zq===>account='zq'
Validator:主要用于验证用户输入的数据合法性,比如Length验证器用户验证输入数据的长度
Widgets:html插件,允许使用者在字段中通过该字典自定义html小部件
Meta:用于使用者定义wtfomrs功能,例如csrf的功能开启
Extensions:丰富的扩展库,可以与其他框架结合使用,例如django
'''
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,ValidationError
from app.models import Admin
# 1.管理员登录表单
class LoginForm(FlaskForm):
# validators:验证器
# description:描述
# render_kw:渲染属性
account = StringField(
label="账号",
validators=[DataRequired("账号不能为空")],
description="管理员账号",
render_kw={
'class':'form-control',
'placeholder':'请输入账号'
}
)
pwd = PasswordField(
label="密码",
validators=[DataRequired("密码不能为空")],
description="管理员密码",
render_kw={
'class':'form-control',
'placeholder':'请输入密码'
}
)
submit=SubmitField(
label='登录',
render_kw={
'class':'btn btn-primary btn-block btn-flat'
}
)
# 根据账号查询数据是否存在 field ===>account的值
def validat_account(self,field):
# 获取账号的值
account = field.data
# 查询操作models
admin = Admin.query.filter_by(name=account).count()
if admin==0:
raise ValidationError("账号不存在!")
10.app中新建models.py文件
'''
模型层
跟数据库中表一一对应
'''
# 调用init文件中的db属性
from app import db
from datetime import datetime
# 1.管理员
class Admin(db.Model):
# 1.设置表格名称(数据库表一致)
__tablename__='admin'
# 2.表格是否存在
__table_args__={'useexisting':True}
# 3.设置映射
id = db.Column(db.Integer,primary_key=True)# 编号
name=db.Column(db.String(100),unique=True)# 管理员账号
pwd = db.Column(db.String(100))# 管理员密码
is_super=db.Column(db.SmallInteger)# 是否为超级管理员 0为超级管理员
role_id=db.Column(db.Integer)# 所属角色
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
# '''外键关联'''
# adminlogs=db.relationship('Adminlog',backref='admin')# 管理员登录日志外键关联
# oplogs=db.relationship("Oplog",backref='admin')
# 4.显示对象属性
def __repr__(self):
return '<Admin %r>'%self.name
# 5.检查密码
def check_pwd(self,pwd):
# 系统密码
print("系统密码:",self.pwd)
# 用户密码
print("用户密码:",pwd)
return self.pwd == pwd
10.1 编写Admin类
'''
模型层
跟数据库中表一一对应
'''
# 调用init文件中的db属性
from app import db
from datetime import datetime
# 1.管理员
class Admin(db.Model):
# 1.设置表格名称(数据库表一致)
__tablename__='admin'
# 2.表格是否存在
__table_args__={'useexisting':True}
# 3.设置映射
id = db.Column(db.Integer,primary_key=True)# 编号
name=db.Column(db.String(100),unique=True)# 管理员账号
pwd = db.Column(db.String(100))# 管理员密码
is_super=db.Column(db.SmallInteger)# 是否为超级管理员 0为超级管理员
rold_id=db.Column(db.Integer)# 所属角色
# '''外键关联'''
# adminlogs=db.relationship('Adminlog',backref='admin')# 管理员登录日志外键关联
# oplogs=db.relationship("Oplog",backref='admin')
# 4.显示对象属性
def __repr__(self):
return '<Admin %r>'%self.name
# 5.检查密码
def check_pwd(self,pwd):
# 系统密码
print("系统密码:",self.pwd)
# 用户密码
print("用户密码:",pwd)
return self.pwd == pwd
11.补全views.py文件中login函数
'''
app/admin/views
管理员模块 视图文件
后台登录系统
'''
# 1.登录功能实现
from flask import render_template
from . import admin
from app.admin.forms import LoginForm
@admin.route("/login/",methods=['GET','POST'])
def login():
#1.获取登录表单
form=LoginForm()
return render_template("admin/login.html",form=form)
运行
12.views.py中新建index函数
'''
app/admin/views
管理员模块 视图文件
后台登录系统
'''
# 1.登录功能实现
from flask import render_template,flash,redirect,url_for,session
from . import admin
from app.admin.forms import LoginForm
from app.models import Admin
#1.登录功能实现
@admin.route("/login/",methods=['GET','POST'])
def login():
#1.获取登录表单
form=LoginForm()
# 2.判断是否提交按钮
if form.validate_on_submit():
# 3.获取表单数据
data=form.data
# 4.判断账号是否一致
# query查询
# name缺省值参数
# data数据{'account':'admin','pwd':'123'}
# first() 第一个被查询出来的值 将查询出来的数据保存成Admin的实体类
admin=Admin.query.filter_by(name=data['account']).first()
# 5.判断密码是否一致
if admin==None or not admin.check_pwd(data['pwd']):
# 5.1通过flash发送错误信息
flash("用户名或密码错误",'err')
# 5.2 重定向请求
return redirect(url_for('admin.login'))
# 6.如果都正确 则保存session
session['admin']=data['account']
session['admin_id']=admin.id
# 7.设置管理员日志
# 8.数据库添加session add是数据库添加操作
# 9.输出结果
print("登录成功")
# 10.重定向
# 当需要获取前端页面表单传过来的id值的时候,我们需要使用request.args.get
# request.args.get('next') 获取请求的单个参数
return redirect(url_for('admin.index'))
return render_template("admin/login.html",form=form)
# 2.系统首页
@admin.route("/")
def index():
return render_template("admin/index.html")
13.admin中新建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>后台首页</title>
</head>
<body>
<p>主界面</p>
</body>
</html>
14.运行起来 登录
缺少mysql模块
cmd===>pip install mysql-connector
15.修改index.html页面
15.1 头部区域 admin.html
15.2 主区域 显示主页的内容的
15.3 底部区域 js区域
<!--1.头部页面 继承-->
{% extends 'admin/admin.html' %}
<!--2.主区域-->
{% 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-6">
<div class="box box-primary">
<div class="box-header with-border">
<h3>内存使用率</h3>
</div>
<div class="box-body" id="meminfo"
style="height: 600px">
</div>
</div>
</div>
<!--系统设置-->
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">系统设置</h3>
</div>
<!--限制速率大小 限制内存 限制客户端数量-->
<form role="form">
<div class="box-body" style="height: 600px">
<!--1.限制速率大小-->
<div class="form-group">
<label for="input_speed">限制速率大小</label>
<input type="text" class="form-control"
id="input_speed"
placeholder="请输入限制速率" value="512">
</div>
<!--2.限制内存大小-->
<div class="form-group">
<label for="input_mem">限制内存大小</label>
<input type="text" class="form-control"
id="input_mem"
placeholder="请输入限制内存" value="10M">
</div>
<!--3.限制客户端数量-->
<div class="form-group">
<label for="input_num">限制客户端数量</label>
<input type="text" class="form-control"
id="input_num"
placeholder="请输入限制客户端数量" value="4">
</div>
<!--4.保存按钮-->
<div class="form-group">
<button type="submit" class="btn btn-primary">保存并重启服务</button>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3. js区域-->
{% block js %}
<!--3.1 加载js文件-->
<script src="{{ url_for('static',filename='js/echarts.min.js')}}"></script>
<!--3.2 调用显示的标签-->
<script>
var myChart = echarts.init(document.getElementById('meminfo'))
option = {
backgroundcolor:'white',
tooltip:{
formatter:"{a} <br/>{b} : {c}%"
},
toolbox:{
feature:{
restore:{},
saveAsImage:{}
}
},
series:[{
name:'内存使用率',
type:'gauge',
detail:{
formatter:'{value}%'
},
data:[{
value:50,
name:'内存使用率'
}]
}]
};
// 设置时间 2000毫秒执行一次内部代码
setInterval(function (){
// 默认是50的值
option.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0;
myChart.setOption(option,true)
},2000);
</script>
<!--3.3 将左侧菜单<控制面板>样式调整-->
<script>
$(document).ready(function (){
$("#g-1").addClass("active");
$("#g-1-1").addClass("active");
});
</script>
{% endblock %}
16. 新建admin.html并编写
16.1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>后台浏览器</title>
<!--解决IE浏览器问题-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="width=device-width,initial-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='fonts/css/font-awesome.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='admin/bootstrap/css/bootstrap.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='ionicons/css/ionicons.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/AdminLTE.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/skins/_all-skins.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='admin/plugins/datepicker/datepicker3.css') }}">
<!--设置界面的总样式-->
<style>
*{
font-family: 'Microsoft YaHei',sans-serif;
}
.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 %}
<!--其他页面CSS样式编写区域-->
{% endblock %}
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!--1.头部标签区域-->
<header class="main-header">
<!--1.1 左侧系统名称-->
<a href="{{ url_for('admin.index') }}" class="logo">
<span>
<img src="{{ url_for('static',filename='base/images/logo.png') }}"
style="height: 40px;width: 40px"/>
星空电影系统
</span>
<span class="logo-lg">
<img src="{{ url_for('static',filename='base/images/logo.png') }}"
style="height: 40px;width: 40px"/>
电影管理系统
</span>
</a>
<!--1.2 右侧下拉菜单(用户名显示 修改密码 退出系统)-->
<nav class="navbar navbar-static-top">
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" rel="button">
<span class="sr-only">下拉菜单</span>
</a>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<!--1.2.1 用户名显示以及图像-->
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="{{ url_for('static',filename='admin/dist/img/mtianyan.jpg') }}"
class="user-image" alt="User Image"/>
<span class="hidden-xs">{{ session['admin'] }}</span>
</a>
</li>
</ul>
</div>
</nav>
</header>
</div>
</body>
</html>
16.2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>后台浏览器</title>
<!--解决IE浏览器问题-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="width=device-width,initial-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='fonts/css/font-awesome.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='admin/bootstrap/css/bootstrap.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='ionicons/css/ionicons.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/AdminLTE.css') }}">
<link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/skins/_all-skins.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='admin/plugins/datepicker/datepicker3.css') }}">
<!--设置界面的总样式-->
<style>
*{
font-family: 'Microsoft YaHei',sans-serif;
}
.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>
*{
font-family: 'Microsoft YaHei',sans-serif;
}
.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 %}
<!--其他页面CSS样式编写区域-->
{% endblock %}
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!--1.头部标签区域-->
<header class="main-header">
<!--1.1 左侧系统名称-->
<a href="{{ url_for('admin.index') }}" class="logo">
<span>
<img src="{{ url_for('static',filename='base/images/logo.png') }}"
style="height: 40px;width: 40px"/>
星空电影系统
</span>
<span class="logo-lg">
<img src="{{ url_for('static',filename='base/images/logo.png') }}"
style="height: 40px;width: 40px"/>
电影管理系统
</span>
</a>
<!--1.2 右侧下拉菜单(用户名显示 修改密码 退出系统)-->
<nav class="navbar navbar-static-top">
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" rel="button">
<span class="sr-only">下拉菜单</span>
</a>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<!--1.2.1 用户名显示以及图像-->
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="{{ url_for('static',filename='admin/dist/img/mtianyan.jpg') }}"
class="user-image" alt="User Image"/>
<span class="hidden-xs">{{ session['admin'] }}</span>
</a>
<!--1.2.1.1 嵌套的列表-->
<ul class="dropdown-menu">
<li class="user-header">
<img src="{{ url_for('static',filename='admin/dist/img/mtianyan.jpg') }}"
class="img-circle" alt="User Image">
<p>
{{ session['admin'] }}
<small>{{ online_time }}</small>
</p>
</li>
<!--修改密码和退出系统-->
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">修改密码</a>
</div>
<div class="pull-right">
<a href="#" class="btn btn-default btn-flat">退出系统</a>
</div>
</li>
</ul>
</li>
</ul>
</div>
</nav>
</header>
<!--2.搜索框-->
<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/mtianyan.jpg') }}"
class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>用户{{ session['admin'] }}</p>
<a href="#"><i class="fa fa-circle text-success"></i>在线</a>
</div>
</div>
<!--2.1 搜索框-->
<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>
<!--2.2 添加左侧菜单选项-->
{% include "admin/grid.html" %}
</section>
</aside>
<!--3.页面主内容-->
<div class="content-wrapper">
{% block content %}
{% endblock %}
</div>
<!--4.底部内容-->
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>星空版本</b>
</div>
<strong>版本 2021-2022 <a href="#"></a>mobcute</strong>所有
</footer>
</div>
<!--5.js加载-->
<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="{{ 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') }}"></script>
<script src="http://cdn.bootcss.com/holder/2.9.4/holder.min.js"></script>
{% block js %}
<!--加载其他页面的JS文件-->
{% endblock %}
</body>
</html>
17. 新建grid.html菜单页面
<!--左侧菜单页面-->
<ul class="sidebar-menu">
<li class="header">菜单管理</li>
<!--1.首页-->
<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>
</ul>
18. 修改views.py文件中 添加管理员日志
'''
app/admin/views
管理员模块 视图文件
后台登录系统
'''
# 1.登录功能实现
from flask import render_template,flash,redirect,url_for,session,request
from . import admin
from app.admin.forms import LoginForm
from app.models import Admin,Adminlog
from app.models import db
#1.登录功能实现
@admin.route("/login/",methods=['GET','POST'])
def login():
#1.获取登录表单
form=LoginForm()
# 2.判断是否提交按钮
if form.validate_on_submit():
# 3.获取表单数据
data=form.data
# 4.判断账号是否一致
# query查询
# name缺省值参数
# data数据{'account':'admin','pwd':'123'}
# first() 第一个被查询出来的值 将查询出来的数据保存成Admin的实体类
admin=Admin.query.filter_by(name=data['account']).first()
# 5.判断密码是否一致
if admin==None or not admin.check_pwd(data['pwd']):
# 5.1通过flash发送错误信息
flash("用户名或密码错误",'err')
# 5.2 重定向请求
return redirect(url_for('admin.login'))
# 6.如果都正确 则保存session
session['admin']=data['account']
session['admin_id']=admin.id
# 7.设置管理员日志
adminlog = Adminlog(
admin_id=admin.id,
ip=request.remote_addr
)
# 8.数据库添加session add是数据库添加操作
db.session.add(adminlog)
db.session.commit()
# 9.输出结果
print("登录成功")
# 10.重定向
# 当需要获取前端页面表单传过来的id值的时候,我们需要使用request.args.get
# request.args.get('next') 获取请求的单个参数
return redirect(url_for('admin.index'))
return render_template("admin/login.html",form=form)
# 2.系统首页
@admin.route("/")
def index():
return render_template("admin/index.html")
18.1 models中添加管理员日志和管理员操作日志
'''
模型层
跟数据库中表一一对应
'''
# 调用init文件中的db属性
from app import db
from datetime import datetime
# 1.管理员
class Admin(db.Model):
# 1.设置表格名称(数据库表一致)
__tablename__='admin'
# 2.表格是否存在
__table_args__={'useexisting':True}
# 3.设置映射
id = db.Column(db.Integer,primary_key=True)# 编号
name=db.Column(db.String(100),unique=True)# 管理员账号
pwd = db.Column(db.String(100))# 管理员密码
is_super=db.Column(db.SmallInteger)# 是否为超级管理员 0为超级管理员
role_id=db.Column(db.Integer)# 所属角色
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
# '''外键关联'''
# adminlogs=db.relationship('Adminlog',backref='admin')# 管理员登录日志外键关联
# oplogs=db.relationship("Oplog",backref='admin')
# 4.显示对象属性
def __repr__(self):
return '<Admin %r>'%self.name
# 5.检查密码
def check_pwd(self,pwd):
# 系统密码
print("系统密码:",self.pwd)
# 用户密码
print("用户密码:",pwd)
return self.pwd == pwd
# 2.管理员登录日志
class Adminlog(db.Model):
__tablename__='adminlog'
__table_args__={'useexisting':True}
id = db.Column(db.Integer,primary_key=True)# 编号
admin_id=db.Column(db.Integer,db.ForeignKey('admin.id'))# 管理员编号
ip=db.Column(db.String(100))# 登录ip
addtime=db.Column(db.DateTime,index=True,default=datetime)
def __repr__(self):
return "<Adminlog %r>"%self.id
# 3.管理员操作日志
class Oplog(db.Model):
__tablename__='oplog'
__table_args__={'useexisting':True}
id = db.Column(db.Integer,primary_key=True)
admin_id=db.Column(db.Integer,db.ForeignKey('admin.id'))
ip=db.Column(db.String(100))# ip地址
reason=db.Column(db.String(600))# 操作原因
addtime=db.Column(db.DateTime,index=True,default=datetime)
def __repr__(self):
return "<Oplog %r>"%self.id
18.2 login函数中添加管理员登录日志
上个login内已经添加 adminlog表中可以查看管理员登录日志
19. 标签管理-添加标签
19.1 grid.html中添加标签请求
<!--左侧菜单页面-->
<ul class="sidebar-menu">
<li class="header">菜单管理</li>
<!--1.首页-->
<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>
<!--2.标签管理-->
<li class="treeview" id="g-2">
<a href="#">
<i class="fa fa-home" 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>
</ul>
19.2 views.py中添加 tag_add函数
# 3.标签管理-添加标签
@admin.route('/tag_add/',methods=['GET','POST'])
def tag_add():
'''第一种情况:点击左侧菜单子选项 进入到tag_add.html页面
第二种情况:tag_add.html页面 提交form表单数据保存
'''
# 3.1 获取表单验证
form = TagForm()
# 3.2 判断是否点击了提交按钮
if form.validate_on_submit():
# 获取表单数据
data = form.data
# 根据标签名称查找统计标签
tag = Tag.query.filter_by(name=data['name']).count()
# 若查找该标签
if tag == 1:
flash("标签已经存在,不可重复",'err')
return redirect(url_for('admin.tag_add'))
# 没有查找到该标签
tag = Tag(name=data['name'])
# 设置session添加
db.session.add(tag)
db.session.commit()
# 添加管理员操作日志
oplog = Oplog(
admin_id = session['admin_id'],
ip = request.remote_addr,
reason='添加标签%s'%data['name']
)
db.session.add(oplog)
db.session.commit()
flash("标签添加成功",'ok')
redirect(url_for('admin.tag_add'))
return render_template('admin/tag_add.html',form=form)
19.3 forms.py中添加 TagForm()
# 2.标签的表单
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'}
)
19.4 admin文件夹中添加 tag_add.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.设置显示主内容-->
{% block content %}
<!--内容--->
<section class="content-header">
<h1>星空电影管理系统 | 后台</h1>
<ol class="breadcrumb">
<li>
<a href="#">
<i class="fa fa-dashboard"></i> 标签管理
</a>
</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" >
<div class="box-body">
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-2').addClass('active');
$('#g-2-1').addClass('active');
});
</script>
{% endblock %}
19.5 models.py文件中添加 Tag类
# 4.标签表
class Tag(db.Model):
__tablename__ = 'tag'
__table_args__ = {'useexisting':True}
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(100),unique=True)# 标签名称
addtime = db.Column(db.DateTime,index=True,default=datetime.now()) # 添加时间
# 设置外键关联 与 电影的外键关联movie
movies = db.relationship('Movie',backref='tag')
# 显示属性
def __repr__(self):
return "<Tag %r>"%self.name
20.标签管理-标签列表
20.1 grid.html中添加标签列表请求
已添加
20.2 views.py中添加 tag_list函数
# 4.标签管理-标签列表
@admin.route("/tag_list/<int:page>/",methods=['GET'])
def tag_list(page=None):
'''
1.点击左侧菜单 标签列表===> tag_list.html页面展示数据
2.点击页码 使用缺省值参数 page接受页码值===>根据页码查询数据并展示到tag_list.html
'''
# 第一种情况无页码
if page is None:
page = 1
# 分页查询
# paginate(page,per_page,False) 显示第page页 每页per_page,error_out=False不抛出404
# 按照标签添加时间进行降序 分页插件设置页码
page_data = Tag.query.order_by(Tag.addtime.desc())\
.paginate(page=page,per_page=3)
return render_template("admin/tag_list.html",page_data=page_data)
20.3 admin文件夹中添加 tag_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.标签列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>名称</th>
<th>添加时间</th>
<th>操作事项</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.name }}</td>
<td>{{ v.addtime }}</td>
<td>
<a href="{{url_for('admin.tag_edit',id=v.id)}}" class="label label-success">编辑</a>
<a href="{{url_for('admin.tag_del',id=v.id)}}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.tag_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-2').addClass('active');
$('#g-2-2').addClass('active');
});
</script>
{% endblock %}
20.4 新建ui/admin_page.html
<!--分页查询部分 macro相当于模板中声明函数-->
<!--pg.page(page_data,'admin.tag_list')-->
{% macro page(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 %}
{% 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 %}
{% 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 %}
21.标签管理-标签编辑
21.1 tag_list.html中发送编辑请求
21.2 views.py中添加 tag_edit函数
# 5.标签管理-标签编辑
@admin.route("/tag_edit/<int:id>",methods=['GET','POST'])
def tag_edit(id=None):
# 5.1 获取表单
form = TagForm()
# 5.2 将表单中的按钮改成修改
form.submit.label.text = '修改'
# 5.3 根据id值查询数据库 有数据或者404 tag是原有的标签数据 喜剧片
tag = Tag.query.get_or_404(id)
# 5.4 判断表单是否提交
if form.validate_on_submit():
# 5.5 获取表单数据
data = form.data
# 5.6 先把用户数据查询一遍判断是否存在
tag_count = Tag.query.filter_by(name=data['name']).count()
# 5.7 判断标签是否存在
if tag.name != data['name'] and tag_count == 1:
flash("标签名称已经存在",'err')
return redirect(url_for('admin.tag_edit',id=tag.id))
# 5.8 表单数据更改
tag.name = data['name']
# 5.9 数据库的数据提交和添加
db.session.add(tag)
db.session.commit()
# 5.10 标签的提示框
flash("标签已经修改成功",'ok')
# 5.11 重定向到编辑页面
redirect(url_for('admin.tag_edit',id=tag.id))
return render_template("admin/tag_edit.html",form=form,tag=tag)
21.3 admin文件夹下添加 tag_edit.html
<!--1.继承 admin.html-->
{% extends 'admin/admin.html' %}
<!--2.主页面区域-->
{% block content %}
<!--2.1 页面路径-->
<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>
<!--2.2 主内容-->
<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>
<!--2.2.1 表单-->
<form role="form" method="post">
<div class="box-body">
<!--2.2.2 弹出框-->
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--2.2.3 标签框-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<!--2.2.4 修改按钮和令牌-->
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.修改左侧菜单页面内容-->
{% block js %}
<script>
$(document).ready(function (){
$('#g-2').addClass('active');
$('#g-2-2').addClass('active');
});
</script>
{% endblock %}
22.标签管理-标签删除
22.1 tag_list.html中发送编辑请求
22.2 views.py中添加 tag_del函数
# 6.标签管理-标签删除
@admin.route('/tag_del/<int:id>',methods=['GET'])
def tag_del(id=None):
# 6.1 查看是否存在该标签
# filter_by查不到或者多个数据不会报错,get会报错
tag = Tag.query.filter_by(id=id).first_or_404()
# 6.2 删除标签
db.session.delete(tag)
db.session.commit()
# 6.3 提示框
flash("标签<<{0}>>删除成功".format(tag.name),'ok')
# 6.4 重定向标签列表页面
return redirect(url_for('admin.tag_list',page=1))
23.电影管理-添加电影
23.1 grid.html中 设置电影管理 添加电影 和电影列表
<!--3.电影管理-->
<li class="treeview" id="g-3">
<a href="#">
<i class="fa fa-home" 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>
23.2 views.py中 添加movie_add和movie_list请求函数
# 7.电影管理-电影添加
@admin.route('/movie_add',methods=['GET','POST'])
def movie_add():
# 7.1 获取电影表单
form = MovieForm()
# 7.2 判断按钮是否点击
if form.validate_on_submit():
# 7.3 获取表单数据
data = form.data
# 7.4 处理上传文件以及LOGO
file_url = secure_filename(form.url.data.filename)
file_logo = secure_filename(form.logo.data.filename)
# 7.5 判断当前项目中的上传文件目录是否存在 static/uploads文件夹
if not os.path.exists(app.config['UP_DIR']):
# 7.5.1 创建目录
os.makedirs(app.config['UP_DIR'])
# 7.5.2 更改目录以及目录权限
os.chmod(app.config['UP_DIR'],'rb')
# 7.6 修改form表单数据
# file_url ====>psdb.png els.mp4
url = change_filename(file_url)
logo = change_filename(file_logo)
# 7.7 保存数据到form表单
# static/uploads/20220406173106f5a6a528041b429eb0fa50004fc9abea.png
form.url.data.save(app.config['UP_DIR']+url)
form.logo.data.save(app.config['UP_DIR']+logo)
# 7.8 设置form表单数据
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']
)
# 7.9 添加数据
db.session.add(movie)
db.session.commit()
# 7.10 弹出框
flash("添加电影成功啦!!!",'ok')
# 7.11 重定向
return redirect(url_for("admin.movie_add"))
# 7.12 进入添加页面
return render_template('admin/movie_add.html',form=form)
def change_filename(filename):
# 1.将传递的路径进行分解 E:/pycharm/project/els.mp4
fileinfo = os.path.splitext(filename)
# 2.拼接新的文件名称
'''
2022040617310
datetime.now()当前时间 按照YYYYmmddHHMMSS
f5a6a528041b429eb0fa50004fc9abea
str(uuid.uuid4().hex)
fileinfo[-1]
.png .mp4
'''
filename = datetime.now().strftime("%Y%m%d%H%M%S") + str(uuid.uuid4().hex)+fileinfo[-1]
return filename
23.3 forms.py中 添加MovieForm
# 3.电影的表单
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
}
)
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,
# 查询数据库中的tag标签表的内容循环遍历
choices=[(v.id,v.name) for v in Tag.query.all()],
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',
'placeholder':'请选择上映时间!',
'id':'input_release_time'
}
)
submit = SubmitField(
'添加',
render_kw= {
'class':'btn btn-primary'
}
)
23.4 models.py中 添加Movie
外键关联 Comment 评论 MovieCol收藏
# 5.电影表
class Movie(db.Model):
__tablename__ = 'movie'
__table_args__ = {'useexisting':True}
id = db.Column(db.Integer,primary_key=True)
title = db.Column(db.String(255),unique=True)
url = db.Column(db.String(255), unique=True)
info = db.Column(db.Text)
logo = db.Column(db.String(255), unique=True)
star = db.Column(db.SmallInteger)
playnum = db.Column(db.BigInteger)
commentnum = db.Column(db.BigInteger)
tag_id = db.Column(db.Integer,db.ForeignKey('tag.id'))
area = db.Column(db.String(255))
release_time = db.Column(db.Date)
length = db.Column(db.String(100))
addtime = db.Column(db.DateTime,index=True,default=datetime.now)
# 评论和收藏暂时不写
comments= db.relationship('Comment',backref='movie')
moviecols = db.relationship('Moviecol', backref='movie')
def __repr__(self):
return "<Movie %r>"%self.title
# 设置外键关联 与 电影的外键关联movie
movies = db.relationship('Movie',backref='tag')
添加与tag的关联
23.5 admin文件夹中 movie_add.html和 movie_list.html
24.电影管理-电影列表
24.1 grid.html 添加电影列表请求
24.2 views.py 添加函数 movie_list
# 8.电影管理-电影列表
@admin.route('/movie_list/<int:page>',methods=['GET'])
def movie_list(page=None):
# 8.1 判断page是否有值
if page is None:
page = 1
# 8.2 进行关联查询 关联Tag查询 单表filter_by 多表filter进行关联字段的
# 过滤条件 Tag.id == Movie.tag_id
# 排序条件 Movie.addtime.desc()
# 分页设置 page=page per_page=1 每页显示1条数据 当前页面是那一页
page_data = Movie.query.join(Tag).filter(
Tag.id == Movie.tag_id
).order_by(
Movie.addtime.desc()
).paginate(page=page,per_page=1)
# 8.3 返回movie_list.html 将分页数据传递到前端
return render_template("admin/movie_list.html",page_data=page_data)
24.3 admin文件夹中新建 movie_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.电影列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</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 v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.title }}</td>
<td>{{ v.length }}分钟</td>
<td>{{ v.tag.name }}</td>
<td>{{ v.area }}</td>
<td>{{ v.star }}</td>
<td>{{ v.playnum }}</td>
<td>{{ v.commentnum }}</td>
<td>{{ v.addtime }}</td>
<td>
<a href="{{ url_for('admin.movie_edit',id=v.id) }}" class="label label-success">编辑</a>
<a href="{{ url_for('admin.movie_del',id=v.id) }}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.movie_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-3').addClass('active');
$('#g-3-2').addClass('active');
});
</script>
{% endblock %}
25.电影管理-电影编辑
25.1 movie_list.html 添加编辑请求
25.2 views中添加函数 movie_edit
# 9.电影管理-电影编辑
@admin.route("/movie_edit/<int:id>",methods=['GET','POST'])
def movie_edit(id=None):
# 9.1 获取电影表单
form = MovieForm()
form.submit.label.text = '修改'
# 9.2 设置url,logo非空验证为空 编辑不修改的时候 不会验证器报错
form.url.validators = []
form.logo.validators = []
# 9.3 根据id查询数据
movie = Movie.query.get_or_404(int(id))
# 9.4 判断请求类型
if request.method == "GET":
# 9.5 将info,tag_id,star数据放到表单中显示在编辑页面
form.info.data = movie.info
form.tag_id.data = movie.tag_id
form.star.data = movie.star
# 9.6 表单提交 post请求
if form.validate_on_submit():
# 9.7 获取表单数据
data = form.data
# 9.8 根据表单名查看数据库是否存在
movie_count = Movie.query.filter_by(title=data['title']).count()
# 9.9 判断电影名称是否存在以及电影名称没有修改
if movie_count == 1 and movie.title != data['title']:
# 提示错误信息
flash("片名已经存在!",'err')
return redirect(url_for("admin.movie_edit",id=id))
# 9.10 创建目录 uploads不存在则新建 存在则不再新建
if not os.path.exists(app.config['UP_DIR']):
os.makedirs(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'],'rb')
# 9.11 上传新的视频文件
if form.url.data != "":
# 删除原有的视频文件
os.remove(app.config['UP_DIR'] + movie.url)
# 上传的视频文件名称
file_url = secure_filename(form.url.data.filename)
# 修改了的视频文件名称
movie.url = change_filename(file_url)
form.url.data.save(app.config['UP_DIR']+movie.url)
# 9.12 上传图片
if form.logo.data != "":
# 删除原有的图片文件
os.remove(app.config['UP_DIR']+movie.logo)
file_logo = secure_filename(form.logo.data.filename)
movie.logo = change_filename(file_logo)
form.logo.data.save(app.config['UP_DIR'] + movie.logo)
# 9.13 设置其他的数据信息
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']
# 9.14 数据提交
db.session.add(movie)
db.session.commit()
# 9.15 提示修改成功
flash("修改电影成功啦啦啦!!!",'ok')
return redirect(url_for('admin.movie_edit',id=id))
# 返回到电影编辑页面
return render_template("admin/movie_edit.html",form=form,movie=movie)
25.3 admin文件夹中新建 movie_edit.html
<!--1.继承 admin.html-->
{% extends 'admin/admin.html' %}
<!--2.主页面区域-->
{% block content %}
<!--2.1 页面路径-->
<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>
<!--2.2 主内容-->
<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>
<!--2.2.1 表单-->
<form role="form" method="post" enctype="multipart/form-data">
<div class="box-body">
<!--2.2.2 弹出框-->
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--2.2.3 电影框-->
<!--1.片名-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--2.url-->
<div class="form-group">
<label for="input_url">{{ form.url.label }}</label>
{{ form.url(value = movie.url) }}
{% for err in form.url.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
<div style="margin-top: 5px">
<div id="moviecontainer"></div>
</div>
</div>
<!--3.电影介绍-->
<div class="form-group">
<label for="input_info">{{ form.info.label }}</label>
{{ form.info(value = movie.info) }}
{% for err in form.info.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--4.封面-->
<div class="form-group">
<label for="input_logo">{{ form.logo.label }}</label>
{{ form.logo(value = movie.logo) }}
{% for err in form.logo.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
<img src="{{ url_for('static',filename='uploads/'+movie.logo) }}"
style="margin-top: 5px" class="img-responsive" alt="">
</div>
<!--5.电影评级-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--6.电影标签-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--7.上映地区-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--8.片长-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--9.上映时间-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<!--2.2.4 修改按钮和令牌-->
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.修改左侧菜单页面内容-->
{% block js %}
<!--播放页面-->
<!--1.加载js文件-->
<script src="{{ url_for('static',filename='jwplayer/jwplayer.js') }}"></script>
<!--2.设置播放插件的key值-->
<script type="text/javascript">
jwplayer.key = 'P9VTqT/X6TSP4gi/hy1wy23BivBhjdzVjMeOaQ==';
</script>
<!--3.设置播放的文件以及形式-->
<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:"downlaod"}],
skin:{name:"vapor"},
"playlist.position":"left",
"playlist.sieze":200,
height:250,
width:387
});
</script>
<!--4.设置上映时间的格式-->
<script>
$(document).ready(function (){
$('#iniput_release_time').datepicker({
autoclose: true,
format:'yyyy-mm-dd',
language:'zh-CN'
});
});
</script>
<script>
$(document).ready(function (){
$('#g-3').addClass('active');
$('#g-3-2').addClass('active');
});
</script>
{% endblock %}
26.电影管理-电影删除
26.1 movie_list.html 添加删除请求
26.2 views中添加函数 movie_del
# 10.电影管理-电影删除
@admin.route("/movie_del/<int:id>",methods=['GET'])
def movie_del(id=None):
# 10.1 根据id查询删除的数据是否存在
movie = Movie.query.get_or_404(id)
# 10.2 若存在则进行删除操作
if not movie is None:
# 删除数据库的电影数据时候 uploads中的文件并没有删除掉
os.remove(app.config['UP_DIR']+movie.url)
os.remove(app.config['UP_DIR']+movie.logo)
db.session.delete(movie)
db.session.commit()
# 10.3 提示框
flash("电影删除成功啦!","ok")
return redirect(url_for('admin.movie_list',page=1))
27.预告管理-添加预告
27.1 grid.html 添加预告请求 admin.preview_add
<!--4.预告管理-->
<li class="treeview" id="g-4">
<a href="#">
<i class="fa fa-home" 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>
27.2 views.py 新建preview_add函数
# 11.预告管理-预告添加
@admin.route("/preview_add/",methods=['GET','POST'])
def preview_add():
# 11.1 获取预告表单
form = PreviewForm()
# 11.2 判断表单是否点击提交
if form.validate_on_submit():
# 11.3 获取添加的数据
data = form.data
# 11.4 获取logo的名称
file_logo = secure_filename(form.logo.data.filename)
# 11.5 判断是否有uploads文件夹
if not os.path.exists(app.config['UP_DIR']):
os.makedirs(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'],'rb')
# 11.6 修改logo的文件名称
logo = change_filename(file_logo)
# 11.7 保存logo到form中
form.logo.data.save(app.config['UP_DIR'] + logo)
# 11.8 设置其他的预告数据
preview = Preview(
title=data['title'],
logo = logo
)
# 11.9 添加数据到数据库中
db.session.add(preview)
db.session.commit()
# 11.10 提示成功
flash("添加预告成功!",'ok')
return redirect(url_for("admin.preview_add"))
return render_template("admin/preview_add.html",form=form)
27.3 models.py 新建 Preview 模型
# 6.上映预告表
class Preview(db.Model):
__tablename__ = 'preview'
__table_args__ = {'useexisting':True}
# 编号
id = db.Column(db.Integer,primary_key=True)
# 标题
title = db.Column(db.String(255),unique=True)
# 封面
logo = db.Column(db.String(255),unique=True)
# 添加时间
addtime = db.Column(db.DateTime,index=True,default=datetime.now)
def __repr__(self):
return "<Preview %r>"%self.title
27.4 forms.py 新建 PreviewForm表单
# 4.预告的表单
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'
}
)
27.5 admin文件夹下新建 preview_add.html
28.预告管理-预告列表
28.1 grid.html 添加预告列表请求 admin.preview_list
28.2 views.py 新建preview_list函数
# 12.预告管理-预告列表
@admin.route("/preview_list/<int:page>",methods=['GET'])
def preview_list(page=None):
# 12.1 判断page是否为None
if page is None:
page = 1
# 12.2 根据添加时间排序的分页数据
page_data = Preview.query.order_by(
Preview.addtime.desc()
).paginate(page=page,per_page=1)
# 12.3 返回分页数据
return render_template("admin/preview_list.html",page_data=page_data)
28.3 admin文件夹下编辑 preview_add.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.设置显示主内容-->
{% block content %}
<!--内容--->
<section class="content-header">
<h1>星空电影管理系统 | 后台</h1>
<ol class="breadcrumb">
<li>
<a href="#">
<i class="fa fa-dashboard"></i> 预告管理
</a>
</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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--1.预告标题-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--2.预告LOGO-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
<img data-src="holder.js/700*320" 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 %}
<!--3.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-4').addClass('active');
$('#g-4-1').addClass('active');
});
</script>
{% endblock %}
29.预告管理-预告编辑
29.1 preview_list.html 中添加 编辑请求 admin.preview_edit
29.2 views.py 中添加 preview_edit函数
# 13.预告管理-预告编辑
@admin.route("/preview_edit/<int:id>",methods=['GET','POST'])
def preview_edit(id=None):
# 13.1 获取预告表单
form = PreviewForm()
form.submit.label.text = "修改"
# 13.2 设置logo的验证器为空
form.logo.validators = []
# 13.3 根据id获取预告的数据信息
preview = Preview.query.get_or_404(int(id))
# 13.4 判断请求类型
if request.method == 'GET':
form.title.data = preview.title
# 13.5 post请求
if form.validate_on_submit():
# 13.6 获取编辑页面的数据
data = form.data
# 13.7 判断logo是否为空
if form.logo.data != "":
# 13.8 删除原有的封面图片
os.remove(app.config['UP_DIR']+preview.logo)
# 13.9 获取上传图片的文件名以及路径
file_logo = secure_filename(form.logo.data.filename)
# 13.10 对上传的图片名进行更改
preview.logo = change_filename(file_logo)
# 13.11 保存新的数据到form表单中
form.logo.data.save(app.config['UP_DIR'] + preview.logo)
# 13.12 设置提交到数据库的数据信息
preview.title = data['title']
# 13.13 提交到数据库中
db.session.add(preview)
db.session.commit()
# 13.14 提示框
flash("预告修改成功!!!",'ok')
return redirect(url_for('admin.preview_edit',id=id))
return render_template("admin/preview_edit.html",form=form,preview=preview)
29.3 admin文件夹下编辑preview_edit.html
<!--1.继承 admin.html-->
{% extends 'admin/admin.html' %}
<!--2.主页面区域-->
{% block content %}
<!--2.1 页面路径-->
<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>
<!--2.2 主内容-->
<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>
<!--2.2.1 表单-->
<form role="form" method="post" enctype="multipart/form-data">
<div class="box-body">
<!--2.2.2 弹出框-->
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--1.预告标题-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--2.预告封面-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
<img src="{{ url_for('static',filename='uploads/'+preview.logo) }}"
style="margin-top: 5px" class="img-responsive" alt="">
</div>
</div>
<!--2.2.4 修改按钮和令牌-->
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.修改左侧菜单页面内容-->
{% block js %}
<script>
$(document).ready(function (){
$('#g-4').addClass('active');
$('#g-4-2').addClass('active');
});
</script>
{% endblock %}
30.预告管理-预告删除
30.1 preview_list.html 中添加 删除请求 admin.preview_del
30.2 views.py 中添加preview_del函数
# 14.预告管理-预告删除
@admin.route("/preview_del/<int:id>",methods=['GET'])
def preview_del(id =None):
# 14.1 根据id获取预告数据
preview = Preview.query.get_or_404(id)
# 14.2 判断是否有数据
if not preview is None:
# 14.3 删除原有的预告封面
os.remove(app.config['UP_DIR']+preview.logo)
# 14.4 删除数据
db.session.delete(preview)
db.session.commit()
# 14.5 提示删除成功
flash("预告删除成功啦!!!",'ok')
return redirect(url_for("admin.preview_list",page=1))
else:
flash("预告删除失败啦!!!",'err')
return redirect(url_for("admin.preview_list",page=1))
31.会员管理-会员列表
31.1 grid.html 设置会员管理 子标签 会员列表 admin.user_list
<!--5.会员管理-->
<li class="treeview" id="g-5">
<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-5-1">
<a href="{{ url_for('admin.user_list',page=1) }}">
<i class="fa fa-circle-o"></i>会员列表
</a>
</li>
</ul>
</li>
31.2 models.py 新建 User
# 7.会员表
class User(db.Model):
__tablename__ = 'user'
__table_args__ = {'useexisting': True}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True)
pwd = db.Column(db.String(100))
email=db.Column(db.String(100),unique=True)
phone=db.Column(db.String(11),unique=True)
info = db.Column(db.Text)
face = db.Column(db.String(255), unique=True)
addtime = db.Column(db.DateTime, index=True, default=datetime.now) # 添加时间
uuid=db.Column(db.String(255),unique=True)# 唯一标识符
comments=db.relationship('Comment',backref='user')
moviecols = db.relationship('Moviecol', backref='user')
# 会员日志、评论表、收藏表外键关联
def __repr__(self):
return "<User %r>" % self.name
def check_pwd(self,pwd):
# 加密判断
return pwd == self.pwd
31.3views.py中 新建 user_list函数
# 15.会员管理-会员列表
@admin.route("/user_list/<int:page>",methods=['GET'])
def user_list(page=None):
# 15.1 判断page是否为None
if page is None:
page = 1
# 15.2 根据添加时间排序的分页数据
page_data = User.query.order_by(
User.addtime.desc()
).paginate(page=page,per_page=1)
# 15.3 返回分页数据
return render_template("admin/user_list.html",page_data=page_data)
31.5 admin文件夹下 新建user_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.会员列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</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>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.name }}</td>
{# <td>{{ v.pwd }}</td>#}
<td>{{ v.email }}</td>
<td>{{ v.phone }}</td>
{# <td>{{ v.info }}</td>#}
<td>
{% if v.face %}
<img alt="50*50"
src="{{ url_for('static',filename='uploads/users/'+v.face) }}"
class="img-circle"
style="border: 1px solid #abcdef;width: 50px;">
{% else %}
<img alt="50*50"
data-src="holder.js/50*50"
class="img-circle"
style="border: 1px solid #abcdef;width: 50px;">
{% endif %}
</td>
<td>正常/冻结</td>
<td>{{ v.addtime }}</td>
<td>
<a class="label label-success" href="{{ url_for('admin.user_view',id=v.id,fp=page_data.page) }}">查看</a>
<a class="label label-info">解冻</a>
<a class="label label-warning">冻结</a>
<a href="{{ url_for('admin.user_del', id=v.id,fp=page_data.page)}}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.user_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-5').addClass('active');
$('#g-5-1').addClass('active');
});
</script>
{% endblock %}
32.会员管理-会员删除
32.1 user_list.html 添加 会员删除请求 admin.user_del
32.2 views.py 新建 user_del函数
# 14.会员管理-会员删除
@admin.route("/user_del/<int:id>",methods=['GET'])
def user_del(id =None):
form_page= int(request.args.get("fp"))-1
if not form_page:
form_page=1
# 14.1 根据id获取预告数据
user = User.query.get_or_404(int(id))
# 14.4 删除数据
db.session.delete(user)
db.session.commit()
# 14.5 提示删除成功
flash("会员删除成功啦!!!",'ok')
return redirect(url_for("admin.user_list",page=form_page))
33.会员管理-会员查看
33.1 user_list.html 添加 会员查看请求 admin.user_view
33.2 views.py 新建 user_view函数
# 17.会员管理-会员查看
@admin.route("/user_view/<int:id>",methods=['GET'])
def user_view(id=None):
#17.1
form_page=request.args.get('fp')
if not form_page:
form_page=1
user=User.query.get_or_404(int(id))
return render_template("admin/user_view.html",user=user,form_page=form_page)
33.3 admin文件夹下新建 user_view.html
{% extends 'admin/admin.html' %}
{% block 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: left;
}
.td_bd {
width: 100px;
font-weight: bold;
}
</style>
{% endblock %}
{% block content %}
<section class="content-header">
<h1>星空电影管理系统</h1>
<ol class="breakcrumb">
<li>
<a href="{{ url_for('admin.user_list',page=form_page) }}">
<i class="fa fa-dashboard"></i>会员管理
</a>
</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>
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
<tbody>
<tr>
<td class="td_bd">编号:</td>
<td>{{ user.id }}</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>
{% if user.face %}
<img alt="100*100"
src="{{ url_for('static',filename='uploads/users/'+user.face)}}"
class="img-responsive"
style="border: 1px solid #abcdef;width:100px">
{% else %}
<img alt="100*100"
data-src="holder.js/100*100"
class="img-responsive"
style="border: 1px solid #abcdef;width:100px">
{% endif %}
</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>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
{% block js %}
<script>
$(document).ready(function (){
$('#g-5').addClass('active')
$('#g-5-1').addClass('active')
});
</script>
{% endblock %}
34.评论管理-评论列表
34.1 grid.html新建评论管理 以及评论列表请求 comment_list
<!--6.评论管理-->
<li class="treeview" id="g-6">
<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-6-1">
<a href="{{ url_for('admin.comment_list',page=1) }}">
<i class="fa fa-circle-o"></i>评论列表
</a>
</li>
</ul>
</li>
34.2 models.py 新建comment类
# 8.评论表
class Comment(db.Model):
__tablename__='comment'
__table_args__={'useexisting':True}
id=db.Column(db.Integer,primary_key=True)
content=db.Column(db.Text)
#外键关联
movie_id=db.Column(db.Integer,db.ForeignKey('movie.id'))
user_id=db.Column(db.Integer,db.ForeignKey('user.id'))
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
def __repr__(self):
return "<Comment %r>"%self.id
34.3 views.py 新建comment_list函数
# 18.评论管理-评论列表
@admin.route("/comment_list/<int:page>",methods=['GET'])
def comment_list(page=None):
#18.1
if page is None:
page=1
#18.2 通过评论join查询相关的movie以及user表
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=1)
return render_template("admin/comment_list.html",page_data=page_data)
34.4 admin文件夹下新建 comment_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.评论列表主内容-->
{% 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 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
{% for v in page_data.items %}
<div class="box-comment">
{% if v.user.face %}
<img atl="50*50"
src="{{ url_for('static',filename='uploads/users/'+v.user.face) }}"
class="img-circle img-sm"
style="border:1px solid #abcdef;width:50px">
{% else %}
<img atl="50*50"
data-src="holder.js/50*50"
class="img-circle img-sm"
style="border:1px solid #abcdef;width:50px">
{% endif %}
<div class="comment-text">
<span class="username">
{{ v.user.name }}
<span class="text-muted pull-right">
<i class="fa fa-calendar" aria-hidden="true"></i>
{{ v.addtime }}
</span>
</span>
关于电影<a>《{{ v.movie.title }}》</a>的评论:{{ v.content|safe }}
<br><a href="{{ url_for('admin.comment_del', id=v.id,fp=page_data.page) }}"
class="label label-danger pull-right">删除</a>
</div>
</div>
{% endfor %}
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.comment_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-6').addClass('active');
$('#g-6-1').addClass('active');
});
</script>
{% endblock %}
35.评论管理-评论删除
35.1 comment_list.html 添加评论删除请求 comment_del
35.2 views.py 添加 comment_del函数
# 19.评论管理-评论删除
@admin.route("/comment_del/<int:id>",methods=['GET'])
def comment_del(id =None):
form_page= int(request.args.get("fp"))-1
if not form_page:
form_page=1
# 14.1 根据id获取预告数据
comment = Comment.query.get_or_404(int(id))
# 14.4 删除数据
db.session.delete(comment)
db.session.commit()
# 14.5 提示删除成功
flash("评论删除成功啦!!!",'ok')
return redirect(url_for("admin.comment_list",page=form_page))
36.收藏管理-收藏列表
36.1 grid.html 新建收藏管理 admin.moviecol_list
<!--7.收藏管理-->
<li class="treeview" id="g-7">
<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-7-1">
<a href="{{ url_for('admin.moviecol_list',page=1) }}">
<i class="fa fa-circle-o"></i>收藏列表
</a>
</li>
</ul>
</li>
36.2 models.py 添加 Moviecol类
movie.id user.id
# 9.收藏表
class Moviecol(db.Model):
__tablename__='moviecol'
__table_args__={'useexisting':True}
id=db.Column(db.Integer,primary_key=True)
#外键关联
movie_id=db.Column(db.Integer,db.ForeignKey('movie.id'))
user_id=db.Column(db.Integer,db.ForeignKey('user.id'))
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
def __repr__(self):
return "<Moviecol %r>"%self.id
36.3 views.py 添加 moviecol_list函数
# 20.收藏管理-收藏列表
@admin.route("/moviecol_list/<int:page>",methods=['GET'])
def moviecol_list(page=None):
#20.1
if page is None:
page=1
#20.2 通过评论join查询相关的movie以及user表
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=1)
print(page_data)
return render_template("admin/moviecol_list.html",page_data=page_data)
36.4 admin文件夹新建 moviecol_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.收藏列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>电影</th>
<th>用户</th>
<th>收藏时间</th>
<th>操作事项</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.movie.title }}</td>
<td>{{ v.user.name }}</td>
<td>{{ v.addtime }}</td>
<td>
<a href="{{url_for('admin.moviecol_del',id=v.id,fp=page_data.page)}}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.moviecol_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-7').addClass('active');
$('#g-7-1').addClass('active');
});
</script>
{% endblock %}
37.收藏管理-收藏删除
37.1 moviecol_list.html中添加 删除请求 admin.moviecol_del
37.2 views.py 添加moviecol_del函数
# 21.收藏管理-收藏删除
@admin.route("/moviecol_del/<int:id>",methods=['GET'])
def moviecol_del(id =None):
form_page= int(request.args.get("fp"))-1
if not form_page:
form_page=1
# 21.1 根据id获取预告数据
moviecol = Moviecol.query.get_or_404(int(id))
# 21.4 删除数据
db.session.delete(moviecol)
db.session.commit()
# 14.5 提示删除成功
flash("收藏删除成功啦!!!",'ok')
return redirect(url_for("admin.comment_list",page=form_page))
38.日志管理
38.1 grid.html中
<!--8.日志管理-->
<li class="treeview" id="g-8">
<a href="#">
<i class="fa fa-home" 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>
</ul>
<ul class="treeview-menu">
<li id="g-8-2">
<a href="{{ url_for('admin.adminlog_list',page=1) }}">
<i class="fa fa-circle-o"></i>管理员登录日志列表
</a>
</li>
</ul>
<ul class="treeview-menu">
<li id="g-8-3">
<a href="{{ url_for('admin.userlog_list',page=1) }}">
<i class="fa fa-circle-o"></i>会员登录日志列表
</a>
</li>
</ul>
</li>
38.2 models.py编写Userlog , Adminlog , 0plog
# 2.管理员登录日志
class Adminlog(db.Model):
__tablename__ = 'adminlog'
__table_args__ = {'useexisting':True}
id = db.Column(db.Integer,primary_key=True)# 编号
admin_id = db.Column(db.Integer,db.ForeignKey('admin.id'))# 管理员编号
ip = db.Column(db.String(100)) # 登录ip
addtime = db.Column(db.DateTime,index=True,default=datetime.now())# 登录时间
def __repr__(self):
return "<Adminlog %r>"%self.id
# 3.管理员操作日志
class Oplog(db.Model):
__tablename__ = 'oplog'
__table_args__ = {'useexisting':True}
id = db.Column(db.Integer,primary_key=True)
admin_id = db.Column(db.Integer,db.ForeignKey("admin.id"))
ip = db.Column(db.String(100)) # ip地址
reason = db.Column(db.String(100))# 操作原因
addtime = db.Column(db.DateTime,index=True,default=datetime.now())
def __repr__(self):
return "<Oplog %r>"%self.id
#10.会员登录日志
class Userlog(db.Model):
__tablename__='userlog'
__table_args__={'useexisting':True}
id=db.Column(db.Integer,primary_key=True)
user_id=db.Column(db.Integer,db.ForeignKey('user.id'))
ip=db.Column(db.String(100))
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
def __repr__(self):
return "<Userlog %r>"%self.id
38.3 views.py中添加userlog_list adminlog_list oplog_list函数
# 22. 日志管理-操作日志列表
@admin.route("/oplog_list/<int:page>",methods=['GET'])
def oplog_list(page=None):
#22.1
if page is None:
page=1
#22.2 oplog关联查询
page_data=Oplog.query.join(Admin).filter(
Admin.id==Oplog.admin_id,
).order_by(
Oplog.addtime.desc()
).paginate(page=page,per_page=2)
return render_template("admin/oplog_list.html",page_data=page_data)
#23.日志管理-管理员登录日志列表
@admin.route("/adminlog_list/<int:page>",methods=['GET'])
def adminlog_list(page=None):
#23.1判断是否
if page is None:
page=1
#23.2
page_data=Adminlog.query.join(Admin).filter(
Admin.id==Adminlog.admin_id
).order_by(
Adminlog.addtime.desc()
).paginate(page=page,per_page=50)
return render_template("admin/adminlog_list.html",page_data=page_data)
#24.日志管理-会员登录日志列表
@admin.route("/userlog_list/<int:page>",methods=['GET'])
def userlog_list(page=None):
#24.1判断是否
if page is None:
page=1
#24.2
page_data=Userlog.query.join(User).filter(
User.id==Userlog.user_id
).order_by(
Userlog.addtime.desc()
).paginate(page=page,per_page=5)
return render_template("admin/userlog_list.html",page_data=page_data)
38.4 admin文什夹中 userlog_list.html, adminlog_list.html, oplog_list.html
userlog_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.会员登录日志列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>会员</th>
<th>登录时间</th>
<th>IP地址</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.user.name }}</td>
<td>{{ v.addtime }}</td>
<td>{{ v.ip }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.userlog_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-8').addClass('active');
$('#g-8-3').addClass('active');
});
</script>
{% endblock %}
admin_lists.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.管理员登录日志列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>管理员</th>
<th>登录时间</th>
<th>IP地址</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.admin.name }}</td>
<td>{{ v.addtime }}</td>
<td>{{ v.ip }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.adminlog_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-8').addClass('active');
$('#g-8-2').addClass('active');
});
</script>
{% endblock %}
oplog_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.操作日志列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>管理员</th>
<th>操作时间</th>
<th>操作原因</th>
<th>IP地址</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.admin.name }}</td>
<td>{{ v.addtime }}</td>
<td>{{ v.reason }}</td>
<td>{{ v.ip }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.oplog_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-8').addClass('active');
$('#g-8-1').addClass('active');
});
</script>
{% endblock %}
39.权限管理
39.1 grid.html 添加权限管理
<!--9.权限管理-->
<li class="treeview" id="g-9">
<a href="#">
<i class="fa fa-home" 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>
</ul>
<ul class="treeview-menu">
<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>
39.2 models.py 编写 Auth模型
#10.权限
class Auth(db.Model):
__tablename__='auth'
__table_args__={'useexisting':True}
id=db.Column(db.Integer,primary_key=True)
name=db.Column(db.String(100),unique=True)
url = db.Column(db.String(255), unique=True)
# role_id=db.Column(db.Integer,db.ForeignKey('role.id'))
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
# roles=db.relationship("Role",backref='auth')
def __repr__(self):
return "<Auth %r>"%self.name
39.3 forms.py 添加 AuthForm表单
# 5.权限得表单
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'
}
)
39.4 views.py添加 auth_add,auth_list,auth_edit,auth_del
auth_add,
#25.权限管理-权限添加
@admin.route("/auth_add/",methods=['GET','POST'])
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("权限添成功",'ok')
return render_template("admin/auth_add.html",form=form)
auth_list,
#26.日志管理-会员登录日志列表
@admin.route("/auth_list/<int:page>",methods=['GET'])
def auth_list(page=None):
#26.1判断是否
if page is None:
page=1
#26.2
page_data=Auth.query.order_by(
Auth.addtime.desc()
).paginate(page=page,per_page=1)
return render_template("admin/auth_list.html",page_data=page_data)
auth_edit,
#27.权限管理-权限编辑
@admin.route("/auth_edit/<int:id>",methods=['GET','POST'])
def auth_edit(id=None):
form=AuthForm()
auth=Auth.query.get_or_404(id)
form.submit.label.text='编辑'
if form.validate_on_submit():
data=form.data
auth.url=data['url']
auth.name=data['name']
db.session.add(auth)
db.session.commit()
flash("修改权限成功",'ok')
redirect(url_for('admin.auth_edit',id=id))
return render_template("admin/auth_edit.html",form=form,auth=auth)
auth_del
#28.权限管理-权限删除
@admin.route("/auth_del/<int:id>",methods=['GET'])
def auth_del(id=None):
auth=Auth.query.filter_by(id=id).first_or_404()
db.session.delete(auth)
db.session.commit()
flash("删除权限成功!",'ok')
return redirect(url_for("admin.auth_list",page=1))
39.5 admin文件夹中添加 auth_add.html,auth_list.html,auth_edit.html
auth_add.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.设置显示主内容-->
{% block content %}
<!--内容--->
<section class="content-header">
<h1>星空电影管理系统 | 后台</h1>
<ol class="breadcrumb">
<li>
<a href="#">
<i class="fa fa-dashboard"></i> 权限管理
</a>
</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" >
<div class="box-body">
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--1.权限名称-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--2.权限url-->
<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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-9').addClass('active');
$('#g-9-1').addClass('active');
});
</script>
{% endblock %}
,auth_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.权限列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>名称</th>
<th>地址</th>
<th>添加时间</th>
<th>操作事项</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.name }}</td>
<td>{{ v.url }}</td>
<td>{{ v.addtime }}</td>
<td>
<a href="{{ url_for('admin.auth_edit',id=v.id) }}" class="label label-success">编辑</a>
<a href="{{ url_for('admin.auth_del',id=v.id) }}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.auth_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-9').addClass('active');
$('#g-9-2').addClass('active');
});
</script>
{% endblock %}
,auth_edit.html
<!--1.继承 admin.html-->
{% extends 'admin/admin.html' %}
<!--2.主页面区域-->
{% block content %}
<!--2.1 页面路径-->
<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>
<!--2.2 主内容-->
<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>
<!--2.2.1 表单-->
<form role="form" method="post">
<div class="box-body">
<!--2.2.2 弹出框-->
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--2.2.3 权限框-->
<div class="form-group">
<label for="input_name">{{ form.name.label }}</label>
{{ form.name(value = auth.name) }}
{% for err in form.name.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--2.2.4 权限框-->
<div class="form-group">
<label for="input_name">{{ form.url.label }}</label>
{{ form.url(value = auth.url) }}
{% for err in form.url.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<!--2.2.4 修改按钮和令牌-->
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.修改左侧菜单页面内容-->
{% block js %}
<script>
$(document).ready(function (){
$('#g-9').addClass('active');
$('#g-9-2').addClass('active');
});
</script>
{% endblock %}
40.角色管理
40.1 grid.html 添加角色管理
<!--10.角色管理-->
<li class="treeview" id="g-10">
<a href="#">
<i class="fa fa-home" 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>
</ul>
<ul class="treeview-menu">
<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>
40.2 models.py 编写Role模型
#11.角色
class Role(db.Model):
__tablename__='role'
__table_args__={'useexisting':True}
id=db.Column(db.Integer,primary_key=True)
name=db.Column(db.String(100),unique=True)
# auths = db.Column(db.String(600),db.ForeignKey('auth.id'))
auths=db.Column(db.String(600))
addtime=db.Column(db.DateTime,index=True,default=datetime.now)
admins = db.relationship('Admin', backref='role') # 管理员外键关联
# auths=db.relationship('Auth',backref='role')
def __repr__(self):
return "<Role %r>"%self.name
40.3 forms.py 添加RoleForm表单
# 6.角色的表单
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 Auth.query.all()],
description='权限列表',
render_kw={
'class':'form-control'
}
)
submit=SubmitField(
'添加',
render_kw={
'class':'btn btn-primary'
}
)
40.4 views.py添加 role_add,role_list,role_edit,role_del
role_add
#29.角色管理-角色添加
@admin.route("/role_add",methods=['GET','POST'])
def role_add():
#29.1
form=RoleForm()
#29.2 判断表单中按钮是否点击
if form.validate_on_submit():
#29.3 获取表单数据
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("添加角色成功!",'ok')
return render_template("admin/role_add.html",form=form)
,role_list,
#30.角色管理-角色列表
@admin.route("/role_list/<int:page>",methods=['GET'])
def role_list(page=None):
#30.1判断是否page为none
if page is None:
page=1
#30.2 查询并分页数据
page_data=Role.query.order_by(
Role.addtime.desc()
).paginate(page=page,per_page=1)
'''角色权限显示权限名称'''
for v in page_data.items:
# 设置显示的字符串
auths_str=''
#auths
if v.auths:
# 对权限列表字段值进行切割 返回列表['3','6','7']
ah_list=v.auths.split(',')
# 循环遍历权限列表值
for ix in ah_list:
#根据id查询auth权限表中的名称数据
ah=Auth.query.filter_by(id=int(ix)).first_or_404()
#添加数据
auths_str+=ah.name+','
else:
auths_str='无任何权限'
# 将需要显示的数据设置到分页数据中
v.auths=auths_str
return render_template("admin/role_list.html",page_data=page_data)
role_edit
#31.角色管理-角色编辑
@admin.route("/role_edit/<int:id>",methods=['GET','POST'])
def role_edit(id=None):
form=RoleForm()
role=Role.query.get_or_404(id)
form.submit.label.text='修改'
if request.method=='GET' and role.auths:
auths=role.auths
form.auths.data=list(map(lambda v:int(v),auths.split(',')))
# 31.5 判断表单是否点击了按钮
if form.validate_on_submit():
#31.5.2
data=form.data
#31.5.2
role.name=data['name']
#31.5.3 根据权限值设置 添加的权限列表值
role.auths=','.join(map(lambda v:str(v),data['auths']))
db.session.add(role)
db.session.commit()
flash('修改角色成功了!','ok')
return render_template("admin/role_edit.html",form=form,role=role)
role_del
#32.角色管理-角色删除
@admin.route("/role_del/<int:id>",methods=['GET'])
def role_del(id=None):
role=Role.query.filter_by(id=id).first_or_404()
db.session.delete(role)
db.session.commit()
flash("删除角色成功!",'ok')
return redirect(url_for("admin.role_list",page=1))
40.5 admin文件夹中添加role_add.html,role_list.html,role_edit.html
role_add.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
{% block css %}
<style>
#auth_list.col-md-12,#auth_list{
padding: 0px;
}
</style>
{% endblock %}
<!--2.设置显示主内容-->
{% block content %}
<!--内容--->
<section class="content-header">
<h1>星空电影管理系统 | 后台</h1>
<ol class="breadcrumb">
<li>
<a href="#">
<i class="fa fa-dashboard"></i> 角色管理
</a>
</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" >
<div class="box-body">
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--角色设置-->
<div class="form-group" id="auth_list">
<label for="input_name">{{ form.auths.label }}</label>
{{ form.auths }}
{% for err in form.auths.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-10').addClass('active');
$('#g-10-1').addClass('active');
});
</script>
{% endblock %}
role_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.角色列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>名称</th>
<th>权限</th>
<th>添加时间</th>
<th>操作事项</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.name }}</td>
<td>{{ v.auths }}</td>
<td>{{ v.addtime }}</td>
<td>
<a href="{{url_for('admin.role_edit',id=v.id)}}" class="label label-success">编辑</a>
<a href="{{url_for('admin.role_del',id=v.id)}}" class="label label-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.role_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-10').addClass('active');
$('#g-10-2').addClass('active');
});
</script>
{% endblock %}
role_edit.html
<!--1.继承 admin.html-->
{% extends 'admin/admin.html' %}
{% block css %}
<style>
#auth_list .col-md-12,#auth_list{
padding: 0px;
}
</style>
{% endblock %}
<!--2.主页面区域-->
{% block content %}
<!--2.1 页面路径-->
<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>
<!--2.2 主内容-->
<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>
<!--2.2.1 表单-->
<form role="form" method="post">
<div class="box-body">
<!--2.2.2 弹出框-->
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--2.2.3 角色框-->
<div class="form-group">
<label for="input_name">{{ form.name.label }}</label>
{{ form.name(value = role.name) }}
{% for err in form.name.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--2.2.4 权限框-->
<div class="form-group">
<label for="input_name">{{ form.auths.label }}</label>
{{ form.auths }}
{% for err in form.auths.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<!--2.2.4 修改按钮和令牌-->
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.修改左侧菜单页面内容-->
{% block js %}
<script>
$(document).ready(function (){
$('#g-10').addClass('active');
$('#g-10-2').addClass('active');
});
</script>
{% endblock %}
41.管理员管理
添加管理员
41.1 grid.html 添加权限管理
<!--11.管理员管理-->
<li class="treeview" id="g-11">
<a href="#">
<i class="fa fa-home" 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>
</ul>
<ul class="treeview-menu">
<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>
41.2 models.py 编写 Admin模型
# 1.管理员
class Admin(db.Model):
# 1.设置表格名称(数据库表一致)
__tablename__ = 'admin'
# 2.表格是否存在
__table_args__ = {'useexisting':True}
# 3.设置映射
id = db.Column(db.Integer,primary_key=True)# 编号
name = db.Column(db.String(100),unique=True)# 管理员账号
pwd = db.Column(db.String(100))# 管理员密码
is_super = db.Column(db.SmallInteger)# 是否为超级管理员 0为超级管理员
role_id = db.Column(db.Integer,db.ForeignKey('role.id'))# 所属角色
addtime = db.Column(db.DateTime,index=True,default=datetime.now())# 添加时间
'''外键关联'''
adminlogs = db.relationship('Adminlog',backref='admin') # 管理员登录日志外键关联
oplogs = db.relationship("Oplog",backref='admin') #管理员操作日志外键关联
# 4.显示对象属性
def __repr__(self):
return '<Admin %r>'%self.name
# 5.检查密码
def check_pwd(self,pwd):
# 系统密码
print("系统密码:",self.pwd)
# 用户密码
print("用户密码:",pwd)
return check_password_hash(self.pwd,pwd)
41.3 forms.py 添加 AdminForm表单
# 7.管理员的表单
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': '请输入管理员密码'
})
repwd = PasswordField(
label='管理员重复密码',
validators=[DataRequired('管理员重复密码不能为空'),
EqualTo('pwd',message='两次密码不一致')],
description='管理员重复密码',
render_kw={
'class': 'form-control',
'placeholder': '请输入管理员重复密码'
})
role_id=SelectField(
label='所属角色',
coerce=int,
choices=[(v.id,v.name) for v in Role.query.all()],
render_kw={
'class':'form-control'
}
)
submit = SubmitField(
'编辑',
render_kw={
'class': 'btn btn-primary'
}
)
41.4 views.py添加 admin_add,admin_list,admin_del
admin_add
#33.管理员管理-管理员添加
@admin.route("/admin_add",methods=['GET','POST'])
@admin_login_req
def admin_add():
form = AdminForm()
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
)
#33.5
db.session.add(admin)
db.session.commit()
flash("添加管理员成功!",'ok')
return render_template("admin/admin_add.html",form=form)
,admin_list
#34.管理员管理-管理员列表
@admin.route("/admin_list/<int:page>",methods=['GET'])
def admin_list(page=None):
#34.1 判断page是否有值
if page is None:
page=1
#34.2分页查询数据
page_data=Admin.query.join(Role).filter(
Role.id==Admin.role_id
).order_by(
Admin.addtime.desc()
).paginate(page=page,per_page=1)
'''34.3 根据session中的id值进行查询is_supper的值'''
#获取登录的用户id的值
account_id=session['admin_id']
#查询数据
adm=Admin.query.filter_by(id=account_id).first_or_404()
# 将查询数据传递到前端页面
return render_template("admin/admin_list.html",
page_data=page_data,
isSuper=adm.is_super)
,admin_del
#35.管理员管理-管理员删除
@admin.route("/admin_del/<int:id>",methods=['GET'])
def admin_del(id=None):
admin=Admin.query.filter_by(id=id).first_or_404()
db.session.delete(admin)
db.session.commit()
flash("删除管理员成功!",'ok')
return redirect(url_for("admin.admin_list",page=1))
41.5 admin文件夹中添加 admin_add.html,admin_list.html
admin_add.html,
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.设置显示主内容-->
{% block content %}
<!--内容--->
<section class="content-header">
<h1>星空电影管理系统 | 后台</h1>
<ol class="breadcrumb">
<li>
<a href="#">
<i class="fa fa-dashboard"></i> 管理员管理
</a>
</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" >
<div class="box-body">
<!--成功弹出框-->
{% for msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</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">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--3.管理员重复密码-->
<div class="form-group">
<label for="input_pwd">{{ form.pwd.label }}</label>
{{ form.pwd }}
{% for err in form.pwd.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--4.管理员重复密码-->
<div class="form-group">
<label for="input_repwd">{{ form.repwd.label }}</label>
{{ form.repwd }}
{% for err in form.repwd.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
<!--5.管理员重复密码-->
<div class="form-group">
<label for="input_role_id">{{ form.role_id.label }}</label>
{{ form.role_id }}
{% for err in form.role_id.errors %}
<div class="col-md-12">
<p style="color: red">{{ err }}</p>
</div>
{% endfor %}
</div>
</div>
<div class="box-footer">
{{ form.csrf_token }}
{{ form.submit }}
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
<!--3.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-11').addClass('active');
$('#g-11-1').addClass('active');
});
</script>
{% endblock %}
admin_list.html
<!--1.继承admin.html-->
{% extends 'admin/admin.html' %}
<!--2.导入分页查询页面-->
{% import 'ui/admin_page.html' as pg %}
<!--3.管理员列表主内容-->
{% 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 msg in get_flashed_messages(category_filter=['ok']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--失败弹出框-->
{% for msg in get_flashed_messages(category_filter=['err']) %}
<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>
{{ msg }}
</div>
{% endfor %}
<!--表格显示-->
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>管理员名称</th>
<th>管理员类型</th>
<th>管理员角色</th>
<th>添加时间</th>
{% if isSuper==0 %}
<th>操作事项</th>
{% endif %}
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.name }}</td>
<td>
{% if v.is_super==0 %}
超级管理员
{% else %}
普通管理员
{% endif %}
</td>
<td>{{ v.role.name }}</td>
<td>{{ v.addtime }}</td>
{% if isSuper==0 %}
<td>
<a href="{{url_for('admin.admin_del',id=v.id)}}" class="label label-danger">删除</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!--分页显示-->
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.admin_list') }}
</div>
</div>
</div>
</section>
{% endblock %}
<!--4.js区域-->
{% block js %}
<script>
$(documen).ready(function (){
$('#g-11').addClass('active');
$('#g-11-2').addClass('active');
});
</script>
{% endblock %}
42.修改密码
42.1 admin.html 添加修改密码请求
42.2 views.py中 添加pwd函数
42.3admin文件夹中添加pwd.html页面
43.退出系统
43.1 admin.html 添加退出系统请求
43.2 views.py中 添加logout函数
44.登录验证器
44.1 views.py中添加admin_login_req(f)
44.2 将所有的请求上方添加登录装饰器