说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
目录
一丶叙述
1.项目中使用到的知识点
- 使用整型丶浮点型丶路径型丶字符串型正则表达式以及路由转换器
- 使用get与post请求丶上传文件丶cookie获取与响应丶404页面处理
- 使用模板自动转义丶定义过滤器丶定义全局上下文处理器丶Jinjia2语法丶包含丶继承丶定义宏
- 使用flask_wtf定义表单模型丶字段类型丶字段验证丶视图处理表单丶模板使用表单
- 使用flask_sqlachemy定义数据库模型丶添加数据丶修改数据丶查询数据丶删除数据丶数据库事件丶数据库迁移
- 使用蓝图优化项目结构丶实现微电影网站前台与后台业务逻辑
- 通过nginx反向代理对视频流媒体限制下载速率丶限制单个ip能发起的播放连接数
- 微内核以及flask拓展插件,其中微内核包括werkzug工具箱丶pymysql数据库驱动sqlachemy数据库orm丶wtforms表单验证工具jinja2模板引擎丶flask-script命令行脚本丶functools定义高阶函数;插件包括jwplayer播放器插件丶视频限速限ip访问丶flv以及mp4视频格式支持丶nginx点播实现
2.环境搭建与工具
- 搭建开发环境依赖包丶virtuanlven虚拟化环境的使用
- pycharm编辑器
3.项目优化与模型设计
- 使用flask蓝图Blueprint规划项目结构
- 使用flask_sqlachemy定义和业务需求相关的数据库模型
- 结合mysql数据库生成项目所需的数据表
4.前端搭建
- 实现前台后台html布局页面搭建
- 使用jinjia2引擎
- 引入静态资源文件丶404错误页面处理
5.后端开发
- 使用flask sqlachemy结合mysql数据表进行增删改查操作
- flask数据分页查询丶路由装饰器定义丶模板中变量调用丶登录回话机制丶上传文件
- flask wtforms表单验证丶flask自定义应用上下文丶自定义权限权限装饰器对管理系统进行基于角色权限的访问控制
- flask多表关联查询丶关键字模糊查询
6.网站部署
- 实现在centos服务器上搭建nginx+mysql+python环境
- 使用nginx反向代理多端口多进程部署微电影网站
- 配置nginx流媒体访问限制参数
7.前台静态主页面效果预览
8.后台管理静态主页面效果预览
9.微电影网站组成
10.开发及生产环境
- 生产环境:Centos7
- 开发语言:Python3
- 数据库:MySQL
- 前端:HTML5及BootStrap框架(AdminLTE:一个基于bootstrap框架的轻量级后台模板)
- Web开发框架:Flask
- Web服务器:Nginx
- 编程工具:PyCharm
二丶Windows环境搭建
说明:博主这里使用Python3.6开发语言 数据库Mysql5.7 PyCharm编程工具(这三个就不进行演示了)以及安装虚拟环境
- 安装项目虚拟环境
- 创建虚拟环境
- 配置项目解释器
- 安装Flask包成功后,查看当前环境下的包
三丶项目分析丶搭建目录以及模型设计
1.前台项目目录分析
前台(home)
- 数据模型:models.py
- 表单处理:home/forms.py
- 模板目录:templates/home
2.后台项目目录分析
- 后台(admin)
- 数据模型:models.py
- 表单处理:admin/forms.py
- 模板目录:templates/admin
- 静态目录:static
3.前后台项目目录分析
- manage.py 入口启动脚本
- app 项目APP
- __init__.py 初始化文件
- models.py 数据库模型文件
- static 静态目录
- home/admin 前台/后台模块
- __init__.py 初始化文件
- views.py 视图处理文件
- forms.py 表单处理文件
- templates 模板目录
- home/admin 前台/后台模板
4.搭建目录
5.搭建蓝图
- 在home/__init__.py文件中定义蓝图
# coding:utf-8
from flask import Blueprint
home = Blueprint("home", __name__)
import app.home.views
- 在admin/__init__.py文件中定义蓝图
# coding:utf-8
from flask import Blueprint
admin = Blueprint("admin", __name__)
import app.admin.views
- 在home/views.py文件中定义视图
# coding:utf-8
from . import home
@home.route('/')
def index():
return "<h1 style='color:red'>hello home</h1>"
- 在admin/views.py文件中定义视图
# coding:utf-8
from . import admin
@admin.route('/')
def index():
return "<h1 style='color:green'>hello admin</h1>"
- 在app/__init__.py文件中创建app对象并使用app对象注册蓝图
#coding:utf-8
from flask import Flask
app = Flask(__name__)
app.debug = True
from app.admin import admin as admin_blueprint
from app.home import home as home_blueprint
# 注册蓝图
app.register_blueprint(admin_blueprint, url_prefix="/admin")
app.register_blueprint(home_blueprint)
- 在manage.py中定义启动脚本
# coding:utf-8
from app import app
if __name__ == '__main__':
app.run()
- 运行项目后,在浏览器中分别输入http://127.0.0.1:5000/以及http://127.0.0.1:5000/admin/
6.会员及会员登录日志数据模型设计
- 创建项目所需数据库
- 安装Flask-SQLAlchemy
pip install flask-sqlalchemy
- 安装PyMySQL
pip install pymysql
- 定义会员数据模型
class User(db.Model):
__tablename__ = "user"
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) # 唯一标志符
userlogs = db.relationship('UserLog', backref='user') # 会员日志外键关系
comments = db.relationship('Comment', backref='user') # 评论外键关系关联
moviecols = db.relationship('MovieCol', backref='user') # 电影收藏外键关系关联
def __str__(self):
return "<User:%r>" % self.name
- 定义会员登录日志模型
class UserLog(db.Model):
__tablename__ = "userlog"
id = db.Column(db.Integer, primary_key=True) # 编号
user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # 所属会员
ip = db.Column(db.String(100)) # 登录IP
addtime = db.Column(db.DateTime, index=True, default=datetime.now) # 登录时间
def __repr__(self):
return '<UserLog %r>' % self.id
7.标签丶电影丶上映预告数据模型设计
- 定义标签数据模型
class Tag(db.Model):
__tablename__ = "tag"
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) # 添加时间
movies = db.relationship('Movie', backref='tag') # 电影外键关系关联
def __repr__(self):
return '<Tag %r>' % self.name
- 定义电影数据模型
class Movie(db.Model):
__tablename__ = "movie"
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') # 电影评论外键关联
movieclos = db.relationship('MovieCol', backref='movie') # 电影收藏外键关联
def __repr__(self):
return '<Movie %r>' % self.title
- 定义上映预告数据模型
class Preview(db.Model):
__tablename__ = "preview"
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
8.评论丶收藏丶权限丶角色丶管理员丶操作日志数据模型设计
- 定义评论数据模型
class Comment(db.Model):
__tablename__ = "comment"
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
- 定义收藏电影数据模型
class MovieCol(db.Model):
__tablename__ = "moviecol"
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
- 定义权限数据模型
class Auth(db.Model):
__tablename__ = "auth"
id = db.Column(db.Integer, primary_key=True) # 编号
name = db.Column(db.String(100), unique=True) # 名称
url = db.Column(db.String(255), unique=True) # 电影地址
addtime = db.Column(db.DateTime, index=True, default=datetime.now) # 添加时间
def __repr__(self):
return '<Auth %r>' % self.name
- 定义角色数据模型
class Role(db.Model):
__tablename__ = "role"
id = db.Column(db.Integer, primary_key=True) # 编号
name = db.Column(db.String(100), unique=True) # 名称
auths = db.Column(db.String(600)) # 权限列表
admins = db.relationship("Admin", backref='role') # 管理员外键关系关联
addtime = db.Column(db.DateTime, index=True, default=datetime.now) # 添加时间
def __repr__(self):
return '<Role %r>' % self.name
- 定义管理员数据模型
class Admin(db.Model):
__tablename__ = "admin"
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') # 管理员操作日志外键关系关联
def __repr__(self):
return '<Admin %r>' % self.name
- 定义管理员登录日志数据模型
class AdminLog(db.Model):
__tablename__ = "adminlog"
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
- 定义操作日志数据模型
class OpLog(db.Model):
__tablename__ = "oplog"
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.now) # 添加时间
def __repr__(self):
return '<OpLog %r>' % self.id
9.生成数据表
- 调用db对象中create_all方法
if __name__ == '__main__':
db.create_all()
- 运行models.py文件,提示如下错误
- 解决以上报错,导入pymysql并在配置uri中添加pymysql
import pymysql
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:mysql@127.0.0.1:3306/movie"
- 再次运行成功
- 查看数据库movie下的表
10.添加表数据
- 向角色表(role)添加数据
if __name__ == '__main__':
# db.create_all()
role = Role(
name="超级管理员",
auths=""
)
db.session.add(role)
db.session.commit()
- 查看role表数据
- 向管理员表(admin)添加数据
if __name__ == '__main__':
from werkzeug.security import generate_password_hash
admin = Admin(
name="taogangshow",
pwd=generate_password_hash("hellomovie"),
is_super=0,
role_id=1
)
db.session.add(admin)
db.session.commit()
- 查看admin表数据
四丶搭建前台页面
1.会员登录退出页面搭建
- 将静态资源文件放在static目录下
- 将tpl/2-movie目录下的nav.html文件拷贝到templates/home目录下并命名为home.html,用作于父模板
- 将home.html中的静态文件引入方式全部修改为{{url_for('static', filename='xxx')}},如下
<link rel="shortcut icon" href="{{url_for('static', filename='base/images/logo.png')}}">
<link rel="stylesheet" href="{{url_for('static', filename='base/css/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{url_for('static', filename='base/css/bootstrap-movie.css')}}">
<link rel="stylesheet" href="{{url_for('static', filename='base/css/animate.css')}}">
- 在内容div容器中挖坑(定义数据块)
<div class="container" style="margin-top:76px">
{% block content%}{% endblock %}
</div>
- 在templates/home目录下新建index.html文件,继承与home.html
{% extends "/home/home.html" %}
{% block content %}
<h1>cdtaogang</h1>
{% endblock%}
- 在home/views.py文件中渲染出index.html模板文件
@home.route('/')
def index():
return render_template("home/index.html")
- 启动项目,进入http://127.0.0.1:5000/显示页面
- 在home/views.py文件中定义登录以及退出视图
@home.route('/login/')
def login():
return render_template("home/login.html")
@home.route('/logout/')
def logout():
return redirect(url_for("home.login")) # 跳转到登录页
- 将tpl/2-movie目录下的login.html文件拷贝到templates/home目录下,其余部分删除只保留内容块继承父模板定义数据块
- 修改父模板home.html文件中登录和退出连接地址
<a class="curlink" href="{{url_for('home.login')}}"><span class="glyphicon glyphicon-log-in"></span> 登录</a>
<a class="curlink" href="{{url_for('home.logout')}}"><span class="glyphicon glyphicon-log-out"></span> 退出</a>
- 测试显示登录与退出页面
2.会员注册页面搭建
- 跟登录一样,首先定义视图函数
@home.route('/register/')
def register():
return render_template("home/register.html")
- 然后模板文件register.html
- 修改父模板文件home.html中导航栏注册地址
<a class="curlink" href="{{url_for('home.register')}}"><span class="glyphicon glyphicon-plus"></span> 注册</a>
- 运行项目,成功显示注册页面
3.会员中心页面搭建
会员中心
- 定义视图函数
# 会员中心
@home.route('/user/')
def user():
return render_template("home/user.html")
- 在templates/home目录下创建menu.html将注册页面中的菜单栏代码复制在该文件中
- 修改menu.html中代码,添加id属性,用于激活active
<div class="list-group">
<a id="m-1" href="{{url_for('home.user')}}" class="list-group-item">
<span class="glyphicon glyphicon-user"></span> 会员中心
</a>
<a id="m-2" href="{{url_for('home.pwd')}}" class="list-group-item">
<span class="glyphicon glyphicon-lock"></span> 修改密码
</a>
<a id="m-3" href="{{url_for('home.comments')}}" class="list-group-item">
<span class="glyphicon glyphicon-comment"></span> 评论记录
</a>
<a id="m-4" href="{{url_for('home.loginlog')}}" class="list-group-item">
<span class="glyphicon glyphicon-calendar"></span> 登录日志
</a>
<a id="m-5" href="{{url_for('home.moviecol')}}" class="list-group-item">
<span class="glyphicon glyphicon-heart"></span> 收藏电影
</a>
</div>
- home.html模板文件中新建数据模块,用于存放注册页面独有的CSS代码
- home.html模板文件底部新建数据模块,用于存放注册页面独有的JS代码
- 在templates/home目录下创建user.html将注册页面中的会员中心代码复制在该文件中,并继承父模板,需要将注册页面菜单栏menu.html文件包含在内容块中,以及填写css和js数据块数据
修改密码
- 定义视图函数
# 修改密码
@home.route('/pwd/')
def pwd():
return render_template("home/pwd.html")
- 在templates/home目录下创建pwd.html将注册页面中的会员中心代码复制在该文件中,同上只需要更改修改密码内容块以及底部js也就是class="col-md-9"和id属性值,因为除了独有部分不同其余部分相同
评论记录
- 定义视图函数
# 评论记录
@home.route('/comments/')
def comments():
return render_template("home/comments.html")
- 在templates/home目录下创建pwd.html将注册页面中的会员中心代码复制在该文件中,同上只需要更改评论记录内容块以及底部js也就是class="col-md-9"和id属性值,因为除了独有部分不同其余部分相同
登录日志
- 定义视图函数
# 登录日志
@home.route('/loginlog/')
def loginlog():
return render_template("home/loginlog.html")
- 在templates/home目录下创建pwd.html将注册页面中的会员中心代码复制在该文件中,同上只需要更改登录日志内容块以及底部js也就是class="col-md-9"和id属性值,因为除了独有部分不同其余部分相同
收藏电影
- 定义视图函数
# 收藏电影
@home.route('/moviecol/')
def moviecol():
return render_template("home/moviecol.html")
- 在templates/home目录下创建pwd.html将注册页面中的会员中心代码复制在该文件中,同上只需要更改收藏电影内容块以及底部js也就是class="col-md-9"和id属性值,因为除了独有部分不同其余部分相同
- 设定用户登录成功或者注册成功后进入会员中心页面,则在login.html以及register.html模板文件中修改链接地址
<a href="{{url_for('home.user')}}" class="btn btn-lg btn-success btn-block">登录</a>
<a href="{{url_for('home.user')}}" class="btn btn-lg btn-success btn-block">注册</a>
- 测试会员中心页面显示以及登录注册后页面跳转显示
4.电影列表页以及搜索页面搭建
电影列表页
- 定义视图函数
# 列表
@home.route('/')
def index():
return render_template("home/index.html")
# 动画
@home.route('/animation/')
def animation():
return render_template("home/animation.html")
- 在templates/home目录下新建layout.html文件,将home.html内容复制到layout.html文件中,因为列表页面与其他页面不一样,需要单独使用一个父模板,修改layout.html中的数据块,去除div标签
{% block content%}{% endblock %}
- 编辑templates/home目录下的index.html文件,继承与layout.html,并将热门电影以及电影列表放在数据块中
- 将static/tpl目录下的animation.html文件拷贝到templates/home目录下,用于存放热门电影模块中的幻灯片动画,修改animation.html文件中的地址
- 修改home/index.html文件中动画地址
<iframe class="wow fadeIn" width="100%" height="375px" frameborder=0 scrolling=no src="{{url_for('home.animation')}}"></iframe>
- 测试显示主页
搜索页面
- 定义视图
@home.route('/search/')
def search():
return render_template("home/search.html")
- 将static/tpl/2-movie目录下的search.html文件拷贝到templates/home的目录下,并保留搜索内容块,其他地方继承home.html模板即可
- 测试显示搜索页面
5.电影播放页与404页面搭建
播放页面
- 定义视图函数
@home.route('/play/')
def play():
return render_template("home/play.html")
- 复制static/tpl/2-movie下的play.html文件到templates/home目录下,完成该页面的继承的数据块,并修改静态资源地址
- 在搜索页面(search.html)收藏电影页面(moviecol.html)以及主页(index.html)中将电影播放地址play.html全部修改为{{url_for('home.play')}},执行home下的play视图函数名
<!-- 搜索页面 -->
<a href="{{url_for('home.play')}}">
<img class="media-object" src="holder.js/131x83" alt="环太平洋">
</a>
<!-- 收藏电影页面 -->
<a href="{{url_for('home.play')}}">
<img class="media-object" src="holder.js/131x83" alt="环太平洋">
</a>
<!-- 主页面 -->
<a href="{{url_for('home.play')}}" class="btn btn-primary" target="_blank" role="button"><span class="glyphicon glyphicon-play"></span> 播放</a>
- 测试视频播放页面
404页面搭建
- 在app/__init__.py初始化文件中定义404错误机制视图函数
@app.errorhandler(404)
def page_not_found(error):
return render_template("home/404.html"), 404
- 复制static/tpl/4-404目录下的404.html文件到templates/home目录下,并修改模板中的静态资源路径
- 测试404页面