文章目录
- 使用技术:
- 模块
- 10.18
- 10.19
- 10.26
- 10.27
- 11.16
- 11.17
- 12.25
- 12.26
- 9-1上映预告-标签筛选-电影分页
- 9-2 电影搜索-电影详情
- 5-4 会员-收藏-评论管理页面搭建
- 6-8 修改密码
- 6-9 日志管理
- 1.1
- 遇到的问题
- 1. 当验证在Flask中失败时,如何覆盖html默认的“请填写此字段”?
- 2. ValueError: View function did not return a response
- 3. nginx 限制ip并发 及速率
由于自己目前还在实习上班中,只能周末抽空做毕设,之前用Python做过Flask框架的教务系统,有一些经验,所以偷懒选用Flask框架做了一个简单的视频网站,如果有时间的话可以弄一个推荐算法在里面,做一步算一步吧!
自己写点日志记录下项目过程吧!
具体详情放在自己搭的博客上面了: 传送门
使用技术:
Python MTV模型
Flask微内核
Flask扩展插件配置及使用方法
根据业务开发网站前后台功能
Flask结合MySQL数据库
你将可以独立开发网站 独立部署运维网站
werkzug工具箱
pymysql数据库驱动
sqlalchemy数据库orm
wtforms表单验证工具
jinjia2模板引擎
flask-script命令行脚本
functools定义高阶函数
jwplayer播放器插件
视频限速限IP访问
flv、mp4视频格式支持
Nginx点播实现
模块
前台
会员登录及注册 / 会员中心 / 电影播放
电影评论 / 电影收藏
后台
管理员登录 / 修改密码 / 标签管理
电影管理 / 上映预告管理 / 会员管理
评论管理 / 收藏管理 / 角色管理
权限管理 / 管理员管理 / 日志管理
10.18
熟悉整个项目的部署,流程,以及所用到的库
10.19
使用flask的SQLAlchemy,创建Mysql数据库表,并创建了启动项目所需要前台home,后台admin,蓝图等等
部分mysql表
蓝图的建立
10.26
建立home.html 整个网站的框架,逐渐添加各种功能
电影:index.html
- 由logout.html(负责电影首页类目类目)
- animation.html(热映电影+轮播图)
- 利用jinjia2的语法
{% for v in range(1,13) %}
构造电影信息列表
搜索:search.html 搜索页面
登录:login.html
注册:regist.html
退出:login.html
会员:user.html
-
基于home.html
-
menu.html为会员中心的类目 id="m-*"为各种功能的id,每种功能js执行代码如下:
<% block js %> <script>$(document).ready(function () {$("#m-4").addClass("active");}) </script> <% endblock %>
10.27
前端
404.html 报错页面
play.html 电影播放页面 有bug 无法弹出播放列表,待修复
后端
admin.html 后台整体界面
gird.html 后台类目
login.html 管理员登陆页面
因为工作忙,好久没写项目了,今天补一下
11.16
admin.html 主模板,其余继承主模板,添加主模板的功能
5-1 管理员登录-后台布局搭建
- 功能模块继承admin.gird.html 其各个功能需要添加id 定位,点击功能激活子功能
5-2 修改密码-控制面板-标签管理页面搭建
- pwd.html,index.html,tag.html-tag_add.html
5-3 电影管理-上映预告管理页面搭建
- movie_add.html,movie_add.html ,preview_list.html
5-4 会员-收藏-评论管理页面搭建
- user_list.html,movie_col.html,comment_list.html
5-5 收藏-日志-角色管理页面搭建
- role_add,role_list.html
5-6 管理员管理页面搭建 - admin_add.html,admin_list.html
11.17
6-1 管理员登陆
- 1.在model.py中添加check_pwd()函数,判断密码是否一致
- 2.在form.py中添加表单需要的信息、是否存在账户。在view.py视图中调用,判断登录状态,登录失败,返回错误信息。登录成功,建立session并返回index.html中
def login():"""后台登录"""form = LoginForm()if form.validate_on_submit(): #表单数据data = form.dataadmin = Admin.query.filter_by(name=data["account"]).first()#查找adminif not admin.check_pwd(data['pwd']):flash("密码错误", "err")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)
访问控制,登录装饰器
def admin_log_req(f):"""登录装饰器"""@wraps(f)def decorated_function(*args, **kwargs):if "admin" not in session:return redirect(url_for("admin.login", next=request.url))return f(*args, **kwargs)return decorated_function
6-2 标签的添加与编辑
- 添加标签、编辑
def tag_add():form = TagForm()print(form.name.errors)if form.validate_on_submit():data=form.datatag=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") #闪现消息redirect(url_for("admin.tag_add"))return render_template("admin/tag_add.html", form=form)
@admin.route("/tag/edit/<int:id>", methods=["GET", "POST"])
@admin_log_req
# @admin_auth
def tag_edit(id=None):"""标签编辑"""form = TagForm()form.submit.label.text = "修改"tag = Tag.query.get_or_404(id) #数据库依据id查找tagif form.validate_on_submit():data = form.datatag_count = Tag.query.filter_by(name=data["name"]).count()# 说明已经有这个标签了,此时向添加一个与其他标签重名的标签。if tag.name != data["name"] and tag_count == 1:flash("标签已存在", "err")return redirect(url_for("admin.tag_edit", id=tag.id))tag.name = data["name"]db.session.add(tag)db.session.commit()flash("标签修改成功", "ok")redirect(url_for("admin.tag_edit", id=tag.id))return render_template("admin/tag_edit.html", form=form, tag=tag)
- for循环接收form表单、闪现消息
{% 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 %}
6.3 标签列表的分页设置
#标签列表
@admin.route("/tag/list/<int:page>/", methods=["GET"])
@admin_log_req
def tag_list(page=None):if page is None:page=1page_data=Tag.query.order_by(Tag.addtime.desc() #按添加时间排序).paginate(page=page,per_page=10)return render_template("admin/tag_list.html",page_data=page_data)
{% 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 %}
<!-- data.prev_num 获取上一页页码--><li><a href="{{ url_for(url,page=data.prev_num) }}">上一页</a></li>{% else %}
<!-- 没有上一页--><li class="disabled"><a href="#">上一页</a></li>{% endif %}
<!-- iter_pages() 页码生成器-->{% 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 %}
12.25
6.5
- 完善预告页面的增删
- 在编辑与删除成功时,自动删除原预告
12.26
9-1上映预告-标签筛选-电影分页
跳过其他管理员后台功能的完善,先完善前台页面与视频播放的模块,早些学习新知识。
- 完善home.index页面的搭建(分页)
- home.animation 轮播图的建立(有问题)!!!!!
- 电影列表的建立,以及筛选条件的完善
@home.route("/<int:page>/", methods=["GET"])
def index(page=None):"""首页电影列表"""tags = Tag.query.all()page_data = Movie.query# 标签tid = request.args.get("tid", 0)if int(tid) != 0:page_data = page_data.filter_by(tag_id=int(tid))# 星级star = request.args.get("star", 0)if int(star) != 0:page_data = page_data.filter_by(star=int(star))# 时间time = request.args.get("time", 0)if int(time) != 0:if int(time) == 1:page_data = page_data.order_by(Movie.addtime.desc())else:page_data = page_data.order_by(Movie.addtime.asc())# 播放量pm = request.args.get("pm", 0)if int(pm) != 0:if int(pm) == 1:page_data = page_data.order_by(Movie.playnum.desc())else:page_data = page_data.order_by(Movie.playnum.asc())# 评论量cm = request.args.get("cm", 0)if int(cm) != 0:if int(cm) == 1:page_data = page_data.order_by(Movie.commentnum.desc())else:page_data = page_data.order_by(Movie.commentnum.asc())if page is None:page = 1page_data = page_data.paginate(page=page, per_page=8) ## 为筛选后的电影列表p = dict(tid=tid,star=star,time=time,pm=pm,cm=cm,)return render_template("home/index.html", tags=tags, p=p, page_data=page_data)
9-2 电影搜索-电影详情
@home.route("/search/<int:page>/")
def search(page=None):"""搜索"""if page is None:page = 1key = request.args.get("key", "") ## search 关键字movie_count = Movie.query.filter(Movie.title.ilike('%' + key + '%')).count()page_data = Movie.query.filter(Movie.title.ilike('%' + key + '%')).order_by(Movie.addtime.desc()).paginate(page=page, per_page=10)page_data.key = keyreturn render_template("home/search.html", movie_count=movie_count, key=key, page_data=page_data)
5-4 会员-收藏-评论管理页面搭建
@admin.route("/user/list/<int:page>/",methods=["GET", "POST"])
@admin_log_req
def user_list(page=None):"""会员列表"""if page is None:page = 1page_data = User.query.order_by(User.addtime.desc()).paginate(page=page, per_page=10)return render_template("admin/user_list.html", page_data=page_data)@admin.route("/user/view/<int:id>/",methods=["GET"])
@admin_log_req
def user_view(id=None):"""查看会员详情"""from_page = request.args.get('fp')if not from_page:from_page = 1user = User.query.get_or_404(int(id))return render_template("admin/user_view.html", user=user, from_page=from_page)@admin.route("/user/del/<int:id>/", methods=["GET"])
@admin_log_req
# @admin_auth
def user_del(id=None):"""删除会员"""# # # 因为删除当前页。假如是最后一页,这一页已经不见了。回不到。# from_page = int(request.args.get('fp')) - 1# # # 此处考虑全删完了,没法前挪的情况,0被视为false# if not from_page:# from_page = 1user = User.query.get_or_404(int(id))db.session.delete(user)db.session.commit()flash("删除会员成功!", "ok")return redirect(url_for('admin.user_list', page=1))
6-8 修改密码
@admin.route("/pwd/", methods=["GET", "POST"])
@admin_log_req
def pwd():"""后台密码修改"""form = PwdForm()if form.validate_on_submit():data = form.dataadmin = Admin.query.filter_by(name=session["admin"]).first()from werkzeug.security import generate_password_hashadmin.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)
在form表单中验证密码的错误
def validate_old_pwd(self, field):from flask import sessionpwd = field.dataname = session["admin"]admin = Admin.query.filter_by(name=name).first()if not admin.check_pwd(pwd):raise ValidationError("旧密码错误!")
6-9 日志管理
- 管理员操作日志
# 添加 管理员增加标签log
oplog = Oplog(admin_id=session["admin_id"],ip=request.remote_addr,reason="添加标签%s" % data["name"])db.session.add(oplog)db.session.commit()# 操作日志
@admin.route("/oplog/list/<int:page>", methods=["GET"])
@admin_log_req
def oplog_list(page=None):if page is None:page = 1page_data = Oplog.query.join(Admin).filter(Oplog.admin_id == Admin.id,).order_by(Oplog.addtime.desc()).paginate(page=page, per_page=10)return render_template("admin/oplog_list.html",page_data=page_data)
- 管理员登录日志
在管理员登陆时,插入登录日志
def login():"""后台登录"""form = LoginForm()if form.validate_on_submit(): # 表单数据data = form.dataadmin = Admin.query.filter_by(name=data["account"]).first() # 查找adminif not admin.check_pwd(data['pwd']):flash("密码错误", "err")return redirect(url_for("admin.login"))session['admin'] = data['account']session["admin_id"] = admin.id #增加管理员id,用于管理员操作日志# 管理员登陆日志adminlog = Adminlog(admin_id=admin.id,ip=request.remote_addr, #获取ip)db.session.add(adminlog)db.session.commit()return redirect(request.args.get("next") or url_for("admin.index"))return render_template("admin/login.html", form=form)
1.1
完善前后端的优化工作,并部署到服务器
遇到的问题
1. 当验证在Flask中失败时,如何覆盖html默认的“请填写此字段”?
你应该让浏览器来处理这个问题,这些消息是标准的,并根据用户计算机的区域设置进行调整。有一个JavaScriptAPI来控制这些消息( ,尽管WTForms没有提供与它的任何集成(但是,扩展是一个好主意)。
-
如果你真的想要禁用这个,你可以通过required=False同时渲染一个字段。
{{ form.name(required=False) }}
-
你可以通过重写整个窗体来禁用它。
class NoRequiredForm(Form):class Meta:def render_field(self, field, render_kw):render_kw.setdefault('required', False)return super().render_field(field, render_kw)
-
你可以通过从禁用该窗体的基窗体继承它来禁用多个窗体。
class UserForm(NoRequiredForm):
…
-
还可以通过设置novalidate属性在HTML上。
<form novalidate></form>
2. ValueError: View function did not return a response
添加关键字return,视图无返回值
3. nginx 限制ip并发 及速率
https://blog.csdn.net/weixin_43746433/article/details/103897789