期末作品检查
本学期通过在老师的带领下,学习了管理信息系统这门课,学会了使用Python+Flask+MysqL的web建设技术,在学习的过程中发现了学习每一知识点都是要先了解其概念以及基础,才会知道如何进行实际操作。以下是我这学期的学习的知识归纳总结。
1.制作网页的时候,首先要了解URL、WEB浏览的过程以及观察网页,然后了解HTML基础、HTML标签以及HTML网页结构,还要了解各个标签的属性以及学会使用其用法来制作页面。使用<nav></nav>为网页制作一个导航条。了解HTML头部元素,其中<base> 定义了页面链接标签的默认链接地址,<style> 定义了HTML文档的样式文件,<link> 定义了一个文档和外部资源之间的关系。可以使用以下样式:行内样式表、内嵌样式表、外部样式表,还可以定义一下三类选择器:HTML 选择器、CLASS 类选择器以及ID 选择器。
<nav> <div class="container"> <img id="images" src="{{ url_for('static',filename='images/3.gif') }}" alt="fl" width="50"> <a class="one" href="{{url_for('shouye')}}">首页 </a> <a class="one" href="{{url_for('question')}}">发布问题 </a> <form method="get" action="{{ url_for('search') }}"> <div style="position: absolute;top: 24px;left:20%;"> <input id="keyword" type="text" name="q" placeholder="请输入关键字"> <button type="submit" id="search">搜索</button> </div> </form> {% if username %} {# <a class="login" href="">{{ username }}</a>#} <a class="login" href="{{ url_for('usercenter',user_id=session.get('userid'),tag='1') }}">{{ session.get('user') }}</a> <a class="register" href="{{url_for('logout')}}">注销</a> {% else %} <a class="login" href="{{url_for('login')}}">登录</a> <a class="register" href="{{url_for('register')}}">注册</a> {% endif %} <img id="on_off" onclick="mySwitch()" src="{{ url_for('static',filename='images/bulbon.gif')}}"> </div> </nav>

2.当制作出了导航条之后,则需要实现样式的设置,这就需要用到CSS选择器的运用。首先要认识CSS的 盒子模型。然后了解CSS选择器的灵活使用。CSS可以通过三种方式实现:(1)图片文字用div等元素布局形成HTML文件;(2)新建相应CSS文件,CSS文件中定义样式并用<link>链接到html中;(3)在HTML中的<head>中使用<style>进行布局美化。
3.要了解JS基础。同CSS一样,JS也可以通过以下三种方式来实现:(1)<script></script>放在html文件的<body>中;(2)放在html文件的<head>中使用<script></script>;(3)新建相应外部JS文件,外部JS文件中定义样式并用<link>链接到html中。js具有以下三种输出数据的方式:第一:使用 document.write() 方法将内容写到 HTML 文档中。第二:使用 window.alert() 弹出警告框。第三:使用 innerHTML 写入到 HTML 元素,其可以使用 "id" 属性来标识 HTML 元素。使用 document.getElementById(id) 方法访问 HTML 元素,用innerHTML 来获取或插入元素内容。
4.完成登录页面和注册页面的前端工作:通过JS语句增加错误提示框,并实现写好HTML+CSS文件,设置每个输入元素的id。定义JavaScript 函数,设置登录注册页面验证用户名与登录密码6-20位,注册还需包括验证用户名首字母不能是数字,只能包含字母和数字,输入的两次密码必须一致,并在各自html页面的button标签onclick调用这个函数。
function myLogin() { var oUname = document.getElementById("uname"); var oPass = document.getElementById("upass"); var oError = document.getElementById("error_box"); oError.innerHTML = "<br>"; if (oUname.value.length < 6 || oUname.value.length > 20) { oError.innerHTML = "用户名为6-20位。"; return false; } else if((oUname.value.charCodeAt(0)>=48)&&(oUname.value.charCodeAt(0)<=57)){ oError.innerHTML="首位不能是数字"; 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)){ oError.innerHTML="用户名只能包括字母和数字"; return false; } } if (oPass.value.length < 6 || oPass.value.length > 20) { oError.innerHTML = "密码为6-20位。"; return false; } return true; // window.alert("登录成功!");
function check() { var oUname = document.getElementById("uname"); var oPass = document.getElementById("upass"); var onumber = document.getElementById("unumber"); var ooPass = document.getElementById("uupass"); var oError = document.getElementById("error_box"); oError.innerHTML = "<br>"; if (oUname.value.length < 6 || oUname.value.length > 20) { oError.innerHTML = "用户名为6-20位。"; return false; } else if((oUname.value.charCodeAt(0)>=48)&&(oUname.value.charCodeAt(0)<=57)){ oError.innerHTML="用户名首位不能为数字"; 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)) { oError.innerHTML = "用户名只能包括字母和数字"; return false; } } } if (oPass.value.length < 6 || ooPass.value.length > 20) { oError.innerHTML = "密码为6-20位。"; return false; } if (oPass.value != uupass.value) { alert('两次输入密码不一致'); return false; } return true; // window.alert("注册成功!"); }
5.普遍的网页都会有夜间模式和日间模式,以及父模板。夜间模式的开启与关闭:先在父模板放置点击的图片,然后在<script></script>中定义开关切换函数,再用onclick函数调用。父模板的制作:制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明;汇总相关的样式形成独立的css文件。汇总相关的js代码形成独立的js文件;形成完整的base.html+css+js。
function mySwitch() { var myele=document.getElementById("on_off"); if(myele.src.match("bulbon")){ myele.src="../static/images/bulboff.gif"; document.getElementById("myBody").style.background="black"; document.getElementById("myBody").style.color="white"; } else{ myele.src="../static/images/bulbon.gif"; document.getElementById("myBody").style.background="white"; document.getElementById("myBody").style.backgroundImage="url(../static/images/shouye.gif)"; document.getElementById("myBody").style.color="black"; } }


