models
中数据库的认证部分移动到app
初始化文件中flask_wtf
,可以安装一下先
pip install flask-wtf
forms.py
中from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, ValidationError
class LoginForm(FlaskForm):
"""管理员登录表单"""
account = StringField(
label='账号',
validators=[
DataRequired('请输入账号!')
],
description='账号',
render_kw={
"class":"from-control",
"placeholder":"请输入账号",
"required":"required"
}
)
pwd = StringField(
label='密码',
validators=[
DataRequired('请输入账号!')
],
description='账号',
render_kw={
"class": "from-control",
"placeholder": "请输入账号",
"required": "required"
} # 传递给前端标签的属性,直接从模板中拷贝过来
)
submit = SubmitField(
label='登录',
render_kw={
"class": "btn btn-primary btn-block btn-flat",
}
)
views.py
from app.admin.forms import LoginForm
# 后台登录
@admin.route('/login/', methods=["GET", "POST"])
def login():
form = LoginForm()
# 反过来执行判断
if form.validate_on_submit():
data = form.data
admin = Admin.query.filter_by(name=data['account']).first() # 这是一条包含信息的对象
if not admin.check_pwd(data['pwd']):
flash("密码错误!")
return redirect(url_for('admin.login'))
# 密码正确,保存账号
session['admin'] = data['account'] # 账号
return redirect(request.args.get('next') or url_for('admin.index'))
return render_template('admin/login.html', form=form)
login.html
<input name="user" type="text" class="form-control" placeholder="请输入账号!">
{{ form.account }}
<input name="pwd" type="password" class="form-control" placeholder="请输入密码!">
{{ form.pwd }}
<a id="btn-sub" type="submit" class="btn btn-primary btn-block btn-flat">登录a>
{{ form.submit }}
csrf
字段,这是一种保护策略(跨站请求伪造),我们可以查看官方文档使用
SECRET_KEY
,可以使用uuid模块生成{{ form.csrf_token }}
即可生成隐藏的csrf标签{% for err in form.account.errors %}
<div class="col-md-12">
<font style="color:red">{{err}}font>
div>
{% endfor %}
def validate_account(self, field):
account = field.data
admin = Admin.query.filter_by(name=account).count() # 使用数据库模型查询用户信息
if admin == 0:
raise ValidationError("账号不存在!")
# models.py
# class Admin
def check_pwd(self, pwd):
from werkzeug.security import check_password_hash
return check_password_hash(self.pwd, pwd)
from flask import Flask, render_template, redirect, url_for, flash, session, request
# 后台登录
@admin.route('/login/', methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
data = form.data
admin = Admin.query.filter_by(name=data['account']).first() # 这是一条包含信息的对象
if not admin.check_pwd(data['pwd']):
flash("密码错误!")
return redirect(url_for('admin.login'))
# 密码正确,保存账号
session['admin'] = data['account'] # 账号
return redirect(request.args.get('next') or url_for('admin.index'))
return render_template('admin/login.html', form=form)
flash
,需要前端加点东西{% for msg in get_flashed_messages() %}
<p class="login-box-msg" style="color:red;">{{ msg }}p>
{% endfor %}
# admin/views.py
from functools import wraps # 作用是不改变被装饰函数的信息
def admin_login(f):
@wraps(f)
def inner(*args, **kwargs):
if "admin" not in session: # 不能使用 session['admin'] is None
return redirect(url_for('admin.login', next=request.url)) # next参数表示继续之前请求的地址
return f(*args, **kwargs) # 返回,不调用
return inner
# 然后我们给每个视图函数加上这个装饰器语法糖,例如
@admin.route('/logout')
@admin_login
def logout():
session.pop('admin', None) # 清除session
return redirect(url_for('admin.login'))
# 注意admin.html布局文件中,退出是路由到logout
forms
中定义表单模型class TagForm(FlaskForm):
"""标签添加表单"""
name = StringField(
label='标签名称',
validators=[
DataRequired("请输入标签名称!")
],
description="标签",
render_kw={
"class" : "form-control",
"id" : "input_name",
"placeholder" : "请输入标签名称!"
}
)
submit = SubmitField(
label="添加",
render_kw={
"class" : "btn btn-primary"
}
)
# 标签的添加和列表
@admin.route('/tag/add', methods=["GET", "POST"]) # 这个方法必须定义,否则validator不显示
@admin_login
def tag_add():
form = TagForm()
print("aaaaaaaaaaaaaaaa")
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']
)
db.session.add(tag)
db.session.commit()
flash("标签添加成功", 'ok') # 第二个参数是固定的一些值,应用到模板 category_filter=["ok"]
return render_template('admin/tagadd.html', form=form)
{{form.csrf_token}}
这玩意儿写错了搞了半天,要细心!{% 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">
,前端就要传递页码哦!@admin.route('/tag/list//' , methods=['GET'])
@admin_login
def tag_list(page=None):
if page is None:
page = 1
page_data = Tag.query.order_by(
Tag.addtime.desc()
).paginate(page=page, per_page=2)
return render_template('admin/taglist.html', page_data=page_data)
SQLAlchemy
,templates中新建ui/admin_page.html
,使用macro
的语法,可以参考官方文档url_for
中使用/
拼接,自动放入url,再正则解析,还不同于查询参数?x=x
{{url_for('admin.tag_edit', id=v.id)}}
# menu.html,初始化第一页
<li>
<a href="{{url_for('admin.tag_list', page=1)}}">
<i class="fa fa-circle-o">i> 标签列表
a>
li>
{% 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==data.page %}
<li class="active"><a href="#">{{v}}a>li>
{% else %}
<li><a href="{{url_for(url, page=v)}}">{{v}}a>li>
{% endif %}
{% endfor %}
{% if data.has_next %}
<li><a href="{{url_for(url,page=data.next_num)}}">下一页a>li>
{% else %}
<li class="disabled"><a href="">上一页a>li>
{% endif %}
<li><a href="{{url_for(url, page=data.pages)}}">尾页a>li>
ul>
{% endif %}
{% endmacro %}
{% import "ui/admin_page.html" as pg%}
<div class="box-footer clearfix">
{{pg.page(page_data, 'admin.tag_list')}}
div>
# 标签删除
@admin.route('/tag/del//' , methods=['GET'])
@admin_login
def tag_del(id=None):
tag = Tag.query.filter_by(id=id).first_or_404() # 如果没找到会报错
db.session.delete(tag)
db.session.commit()
flash("删除成功!", "ok")
return redirect(url_for('admin.tag_list', page=1))
# html
<a href="{{url_for('admin.tag_del', id=v.id)}}" class="label label-danger">删除</a>
# 标签编辑
@admin.route('/tag/edit//' , methods=['GET', 'POST'])
@admin_login
def tag_edit(id=None):
# 编辑相当于重新提交一个表单
form = TagForm() # 和tagadd共用表单模型
tag = Tag.query.get_or_404(id) # 要修改的标签名
if form.validate_on_submit():
data = form.data # 提交的标签名
tag_count = Tag.query.filter_by(name=data['name']).count()
if tag_count == 1: # tag.name != data['name'] and
flash("名称已存在", 'err')
tag.name = data['name']
db.session.add(tag)
db.session.commit()
flash("编辑成功!", "ok")
return redirect(url_for('admin.tag_list', page=1))
return render_template("admin/tagedit.html", form=form, tag=tag) # 先渲染到前端,再返回验证
{{form.name(value=tag.name)}}
{% extends "admin/admin.html" %}
{% block content %}
<section class="content-header">
<h1>微电影管理系统h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard">i> 标签管理a>li>
<li class="active">编辑标签li>
ol>
section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">编辑标签h3>
div>
<form role="form" method="post">
<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(value=tag.name)}}
{% for err in form.name.errors %}
<div class="col-md-12">
<span style="color: red">{{ err }}span>
div>
{% endfor %}
div>
div>
<div class="box-footer">
{{form.submit}}
{{form.csrf_token}}
div>
form>
div>
div>
div>
section>
{% endblock %}
{% block js%}
<script>
$(document).ready(function () {
$('#m-2').addClass("active");
})
script>
{% endblock %}
class MovieForm(FlaskForm):
"""电影添加表单"""
title = StringField(
label='电影名称',
validators=[
DataRequired("请输入电影名称!")
],
description="标签",
render_kw={
"class": "form-control",
"id": "input_title",
"placeholder": "请输入片名!"
}
)
url = FileField(
label='文件',
validators=[
DataRequired("请上传文件")
],
description="文件"
)
info = TextAreaField(
label='简介',
validators=[
DataRequired("请输入电影简介")
],
description="简介",
render_kw={
"class": "form-control",
"rows":"10",
"id": "input_info"
}
)
logo = FileField(
label='logo图片',
validators=[
DataRequired("请上传文件")
],
description="logo"
)
star = SelectField(
label='星级',
validators=[
DataRequired("请选择星级")
],
description="星级",
coerce=int,
choices=[(1,"1星"),(2,"2星"),(3,"3星"),(4,"4星"),(5,"5星")],
render_kw={
"class": "form-control",
"id": "input_star"
}
)
tag_id = SelectField(
label='标签',
validators=[
DataRequired("请选择标签")
],
description="标签",
coerce=int,
choices=[(v.id, v.name) for v in tags], # 列表推导式,传递到前端只显示v.name,给到视图是v.id
render_kw={
"class": "form-control",
"id": "input_tag_id"
}
)
area = StringField(
label='地区',
validators=[
DataRequired("请输入地区")
],
description="地区",
render_kw={
"class": "form-control",
"id": "input_area",
"placeholder" : "请输入地区!"
}
)
length = StringField(
label='片长',
validators=[
DataRequired("请输入片长")
],
description="地区",
render_kw={
"class": "form-control",
"id": "input_length",
"placeholder" : "请输入片长!"
}
)
release = StringField(
label='上映时间',
validators=[
DataRequired("请输入上映时间")
],
description="上映时间",
render_kw={
"class": "form-control",
"id": "input_release_time",
"placeholder" : "请输入上映时间!"
}
)
submit = SubmitField(
label="添加",
render_kw={
"class": "btn btn-primary"
}
)
<form role="form" method="POST" enctype="multipart/form-data">
# 电影的添加
from werkzeug.utils import secure_filename
@admin.route('/movie/add', methods=['GET','POST'])
@admin_login
def movie_add():
form = MovieForm()
if form.validate_on_submit():
data = form.data
# 准备一条数据插入
# 过滤数据名
file_url = secure_filename(form.url.data.filename)
file_logo = secure_filename(form.logo.data.filename)
# 准备存储路径
if not os.path.exists(app.config['UP_DIR']):
os.mkdir(app.config['UP_DIR'])
os.chmod(app.config['UP_DIR'], "rw")
# 更改文件名
file_url = changeFileName(file_url)
file_logo = changeFileName(file_logo)
# 保存文件
form.url.data.save(app.config['UP_DIR'] + file_url)
form.logo.data.save(app.config['UP_DIR'] + file_logo)
movie = Movie(
title = data['title'],
url = file_url,
info = data["info"],
logo = file_logo,
star = int(data["star"]),
playnum = 0,
commentnum = 0,
tag_id = int(data['tag_id']), # 给到视图的是v.id ,和表单模型的choices属性有关
area = data['area'],
release_time = data['release'],
length = data["length"]
)
db.session.add(movie)
db.session.commit()
flash("添加电影成功!", "ok")
return render_template('admin/movieadd.html', form=form)
__init__
配置了,并做处理app.config['UP_DIR'] = os.path.join(os.path.abspath(__file__),"/static/uploads/") # 以当前文件为参考,拼接上传文件的保存路径
from werkzeug.utils import secure_filename
import os
from datetime import datetime
def changeFileName(filename):
'''
修改传入文件的名称
:return:
'''
file = os.path.splitext(filename) # 将名称和后缀分开
filename = datetime.now().strftime("%Y%m%d%H%M%S")+str(uuid.uuid4().hex)+str(file[-1])
return filename
# 保存文件时使用save方法
form.url.data.save(app.config['UP_DIR'] + file_url) # 是加号,不是逗号
# app中添加配置时
app.config['UP_DIR'] = os.path.join(os.path.abspath(os.path.dirname(__file__)),"static/uploads/") # uploads后面这个 / 必须写
# 情况当前表中数据
delete from movie; # truncate 有外键约束
@admin.route('/movie/list/' , methods=['GET'])
@admin_login
def movie_list(page=None):
if page==None:
page = 1
# 一个个电影挨着查
page_data = Movie.query.join(Tag).filter(
Tag.id == Movie.tag_id # 多表关联时使用 movie为多端 这里就是查到tag表对应的整条记录,使用时用v.tag.name
).order_by(
Movie.addtime.desc()
).paginate(page=page, per_page=10)
return render_template('admin/movielist.html', page_data=page_data)
@admin.route('/movie/del/' , methods=['GET'])
@admin_login
def movie_del(id):
movie = Movie.query.get_or_404(int(id)) # 如果没有直接跳到404
db.session.delete(movie) # 评论等数据和movie关联,movie是主表,所以会连带一起删除
db.session.commit()
flash("电影删除成功!", "ok") # 小写 ok
return redirect(url_for("admin.movie_list", page=1)) # 重定向,需要模板渲染有add edit 和 list
# 编辑电影
@admin.route('/movie/edit/' , methods=['GET', "POST"])
@admin_login
def movie_edit(id):
form = MovieForm()
form.url.validators = []
# print(form.url.validators)
form.logo.validators = [] # 跳过未选择文件的验证
# 问题:required字段搞不掉?打印发现这么写没问题,解决方案:
# render_kw = {
# "required": False
# }
# 但是这样会在添加的时候不提示选择文件
# 更好的方案是就该edit.html {{form.logo(required=False)}}
movie = Movie.query.get_or_404(int(id)) # 如果没有直接跳到404
# 处理movie某些原信息不显示的问题,通过请求方法区分
if request.method=="GET":
form.info.data = movie.info
form.star.data = movie.star
form.tag_id.data = movie.tag_id # 模板中就不需要 value=movie.info
if form.validate_on_submit(): # POST
data = form.data
m = Movie.query.filter_by(title=data['title']).count()
if m==1:
flash("电影已存在","err")
return redirect(url_for("admin.movie_edit", id=id))
movie.title = data["title"]
movie.info = data["info"]
movie.star = data["star"]
movie.tag_id = data["tag_id"]
movie.area = data["area"]
movie.length = data["length"]
movie.release_time = data["release"] # name属性
# 文件重传
if not os.path.exists(app.config["UP_DIR"]):
os.mkdir(app.config["UP_DIR"])
os.chmod(app.config["UP_DIR"], "rw")
if form.url.data.filename != "": # 问选择文件就是空,现在有值说明重传了(跟显示原文件无关)
file_url = secure_filename(form.url.data.filename)
movie.url = changeFileName(file_url) # 更新原数据信息
form.url.data.save(app.config["UP_DIR"] + movie.url)
if form.logo.data.filename != "":
file_logo = secure_filename(form.logo.data.filename)
movie.logo = changeFileName(file_logo)
form.logo.data.save(app.config["UP_DIR"] + movie.logo)
db.session.add(movie) # 修改
db.session.commit()
flash("修改成功", "pk")
return redirect(url_for('admin.movie_list', page=1))
return render_template("admin/movieedit.html", form=form, movie=movie) # 渲染出原信息
# 预告的添加和列表
@admin.route('/preview/add', methods=['GET', 'POST'])
@admin_login
def preview_add():
'''和电影添加一样的过程'''
form = PreviewForm()
if form.validate_on_submit():
# 过滤
file_logo = secure_filename(form.logo.data.filename)
# 准备存储路径
if not os.path.exists(app.config["UP_DIR"]):
os.mkdir(app.config["UP_DIR"])
os.chmod(app.config["UP_DIR"], "rw")
# 更改文件名
file_logo = changeFileName(file_logo)
# 保存文件
form.logo.data.save(app.config["UP_DIR"] + file_logo)
data = form.data
# 准备一条数据入库
preview = Preview(
title = data["title"],
logo = file_logo # 存名字即可
)
db.session.add(preview)
db.session.commit()
flash("添加预告成功!", "ok")
return redirect(url_for('admin.preview_add'))
return render_template('admin/previewadd.html', form=form)
@admin.route('/preview/list/' )
@admin_login
def preview_list(page=None):
if page==None:
page = 1
page_data = Preview.query.order_by(
Preview.addtime.desc()
).paginate(page=page, per_page=10) # 视图部分提供数据,字典形式;前台部分使用macro渲染
return render_template('admin/previewlist.html', page_data=page_data)
@admin.route('/preview/del/' )
@admin_login
def preview_del(id=None):
preview = Preview.query.get_or_404(int(id)) # 如果没有直接跳到404
db.session.delete(preview) # 评论等数据和movie关联,movie是主表,所以会连带一起删除
db.session.commit()
flash("预告删除成功!", "ok") # 小写 ok
return redirect(url_for("admin.preview_list", page=1)) # 重定向,模板渲染有add edit 和 list
@admin.route('/preview/edit/' , methods=['GET', 'POST'])
@admin_login
def preview_edit(id=None):
form = PreviewForm()
form.logo.validators = []
preview = Preview.query.get_or_404(int(id)) # 如果没有直接跳到404
if form.validate_on_submit(): # POST
data = form.data
m = Preview.query.filter_by(title=data['title']).count()
if m == 1 and form.logo.data.filename == "":
flash("预告已存在", "err")
return redirect(url_for("admin.preview_edit", id=id))
preview.title = data["title"]
# 准备路径
if not os.path.exists(app.config["UP_DIR"]):
os.mkdir(app.config["UP_DIR"])
os.chmod(app.config["UP_DIR"], "rw")
if form.logo.data.filename != "":
file_logo = secure_filename(form.logo.data.filename)
preview.logo = changeFileName(file_logo)
form.logo.data.save(app.config["UP_DIR"] + preview.logo)
db.session.add(preview) # 修改
db.session.commit()
flash("修改成功", "ok")
return redirect(url_for('admin.preview_list', page=1))
return render_template("admin/previewedit.html", form=form, preview=preview) # 渲染出原信息
pip install cryptography
pip install -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com cryptography
-- uuid需要系统生成
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('鼠','1231','[email protected]','13888888881','鼠','1f401.png','d32a72bdac524478b7e4f6dfc8394fc0',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('牛','1232','[email protected]','13888888882','牛','1f402.png','d32a72bdac524478b7e4f6dfc8394fc1',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('虎','1233','[email protected]','13888888883','虎','1f405.png','d32a72bdac524478b7e4f6dfc8394fc2',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('兔','1234','[email protected]','13888888884','兔','1f407.png','d32a72bdac524478b7e4f6dfc8394fc3',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('龙','1235','[email protected]','13888888885','龙','1f409.png','d32a72bdac524478b7e4f6dfc8394fc4',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('蛇','1236','[email protected]','13888888886','蛇','1f40d.png','d32a72bdac524478b7e4f6dfc8394fc5',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('马','1237','[email protected]','13888888887','马','1f434.png','d32a72bdac524478b7e4f6dfc8394fc6',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('羊','1238','[email protected]','13888888888','羊','1f411.png','d32a72bdac524478b7e4f6dfc8394fc7',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('猴','1239','[email protected]','13888888889','猴','1f412.png','d32a72bdac524478b7e4f6dfc8394fc8',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('鸡','1240','[email protected]','13888888891','鸡','1f413.png','d32a72bdac524478b7e4f6dfc8394fc9',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('狗','1241','[email protected]','13888888892','狗','1f415.png','d32a72bdac524478b7e4f6dfc8394fd0',now());
insert into user(name,pwd,email,phone,info,face,uuid,addtime) values('猪','1242','[email protected]','13888888893','猪','1f416.png','d32a72bdac524478b7e4f6dfc8394fd1',now());
# 分页:后台准备数据,前台macro渲染
# 查询参数可有可无,定义 / 后必须每次都传递page
#会员列表
@admin.route('/user/list/' , methods=['GET'])
@admin_login
def user_list(page=None):
if page is None:
page = 1
page_data = User.query.order_by(
User.addtime.desc()
).paginate(page=page, per_page=4)
return render_template('admin/userlist.html', page_data=page_data)
# 会员详细信息查看
@admin.route('/user/view/' )
@admin_login
def user_view(id):
user = User.query.get_or_404(int(id))
return render_template('admin/userview.html', user=user)
@admin.route('/user/del/' , methods=['GET'])
@admin_login
def user_del(id):
user = User.query.get_or_404(int(id)) # 如果没有直接跳到404
db.session.delete(user) # 评论等数据和movie关联,movie是主表,所以会连带一起删除
db.session.commit()
flash("会员删除成功!", "ok") # 小写 ok
return redirect(url_for("admin.user_list", page=1)) # 重定向,模板渲染有add edit 和 list
-- 清空表后复位自增起点
ALTER TABLE comment auto_increment=1;
-- comment表外键约束movie表,user表
insert into comment(movie_id,user_id,content,addtime) values(7,1,"好看",now());
insert into comment(movie_id,user_id,content,addtime) values(7,2,"不错",now());
insert into comment(movie_id,user_id,content,addtime) values(7,3,"经典",now());
insert into comment(movie_id,user_id,content,addtime) values(7,4,"给力",now());
insert into comment(movie_id,user_id,content,addtime) values(8,5,"难看",now());
insert into comment(movie_id,user_id,content,addtime) values(8,6,"无聊",now());
insert into comment(movie_id,user_id,content,addtime) values(8,7,"乏味",now());
insert into comment(movie_id,user_id,content,addtime) values(8,8,"无感",now());
# 评论列表
@admin.route('/comment/list/' )
@admin_login
def comment_list(page=None):
if page==None:
page=1
page_data = Comment.query.join(
Movie
).join(
User
).filter(
Movie.id == Comment.movie_id,
User.id == Comment.user_id
).order_by(
Comment.addtime.desc()
).paginate(page=page, per_page=5)
# {{v.movie.title}}
return render_template('admin/commentlist.html', page_data=page_data)
@admin.route('/comment/del/' , methods=['GET'])
@admin_login
def comment_del(id):
comment = Comment.query.get_or_404(int(id)) # 如果没有直接跳到404
db.session.delete(comment) # 评论等数据和movie关联,movie是主表,所以会连带一起删除
db.session.commit()
flash("评论删除成功!", "ok") # 小写 ok
return redirect(url_for("admin.comment_list", page=1))
alter table movcollec drop content;
# 收藏列表
@admin.route('/collect/list/' )
@admin_login
def collect_list(page=None):
if page==None:
page=1
page_data = MovCollection.query.join(
Movie
).join(
User
).filter(
Movie.id == MovCollection.movie_id,
User.id == MovCollection.user_id
).order_by(
MovCollection.addtime.desc()
).paginate(page=page, per_page=8)
return render_template('admin/collectlist.html', page_data=page_data)
@admin.route('/collect/del/' , methods=['GET'])
@admin_login
def collect_del(id):
collect = MovCollection.query.get_or_404(int(id)) # 如果没有直接跳到404
db.session.delete(collect)
db.session.commit()
flash("收藏删除成功!", "ok")
return redirect(url_for("admin.collect_list", page=1))
@admin.route('/cpwd', methods=['GET', 'POST'])
@admin_login
def cpwd():
form = PwdForm()
if form.validate_on_submit():
data = form.data
# 这里需要传递命名参数,对应字段名;否则会参数异常
admin = Admin.query.filter_by(name=session['admin']).first()
from werkzeug.security import generate_password_hash
admin.pwd = generate_password_hash(data['new_pwd'])
db.session.add(admin)
db.session.commit()
flash("修改密码成功!重新登录",'ok')
return redirect(url_for('admin.logout'))
return render_template('admin/pwd.html', form=form)
@admin.context_processor
def tpl_extra():
'''
上下文处理器
:return:
'''
# 创建全局变量,直接在admin.html渲染
data = dict(
online_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
# 例如在添加标签时:
def tag_add():
form = TagForm()
if form.validate_on_submit(): # 没过验证
data = form.data
tag = Tag.query.filter_by(name=data['name']).count()
if tag == 1:
flash("标签已存在!", "err")
return redirect(url_for('admin.tag_add'))
tag = Tag(
name= data['name']
)
db.session.add(tag)
db.session.commit()
flash("标签添加成功", 'ok') # 第二个参数是固定的一些值,应用到模板 category_filter=["ok"]
# 添加操作日志---------------------
oplog = OperateLog(
admin_id=session['admin_id'],
ip=request.remote_addr,
reason="添加标签 %s" % data['name']
)
db.session.add(oplog)
db.session.commit()
return render_template('admin/tagadd.html', form=form)
# 操作日志
@admin.route('/oplog/list/' )
@admin_login
def oplog_list(page=None):
if page==None:
page=1
page_data = OperateLog.query.join(
Admin
).filter(
Admin.id == OperateLog.admin_id
).order_by(
OperateLog.addtime.desc()
).paginate(page=page,per_page=3)
return render_template('admin/oploglist.html', page_data=page_data)
def login():
xxx
# 添加登录日志-----------------
admin = AdminLog(
admin_id = admin.id,
ip=request.remote_addr
)
db.session.add(admin)
db.session.commit()
xxx
# 管理员登录日志
@admin.route('/adminlog/list/' )
@admin_login
def adminlog_list(page=None):
if page==None:
page=1
page_data = AdminLog.query.join(
Admin
).filter(
Admin.id == AdminLog.admin_id
).order_by(
AdminLog.addtime.desc()
).paginate(page=page,per_page=2)
return render_template('admin/adminloglist.html', page_data=page_data)
insert into userlog(user_id,ip,addtime) values(1,"192.168.4.1",now());
insert into userlog(user_id,ip,addtime) values(2,"192.168.4.2",now());
insert into userlog(user_id,ip,addtime) values(3,"192.168.4.3",now());
insert into userlog(user_id,ip,addtime) values(4,"192.168.4.4",now());
insert into userlog(user_id,ip,addtime) values(5,"192.168.4.5",now());
insert into userlog(user_id,ip,addtime) values(6,"192.168.4.6",now());
insert into userlog(user_id,ip,addtime) values(7,"192.168.4.7",now());
insert into userlog(user_id,ip,addtime) values(8,"192.168.4.8",now());
insert into userlog(user_id,ip,addtime) values(9,"192.168.4.9",now());
# 会员登录日志
@admin.route('/userlog/list/' )
@admin_login
def userlog_list(page=None):
if page==None:
page=1
page_data = UserLog.query.join(
User
).filter(
User.id == UserLog.user_id
).order_by(
UserLog.addtime.desc()
).paginate(page=page,per_page=4)
return render_template('admin/userloglist.html', page_data=page_data)