期末作品检查
- 个人学期总结
- 总结Python+Flask+MysqL的web建设技术过程,标准如下:
- 即是对自己所学知识的梳理
- 也可作为初学入门者的简单教程
- 也可作为自己以后复习的向导
- 也是一种向外展示能力的途径
父模板的制作
- 制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明等。
父模版导航栏
<nav class="navbar navbar-expand-lg bg-light "> <a class="navbar-brand" href="#"></a> <div class="collapse navbar-collapse " id="navbarNav"> <ul class="nav navbar-nav navbar-right"> <li class="nav-item "> <a class="nav-link " href="{{ url_for("shouye")}}">首页 <span class="sr-only">(current)</span></a> </li> <li class="nav-item "> <a class="nav-link disabled " href="#">动画</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="#">音乐</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="">游戏</a> </li> </ul> <form class="form-inline" action="{{ url_for("search") }}" method="get"> <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="q"> <button class="btn btn-secondary" type="submit">搜索</button> </form> </div> <div style="float: right;width: 10%"> {% if username%} <a class="navbar-link disabled"href="">{{ username }}</a> <a class="navbar-link disabled" href="{{ url_for("logout") }}">注销</a> {% else %} <a class="navbar-link disabled"href="{{ url_for("denglu") }}">登陆</a> <a class="navbar-link disabled" href="{{ url_for("zhuce") }}">注册</a> {% endif %} </div> </nav>
2首页、登录页、注册页
登录页:denglu.html 继承父模版 text.html
{% extends "text.html" %}
{% block denglu %}{% endblock %}
<form id="b" method="post" action="{{ url_for('denglu') }}"> <div class="container-fluid " id="denglu"> <div class="mt-5 pt-5" > <div class="card border-primary mb-3 m-auto" style="max-width: 20rem;"> <div class="card-header text-center">wgd</div> <div class="card-body text-primary"> <h4 class="card-title">用户登录</h4> <div class="input-group mb-2 mr-sm-2 mb-sm-0"> <div class="input-group-addon"><i class="fa fa-user"></i></div> <input type="text" class="form-control" placeholder="Username" id="uname" required="true" name="username"> </div> <p id="errorbox1" class="m-0 p-0 text-danger">  </p> <div class="input-group mb-2 mr-sm-2 mb-sm-0"> <div class="input-group-addon"><i class="fa fa-lock"></i></div> <input type="password" class="form-control" placeholder="Password" id="upass" name="password"> </div> <p id="errorbox2" class="m-0 p-0 text-danger">  </p> <div class="row"> <div class="col-3"> <button class="btn btn-outline-primary" onclick=" MyLogin()" >登录</button> </div>
JS文件Mylogin.jsp中的 Mylogin()函数对登录行为进行检验。
function MyLogin() { var oUname=document.getElementById("uname"); var oUpass=document.getElementById("upass"); var oError1=document.getElementById("errorbox1"); var oError2=document.getElementById("errorbox2"); oError1.innerHTML="<br>"; oError2.innerHTML="<br>"; if(oUname.value.length<6 ||oUname.value.length>20){ oError1.innerHTML='Usename必须属于6-20位'; return false; }else if((oUname.value.charCodeAt(0)>=48)&&(oUname.value.charCodeAt(0)<=57)){ oError1.innerHTML='Useman不得以数字开头'; return false; }else for(var i=0;i<oUname.value.length;i++){ if((oUname.value.charCodeAt(i)<48||oUname.value.charCodeAt(i)>57)&&(oUname.value.charCodeAt(i)<97||oUname.value.charCodeAt(i)>122)){ oError1.innerHTML='用户名必须由数字或字母组成' return false; } } if(oUpass.value.length<6||oUpass.value.length>20) { oError2.innerHTML = "Password必须属于6-20位"; return false; }else { oError2.innerHTML=" " return true; } }
后台 denglu()函数控制登录。
@app.route('/denglu',methods=['GET','POST']) def denglu(): if request.method == 'GET': return render_template('denglu.html') else: username = request.form.get('username') password = request.form.get('password') user=User.query.filter(User.username == username).first() if user: if user.check_password(password): session['user'] = username session['id'] = user.id session.permanent = True return redirect(url_for('shouye')) else: return 'password error' else: return 'username is not existed'
注册功能 zhuce.html
<form id='a' action="{{ url_for("zhuce") }}" method="post"> <div class="container-fluid"> <div class="mt-5 pt-5"> <div class="card border-primary mb-3 m-auto" style="max-width: 20rem;"> <div class="card-header text-center">wgd</div> <div class="card-body text-primary"> <h4 class="card-title" align="center">注册</h4> <div class="input-group mb-2 mr-sm-2 mb-sm-0"> <div class="input-group-addon"><i class="fa fa-user"></i></div> <input type="text" class="form-control" placeholder="Username" id="uname" required name="username"> </div> <p id="errorbox1" class="m-0 p-0 text-danger">  </p> <div class="input-group mb-2 mr-sm-2 mb-sm-0"> <div class="input-group-addon"><i class="fa fa-lock"></i></div> <input type="text" class="form-control" placeholder="nickname" id="nickname" required name="nickname"> </div> <br> <div class="input-group mb-2 mr-sm-2 mb-sm-0"> <div class="input-group-addon"><i class="fa fa-lock"></i></div> <input type="password" class="form-control" placeholder="Password" id="upass" required name="password"> </div> <p id="errorbox2" class="m-0 p-0 text-danger">  </p> <div class="input-group mb-2 mr-sm-2 mb-sm-0"> <div class="input-group-addon"><i class="fa fa-lock"></i></div> <input type="password" class="form-control" placeholder="Password_check" id="upass_check" required onblur="check()"/> </div> <span id="warning"> </span> <div class="row"> <div class="col-3"> <button class="btn btn-outline-primary" onclick= "MyLogin()">注册</button> </div>
JS文件Mylogin.jsp中的 check()函数对登录行为进行检验。
function check(){ var password1=document.getElementById("upass").value; var password2=document.getElementById("upass_check").value; if(password1!==password2) { document.getElementById("warning").innerHTML=" 两次密码的输入不一致"; return ; } document.getElementById('a').submit(); }
后台 denglu()函数控制登录。
@app.route('/zhuce',methods=['GET','POST']) def zhuce(): if request.method == 'GET': return render_template('zhuce.html') else: username = request.form.get('username') password = request.form.get('password') nickname = request.form.get('nickname') user1 = User.query.filter(User.username == username).first() if user1: return 'username existed' else: user1 = User(username=username, password=password, nickname=nickname) db.session.add(user1) db.session.commit() return redirect(url_for('denglu'))
控制内容发布页 函数:def fankui(): 发布的内容存储在数据库wgd的表question 中
@app.route('/neirong',methods=['GET','POST']) @log def fankui(): if request.method=='GET': return render_template('fankui.html') else: title=request.form.get('title') detail=request.form.get('detail') author_id=User.query.filter(User.username==session.get('user')).first().id question=Question(title=title,detail=detail,author_id=author_id) db.session.add(question) db.session.commit() return redirect(url_for('shouye'))
验证只有登录状态才能进行内容的发布 def log(func)
def log(func): @wraps(func) def wrapper(*args,**kwargs): if session.get('user'): return func(*args,**kwargs) else: return render_template('denglu.html') return wrapper
内容发布后显示在首页 def shouye():
@app.route('/') def shouye(): context={ 'question':Question.query.all() } return render_template('shouye.html',**context)
for循环遍历数据库wgd中question表中的每一条内容。
{% for foo in question %} <div class="card w-57"></div> <li class="list-group-item rounded m-1" style="height: 10ch"> <span> <a href="{{ url_for("pre",user_id=foo.author.id,tag='1') }}">{{ foo.author.username }}</a> <span class="">{{ foo.creat_time }}</span><br> <a href="{{ url_for("pinglun",question_id=foo.id) }}">{{ foo.title }}</a> <p>{{ foo.detail }}</p> </span> </li>{% endfor %}
点击文章标题进入内容页进行评论。
@app.route('/commemt/',methods=['GET','POST'])
@log
def comment():
if request.method=='GET':
return render_template(url_for('pinglun'))
else:
comment=request.form.get('new_comment')
ques_id=request.form.get('question_id')
auth_id=User.query.filter(User.username == session.get('user')).first().id
comment=Comment(author_id=auth_id,question_id=ques_id,detail=comment)
db.session.add(comment)
db.session.commit()
return redirect(url_for('pinglun',question_id=ques_id))
@app.route('/pinglun<question_id>')
def pinglun(question_id):
quest = Question.query.filter(Question.id==question_id).first()
return render_template('pinglun.html',ques=quest)
通过
{{ ques.author.username }}
{{ ques.detail }}
等语句调用数据库user 和comment表的用户信息 和发布的内容
<div class="card" style="width: 65rem;margin-top:2% ; margin-left: 23%;"> <div style= > <h2 class="card-header" style="margin-bottom: 0" >{{ ques.title }}</h2> </div> <div class="card-body"style="padding-bottom: 1%"> <h4 class="card-title"><a href="{{ url_for('pre',user_id=ques.id,tag='1') }}"> {{ ques.author.username }} </a><small> {{ ques.creat_time }}</small></h4> <hr> <h5>{{ ques.detail }}</h5> <hr> <form action="{{ url_for('comment') }}" method="post"> <div style="width: 50rem;margin-left:6%;margin-top: 3%"> <textarea name="new_comment" class="form-control" rows="10" placeholder="请写下评论" ></textarea><br> <input name="question_id" type="hidden" value="{{ ques.id }}"/> <button type="submit" class="btn btn-outline-primary ">提交评论</button> </div> </form> </div>
发表评论 通过循环语句遍历出每一条存储与数据库库中的评论。
<h5 style="margin-left: 3.5%">评论:<p>内容篇幅:{{ ques.detail|length }}</p></h5> <div class="" style="width:58rem;margin-left: 4%;height: auto;margin-top: 0.5% "> {% for com in ques.comment %} <a href="#" >{{ com.author.username }}</a> <small>{{ com.creat_time }}</small> <p class="">{{ com.detail }}</p> {% endfor %} </div>
点击 用户名可以进入当点登录的用户的个人信息页。
userbase.html继承父模板并作为个人信息页面的父模板。 写入个人信息页的导航栏。
<div align="center"> <ol style="font-size: large;list-style-type: none;" > <li role="presentation" class="breadcrumb-item " aria-current="page"><a href="{{ url_for('pre',user_id=user.id,tag='1') }}"> 全部问答</a></li> <li role="presentation" class="breadcrumb-item active" aria-current="page"><a href="{{ url_for('pre',user_id=user.id,tag='2') }}">全部评论</a></li> <li role="presentation" class="breadcrumb-item active" aria-current="page"><a href="{{ url_for('pre',user_id=user.id,tag='3') }}">个人资料</a></li> </ol></div><br>
@app.route('/presonal_message/<user_id>/<tag>') @log def pre(user_id,tag): user=User.query.filter(User.id==user_id).first() context={ 'user':user } if tag =='1': return render_template('usercenter1.html',**context) elif tag=='2': return render_template('usercenter2.html',**context) else: return render_template('usercenter3.html',**context)
usercenter1.html usercenter2.html usercenter3.html 继承userbase.html
usercenter1.html
<body background="/static/img/WeChat%20Image_20171027161942.png" style="background-attachment: fixed;background-size: 100% 100%"> <div style="margin-left: 28%;margin-top: 1.5%"> <div class="card" style="width: 60rem;height:auto"> <div class="card-header"> <h2><a href="{{ url_for('pre',user_id=user.id,tag='1') }}"> {{ user.username }}</a></h2> </div> <div class="card-body"> <ul style="font-size: large;list-style-type: none;"> <p class="text-info"style="font-size: 30px">所有问答</p> {% for foo in user.question %} <div> <li> <a href="{{ url_for('pre',user_id=user.id,tag='3') }}">{{ foo.author.username }}</a> <span class="">{{ foo.creat_time }}</span><br> <a href="{{ url_for("pinglun",question_id=foo.id) }}">{{ foo.title }}</a> <p>{{ foo.detail }}</p> </li></div>
usercenter2.html
{% block usercenter %} <div style="margin-left: 28%;margin-top: 1.5%"> <div class="card" style="width: 60rem;height:auto"> <div class="card-header"> <h2><a href="{{ url_for('pre',user_id=user.id,tag='1') }}"> {{ user.username }}</a></h2> </div> <div class="card text-left" style="width: 60rem;height: auto"> <div class="card-body"> <ul style="font-size: large;list-style-type: none"> <p class="text-info"style="font-size: 30px">所有评论</p> {% for foo in user.comment %} <li> <a href="#">{{ foo.author.username }}</a> <span>{{ foo.creat_time }}</span><br> <p>{{ foo.detail }}</p> </li> {% endfor %}
usercenter3.html
<div style="margin-left: 28%;margin-top: 1.5%"> <div class="card" style="width: 60rem;height:auto"> <div class="card-header"> <h2><a href="{{ url_for('pre',user_id=user.id,tag='1') }}"> {{ user.username }}</a></h2> </div> <div class="card text-left" style="width: 60rem;height: auto"> <div class="card-body"> <ul style="font-size: large;list-style-type: none"> <p class="text-info"style="font-size: 30px">个人信息</p> <li><p>用户名:{{ user.username }}</p></li> <li><p>Id:{{ user.id }}</p></li> <li><p>内容篇幅:{{ user.question|length }}</p></li> </ul> </div>
<a href="{{ url_for('pre',user_id=user.id,tag='1') }}"> {{ user.username }}</a>
让用户名变成链接,点击用户名跳转到个人中心。
导航栏上的用户名先
if user.check_password(password): session['user'] = username session['id'] = user.id session.permanent = True return redirect(url_for('shouye'))
session获取'id'属性赋值给user.id
父模板调用
href="{{ url_for('pre',user_id=session.get('id'),tag='1') }} 实现链接到个人中心。
实现登录 注册和用户名 注销的变换。
{% if username%} <a class="navbar-link disabled"href="{{ url_for('pre',user_id=session.get('id'),tag='1') }}">{{ username }}</a> <a class="navbar-link disabled" href="{{ url_for("logout") }}">注销</a> {% else %} <a class="navbar-link disabled"href="{{ url_for("denglu") }}">登陆</a> <a class="navbar-link disabled" href="{{ url_for("zhuce") }}">注册</a> {% endif %}
搜索功能。
无搜索条件时:显示所有问答内容
输入搜索条件(模糊查询) 问答标题(如:你好),筛选出相关问答
搜索框的的name设置为'q'
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="q">
request请求'q'获取属性获取搜索的内容
进行条件查询
Question.(数据库属性名).contains(qu)
@app.route('/search/') def search(): qu=request.args.get('q') ques=Question.query.filter( or_( Question.title.contains(qu), Question.detail.contains(qu) ) ).order_by('creat_time') return render_template('shouye.html',question=ques)
提高数据库存储的密码的安全性。
1.更新User对象,设置对内的_password
_password = db.Column(db.String(200), nullable=False)
2.编写对外的password
3.密码验证的方法:
@property def password(self): return self._password @password.setter def password(self,row_password): self._password=generate_password_hash(row_password) def check_password(self,row_password): result =check_password_hash(self._password,row_password) return result
4.登录验证:
@app.route('/denglu',methods=['GET','POST']) def denglu(): if request.method == 'GET': return render_template('denglu.html') else: username = request.form.get('username') password = request.form.get('password') user=User.query.filter(User.username == username).first() if user: if user.check_password(password): session['user'] = username session['id'] = user.id session.permanent = True return redirect(url_for('shouye')) else: return 'password error' else: return 'username is not existed'
个人心得:
经过一学期的Python+flask+html的学习,对于开发一个Flask项目有了初步的接触和初步的了解,学习注册、登录、发布内容的相关知识。
但在这个粗糙的项目中还有很多很多的不足,功能上缺少文件上传,修改功能等一系列的基本功能,需要继续加工。