6.完成页面的设计之后,开始新建Flask项目,设置调试模式,理解Flask项目主程序,使用装饰器,设置路径与函数之间的关系,使用Flask中render_template,用不同的路径,返回首页、登录页、注册页,用视图函数反转得到URL,{{url_for(‘login’)}},完成导航条里的链接。
@app.route('/') def base(): return render_template('base.html') @app.route('/login/') def login(): return render_template('login.html') @app.route('/register/') def register(): return render_template('register.html') if __name__ == '__main__': app.run()
7.加载静态文件,父模板的继承和扩展,用url_for加载静态文件<script src="{{ url_for('static',filename='js/login.js') }}"></script>,flask 从static文件夹开始寻找可用于加载css, js, image文件。实现继承和扩展,把一些公共的代码放在父模板中,避免每个模板写同样的内容。子模板继承父模板 ,父模板提前定义好子模板可以实现一些自己需求的位置及名称。子模板中写代码实现自己的需求。
8.数据库配置信息config.py,建立mysql和app的连接创建用户模型。通过用户模型,对数据进行增删改查操作。
import os DEBUG=True SECRET_KEY=os.urandom(24) SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:@127.0.0.1:3306/mis_db?charset=utf8' SQLALCHEMY_TRACK_MODIFICATIONS=False SECRET_KEY=os.urandom(24)
9.完成注册功能,js文件: onclick函数return True时才提交表单,return False时不提交表单。在主py文件中获取form中的数据,判断用户名是否存在:存在报错,不存在就存到数据库中,redirect重定向到登录页。
@app.route('/register/',methods=['GET','POST']) def register(): if request.method=='GET': return render_template('register.html') else: usern=request.form.get('username') nickn = request.form.get('nickname') passw = request.form.get('password') user=User.query.filter(User.username==usern).first() if user: return '用户名已存在。' else: user1=User(username=usern,password=passw,nickname=nickn) db.session.add(user1) db.session.commit() return redirect(url_for('login'))#重定回向登录页面

10.完成登录功能:与注册一样完成js文件,在主py文件定义函数,读取表单数据查询数据库,用户名密码对就用session记住用户名并跳转到首页;用户名密码不对则提示相应错误。
@app.route('/login/',methods=['GET','POST']) def login(): if request.method == 'GET': return render_template('login.html') else: usern = request.form.get('username') passw = request.form.get('password') user = User.query.filter(User.username == usern).first() if user: if user.check_password(passw): session['user']=usern session['userid'] = user.id session.permanent=True return redirect(url_for('shouye')) else: return '密码错误。' else: return '用户名不存在。'

11.实现登录之后更新导航:用上下文处理器app_context_processor定义函数,获取session中保存的值,返回字典。在父模板中更新导航,插入登录状态判断代码。注意用{% ... %}表示指令、{{ }}表示变量。完成注销功能:清除session并进行跳转页面
@app.context_processor def mycontext(): usern=session.get('user') if usern: return {'username':usern} else: return {} @app.route('/logout/') def logout(): session.clear() return redirect(url_for('shouye'))
{% if username %} {# <a class="login" href="">{{ username }}</a>#} <a class="login" href="{{ url_for('usercenter',user_id=session.get('userid'),tag='1') }}">{{ session.get('user') }}</a> <a class="register" href="{{url_for('logout')}}">注销</a> {% else %} <a class="login" href="{{url_for('login')}}">登录</a> <a class="register" href="{{url_for('register')}}">注册</a> {% endif %}

12.实现发布功能,编写要求登录的装饰器,定义个函数将其返回,应用装饰器,要求在发布前进行登录,没登录则返回登录页面,登录后才可使用发布功能。建立发布内容的对象关系映射。完成发布函数。把发布的内容保存到数据库。重定向到首页。
@app.route('/question/',methods=['GET','POST']) @loginFirst def question(): if request.method == 'GET': return render_template('question.html') else: title = request.form.get('title') detail = request.form.get('detail') user =User.query.filter(User.username==session.get('user')).first() author_id=user.id question=Question(title=title,detail=detail,author_id=author_id) question.anthor=user db.session.add(question) db.session.commit() return redirect(url_for('shouye'))
def loginFirst(func): @wraps(func) def wrapper(*args,**kwargs): if session.get('user'): return func(*args,**kwargs) else: return redirect(url_for('login')) return wrapper

13.做首页显示问题的列表:在首页添加显示问答的无序列表,并定义好相应的CSS样式;用字典将数据库查询结果传递到前端页面,前端页面循环显示整个列表,进行问答排序。
<div class="content"> <p class="biaoti">发布的内容</p> <ul class="list-group"> {% for foo in question %} <li class="list-group-item"> <span class="glyphicon-leaf" aria-hidden="true"></span> <img id="qu" src="{{ url_for('static',filename='images/title.png')}}"> <a href = "{{url_for('detail',question_id=foo.id)}}">{{ foo.title }}</a> <p class="detail">{{ foo.detail }}</p> <img id="qu" src="{{ url_for('static',filename='images/question.jpg')}}"> <a href = "{{ url_for('usercenter',user_id=foo.author_id,tag=1) }}">{{ foo.author.username }}</a> <br> <span class="badge" style="float: right;background-color: burlywood;border-radius: 5px">{{ foo.create_time }}</span> </li> {% endfor %}

14.完成问答详情页布局:包含问答的全部信息,评论区,以往评论列表显示区,在首页点击问答标题,链接到相应详情页:主PY文件写视图函数,带id参数。 首页标题的标签做带参数的链接。在详情页将数据的显示在恰当的位置。
@app.route('/detail/<question_id>',methods=['GET','POST']) def detail(question_id): quest=Question.query.filter(Question.id==question_id).first() return render_template('detail.html',ques=quest)

15.完成评论功能:尝试实现发布评论。读取前端页面数据,保存到数据库中,用<input type="hidden" 方法获取前端的"question_id" ,显示评论次数,调用登录装饰器,要求评论前登录,尝试实现详情页面下的评论列表显示。
<div class="content"> <h3>标题:{{ ques.title }}<br><br><small>作者:{{ ques.author.username }} <br> <span class="badge">发布时间:{{ ques.create_time }}</span> </small></h3> <hr> <p class="lead"><span style="color: maroon" >内容:</span>{{ ques.detail }}</p> <hr> <form action="{{ url_for('comment') }}" method="post"> <textarea class="comment" rows="8" placeholder="写下你的评论:" name="new_comment"></textarea> <input name="question_id" type="hidden" value="{{ ques.id }}" /> <button class="button" >发布 </button> </form> <span class="tcomment">评论:({{ ques.comments|length }})</span> <ul class="list-group"> {% for foo in ques.comments %} <li class="list-group-item"> <span class="glyphicon-leaf" aria-hidden="true"></span> <img id="qu" src="{{ url_for('static',filename='images/question.jpg')}}"><a href = "{{ url_for('usercenter',user_id=foo.author_id,tag=1) }}">{{ foo.author.username }}</a> <span class="badge">评论时间:{{ foo.create_time }}</span> <p style="text-align: left">{{ foo.detail }}</p> </li> {% endfor %} </ul> </div>
@app.route('/comment/',methods=['POST']) @loginFirst def comment(): 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 comm=Comment(author_id=auth_id,question_id=ques_id,detail=comment) db.session.add(comm) db.session.commit() return redirect(url_for('detail',question_id=ques_id))

16.实现评论列表显示及排序。显示所有评论;所有评论排序;显示评论条数;完成个人中心:个人中心的页面布局(html文件及相应的样式文件),定义视图函数def usercenter(user_id)向前端页面传递参数,页面显示相应数据:发布的全部问答、发布的全部评论、个人信息;各个页面链接到个人中心。
17.实现标签页导航:利用嵌套继承,制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。个人中心—视图函数、导航标签与HTML页面链接增加tag参数。
18.个人中心标签也导航:新页面userbase.html,用<ul ><li role="presentation"> 实现标签页导航。让userbase.html继承base.html。重写title,head,main块,将上述<ul>的样式放在head块,<ul>放在main块中,定义新的块user。个人中心页面,继承userbase.html,原个人中心就自动有了标签页导航。制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。
@app.route('/usercenter/<user_id>/<tag>') @loginFirst def usercenter(user_id,tag): user = User.query.filter(User.id == user_id).first() context={ 'user':user } if tag=='1': return render_template('user1.html', **context) elif tag == '2': return render_template('user2.html', **context) else: return render_template('user3.html', **context)
<ul class="nav-header"> <li role="presentation"><a class="nav" href="{{ url_for('usercenter',user_id=user.id,tag='1') }}">全部问答</a></li> <li role="presentation"><a class="nav" href="{{ url_for('usercenter',user_id=user.id,tag='2') }}">全部评论</a></li> <li role="presentation"><a class="nav" href="{{ url_for('usercenter',user_id=user.id,tag='3') }}">个人信息</a></li> </ul>

19.实现搜索功能:准备视图函数search(),修改父模 中搜索输入框所在的;完成视图函数获取搜索关键字,条件查询并加载查询结果,实现组合条件查询。
@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('create_time') return render_template('shouye.html', question=ques)
<form method="get" action="{{ url_for('search') }}"> <div style="position: absolute;top: 24px;left:20%;"> <input id="keyword" type="text" name="q" placeholder="请输入关键字"> <button type="submit" id="search">搜索</button> </div> </form>

20.实现密码保护功能:更新User对象,设置对内的_password,编写对外的password,实现密码验证和登录验证
@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

21.实现此网页的所有的static文件、templates文件与py文件。

22.数据库连接,数据库工具:Navicat for MySQL



以上是本学期学习的知识总结,使用Python的Flask框架+MysqL完成简单的网页。
浙公网安备 33010602011771号