一、个人学期总结
在本学期中我学习了管理信息系统这门课程,并实现了基于Python的Flask框架web建设项目,Python,是一种面向对象的解释型计算机程序语言。学期初始,我们学习了Python的基础语法,输入、输出、交互、数字计算的方法、字符串基本操作、凯撒密码、自制九九乘法表、中英文词频统计等,还学习了import turtle库,并利用这个库绘制出多种多样的图形,提升了我们对编程语言的思维能力,为构建Flask框架制作网页的学习打下基础。期中之后,我们更加深入学习这门课程,了解代码原理,开始网页的制作,然后开始使用标签制作HTML页面内容,以及美化网页,添加网页其他功能等。
这一个学期项目建设的学习使我受益匪浅,在老师的悉心教导下,不仅让我全面的、系统的学会了页设计与制作的基础知识,还让我学会了自己动手去制作属于自己的网页,由于本人的技术还不是很成熟,还存在很多的不足地方,在今后的课余时间,我会继续认真学习网页制作的更多知识以实现自身技能的提高。
二、总结Python+Flask+MysqL的web建设技术过程
首先,利用PyCharm创建一个Flask之后,我们就开始创建python文件,首先一个以网页展示作为前端的管理信息系统需要做到前端与后端Mysql数据库之间的交互,则肯定需要进行连接数据库的操作,此时我们创建了名为config的数据库连接配置的py文件实现与Mysql数据库之间的连接。
1、第三方库导入
from flask import Flask,render_template,request,redirect,url_for,session from flask_sqlalchemy import SQLAlchemy from datetime import datetime from functools import wraps from sqlalchemy import or_ from werkzeug.security import generate_password_hash,check_password_hash
import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app)
2、config的重要代码为:
SQLALCHEMY_DATABASE_URI = ‘mysql+pymysql://root:@127.0.0.1:3306/mis_db?charset=utf8‘ SQLALCHEMY_TRACK_MODIFICATIONS = False
3、在实现与数据库之间的连接之后,我们创建py文件开始创建数据表
(1)user表里存放用户的id,用户名跟密码。
(2)question表里存放用户的id、title(标题)、detail(详情)、create_time(创建时间)、author_id(文章作者的用户id)。
(3)comment表里存放id、author_id(评论用户的id)、question_id(文章的id)、create_time(创建时间)和detail(详情)。
class User(db.Model): __tablename__ = ‘user‘ id = db.Column(db.Integer,primary_key=True,autoincrement=True) username = db.Column(db.String(20),nullable=False) _password = db.Column(db.String(200), nullable=False)#内部使用 @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 class Question(db.Model): __tablename__=‘question‘ id = db.Column(db.Integer, primary_key=True, autoincrement=True) title =db.Column(db.String(100), nullable=False) detail = db.Column(db.Text, nullable=False) creat_time=db.Column(db.DateTime,default=datetime.now) author_id = db.Column(db.Integer,db.ForeignKey(‘user.id‘)) author=db.relationship(‘User‘,backref=db.backref(‘question‘)) class Comment(db.Model): __tablename__ = ‘comment‘ id = db.Column(db.Integer, primary_key=True, autoincrement=True) author_id = db.Column(db.Integer, db.ForeignKey(‘user.id‘)) question_id = db.Column(db.Integer, db.ForeignKey(‘question.id‘)) detail = db.Column(db.Text, nullable=False) create_time = db.Column(db.DateTime, default=datetime.now) question = db.relationship(‘Question‘, backref=db.backref(‘comments‘,order_by=create_time.desc)) author = db.relationship(‘User‘, backref=db.backref(‘comments‘))
user表
question表
comment表
具体建设过程如下:
一、导航,头部,CSS基础
1、制作自己的导航条。
2、HTML头部元素:
(1)<base> 定义了页面链接标签的默认链接地址
(2)<style> 定义了HTML文档的样式文件
(3) <link> 定义了一个文档和外部资源之间的关系。
3、CSS可以通过三种方式实现:
(1)图片文字用div等元素布局形成HTML文件;
(2)新建相应CSS文件,CSS文件中定义样式并用<link>链接到html中;
(3)在HTML中的<head>中使用<style>进行布局美化。
index.html
{% extends‘base2.html‘ %} {% block title %}首页{% endblock %} {% block main %} <link rel="stylesheet" type="text/css" href="{{ url_for(‘static‘,filename=‘css/1.css‘) }}"> <script src="{{ url_for(‘static‘,filename=‘js/base.js‘) }}"></script> <p>{{ user }}</p> <div class="div"> <ul class="list-group"> {% for foo in questions %} <li class="list-group-item"> <br> <a href="{{ url_for(‘usercenter‘,user_id=foo.author_id,tag="1") }}">作者★:{{ foo.author.username }}</a> <br> <a href="{{ url_for(‘detail‘ ,question_id=foo.id)}}">问题标题:{{ foo.title }}</a> <br> <p style="color:black">详情:{{ foo.detail }}</p> <br> <a class="ziti" href="{{ url_for(‘usercenter‘ ,user_id=foo.author_id,tag="1")}}">评论:{{ foo.comments|length }}</a> <br> <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}</span> <hr size="1"> <br> <br> </li> {% endfor %} </ul> </div> <div class="recommend" > <footer class="footer"> <div class="img"> <img src="../static/image/b.jpg" width="250" height="100" > <img src="../static/image/4.jpg" width="250" height="100"> <img src="../static/image/2.jpg" width="250" height="100" > <img src="../static/image/1.jpg" width="250" height="100" > <img src="../static/image/5.jpg" width="250" height="100" > <p>简书 读书 散文 交友 人生</p> </div> </footer> </div> <div class="bottom" style="background-color: cadetblue;clear:both; text-align:center; font-size:12px; padding-bottom:1px"> <a href="">联系我们</a> <a href="">加入我们</a> <a href="">帮助中心</a> <a href="">合作伙伴</a> </div> <div id="footer" style="background-color:cadetblue; clear:both; text-align:center; font-size:12px; padding-bottom:1px">版权@yaya</div> {% endblock %}
二、完成注册功能(用html元素制作web页面)
1、用div,form制作注册页面;
2、通过JS语句增加错误提示框,并实现写好HTML+CSS文件,设置每个输入元素的id。
3、定义JavaScript 函数,设置登录注册页面验证用户名与登录密码6-20位,注册还需包括验证用户名首字母不能是数字,只能包含字母和数字,输入的两次密码必须一致,并在各自html页面的button标签onclick调用这个函数。
4、js文件: onclick函数return True时才提交表单,return False时不提交表单,判断用户名是否存在:存在报错,不存在就存到数据库中,redirect重定向到登录页。
5、html文件:
(1)<form>中设置 action和method="post"
(2)<input> 中设置 name
6、主py文件中:
(1)from flask import request, redirect, url_for
(2)@app.route(‘/regist/‘, methods=[‘GET‘, ‘POST’])
@app.route(‘/register/‘, methods=[‘GET‘,‘POST‘]) def register(): if request.method==‘GET‘: return render_template(‘register.html‘) else: usern=request.form.get(‘username‘) passw= request.form.get(‘password‘) user=User.query.filter(User.username==usern).first() if user: return ‘username existed‘ else: user=User(username=usern,password=passw) db.session.add(user) db.session.commit() return redirect(url_for(‘login2‘))
register.html
{% extends‘base2.html‘ %} {% block title %} register {% endblock %} {% block head %} <link rel="stylesheet" type="text/css" href="../static/css/1.css"> <script src="../static/js/zhuce.js"></script> {% endblock %} {% block main %} <body> <div class="box"> <div id="container" style="width: 400px" align="center"> <div id="header" style="background-color:lightskyblue"><h1 align="center" style="margin-bottom: 0;">注册</h1></div> <div id="content" style="background-color:lightpink;height:205px;width:400px;float:left;"> <p></p> <form action="{{ url_for(‘register‘) }}" method="POST"> <div class="input_box"> Username:<input id="uname" type="text" name="username" placeholder="请输入用户名"> </div> <br> <div class="input_box"> Password:<input id="upass" type="password" name="password" placeholder="请输入登录密码"> </div> <br> <div class="input_box"> 密码确认:<input id="again" type="password" placeholder="请再次输入密码"> </div><br> <div id="error_box"><br></div> <div class="input_box"> <button onclick="return myLogin()">点击注册</button> <button type="button" onclick=window.alert("是否取消注册!")>取消</button> </div> </form> </div> </div> </div> </body> {% endblock %}
zhuce.js
function myLogin() { var oUname = document.getElementById("uname"); var oUpass = document.getElementById("upass"); var oAgain = document.getElementById("again"); 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 (oUpass.value.length < 6 || oUpass.value.length > 20) { oError.innerHTML = "密码6-20位"; return false; } // 验证再次输入的密码 if (upass.value != zhuce.value) { oError.innerHTML = "密码不一致"; return false; } return true; // 验证弹框 window.alert("注册成功!") }
三、完成登录功能
1、定义JavaScript 函数。
(1)验证用户名6-20位
(2)验证密码6-20位。
2、与注册一样完成js文件,在主py文件定义函数,读取表单数据查询数据库;
3、用户名密码对就用session记住用户名并跳转到首页;用户名密码不对则提示相应错误。
py文件
@app.route(‘/login2/‘, methods=[‘GET‘,‘POST‘]) def login2(): if request.method==‘GET‘: return render_template(‘login2.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[‘id‘] = user.id session.permanent=True return redirect(url_for(‘index‘)) else: return "密码错误,请重新输入。" else: return "用户名不存在!"
login.html
{% extends‘base2.html‘ %} {% block title %} Login {% endblock %} {% block head %} <link href="{{ url_for("static",filename="css/1.css") }}" rel="stylesheet" type="text/css"> <script src="{{ url_for("static",filename="js/denglu.js") }}"></script> {% endblock %} {% block main %} <body> <div class="box"> <form action="{{ url_for(‘login2‘) }}" method="post"> <div id="container" style="width: 400px" align="center"> <div id="header" style="background-color:lightskyblue"><h1 align="center" style="margin-bottom: 0;">会员登录</h1></div> <div id="content" style="background-color:lightpink;height:205px;width:400px;float:left;"> <p></p> <div class="input_box"> Username:<input id="username" type="text" name="username" placeholder="请输入用户名"><br> </div> <br> <div class="input_box"> Password:<input id="password" type="password" name="password" placeholder="请输入登录密码"><br> </div> <div id="error_box"><br></div> <div class="input_box"> <input type="radio">普通会员 <input type="radio">金牌会员 <input type="radio">钻石会员 </div><br> <div class="input_box"> <button onclick="return fnLogin()">登录</button> <button type="button" onclick=window.alert("是否取消登录!")>取消</button> </div> </div> </div> </form> </div> </div> </body> {% endblock %} </html>
denglu.js
function fnLogin() { var oUname = document.getElementById("username") var oError = document.getElementById("error_box") var opassward = document.getElementById("password") var isError=true; oError.innerHTML="<br>" //uname if (oUname.value.length < 6 || oUname.value.length > 20) { oError.innerHTML = "用户名6-20位"; isError=false; return isError; } else if ((oUname.value.charCodeAt(0) >= 48) && (oUname.value.charCodeAt(0) <= 57)) { oError.innerHTML = "用户名首字母不能是数字"; isError=false; return isError; } 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="用户名只能是字母或数字"; isError = false; return isError; } } //upass if(oUpass.value.length<6 || oUpass.value.length>12){ oError.innerHTML="密码6-12位"; isError = false; return isError; } window.alert("登录成功") }
四、加载静态文件,父模板的继承和扩展
1、用url_for加载静态文件<script src="{{ url_for(‘static‘,filename=‘js/login.js‘) }}"></script>;
2、flask 从static文件夹开始寻找可用于加载css, js, image文件。
3、实现继承和扩展,把一些公共的代码放在父模板中,避免每个模板写同样的内容。
4、子模板继承父模板 ,父模板提前定义好子模板可以实现一些自己需求的位置及名称。子模板中写代码实现自己的需求。
5、夜间模式的开启与关闭
(1)放置点击的按钮或图片。
(2)定义开关切换函数。
(3)onclick函数调用。
<img id="myOnOff" style="float: right" onclick="mySwitch()" src="{{ url_for("static",filename="image/off.jpg") }}" width="35px">
js文件
function mySwitch() {
var oBody = document.getElementById("myBody");
var oOnoff = document.getElementById("myOnOff");
if (oOnoff.src.match("on")) {
oOnoff.src = "../static/image/off.jpg";
oBody.style.background = "black";
oBody.style.color = "white";
} else {
oOnoff.src = "../static/image/on.jpg";
oBody.style.background = "white";
oBody.style.color = "black";
}
}
五、实现登录之后更新导航
1、用上下文处理器app_context_processor定义函数
(1)获取session中保存的值
(2)返回字典
@app.context_processor def mycontext(): usern=session.get(‘user‘) if usern: return {‘username‘:usern} else: return {}
2、在父模板中更新导航,插入登录状态判断代码。
(1)注意用{% ... %}表示指令。
(2){{ }}表示变量
{% if username %} <a href="{{ url_for(‘usercenter‘,user_id=session.get("id"),tag=1)}}">{{ username }}</a> <a href="{{ url_for(‘logout‘) }} " class="right">注销</a> {% else %} <a href="{{ url_for(‘login2‘ )}}" class="right">登录</a> <a href="{{ url_for(‘register‘ )}}" class="right">注册</a> {% endif %}
3、完成注销功能。
1、清除session
2、跳转
@app.route(‘/logout/‘) def logout(): session.clear() return redirect(url_for(‘index‘))
六、完成发布功能
1.编写要求登录的装饰器
from functools import wraps
def loginFirst(func): #参数是函数
@wraps(func)
def wrapper(*args, ** kwargs): #定义个函数将其返回
#要求登录
return func(*args, ** kwargs)
return wrapper #返回一个函数
2.应用装饰器,要求在发布前进行登录,登录后可发布。
@app.route(‘/question/‘,methods=[‘GET‘,‘POST‘])
@loginFirst
def question():
3.建立发布内容的对象关系映射。
class Question(db.Model):
4.完成发布函数。
保存到数据库。
重定向到首页
def loginFirst(func): @wraps(func) def wrapper(*args, **kwargs): if session.get(‘user‘): return func(*args, **kwargs) else: return redirect(url_for(‘login2‘))
@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‘) 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(‘index‘))
七、制作首页的显示列表
1、在首页添加显示问答的无序列表,并定义好相应的CSS样式;
2、 用字典向index.html传递参数。
- 首页列表显示全部问答:
- 将数据库查询结果传递到前端页面 Question.query.all()
- 前端页面循环显示整个列表。
- 问答排序
3、在首页点击问答标题,链接到相应详情页。
<div class="div"> <ul class="list-group"> {% for foo in questions %} <li class="list-group-item"> <br> <a href="{{ url_for(‘usercenter‘,user_id=foo.author_id,tag="1") }}">作者★:{{ foo.author.username }}</a> <br> <a href="{{ url_for(‘detail‘ ,question_id=foo.id)}}">问题标题:{{ foo.title }}</a> <br> <p style="color:black">详情:{{ foo.detail }}</p> <br> <a class="ziti" href="{{ url_for(‘usercenter‘ ,user_id=foo.author_id,tag="1")}}">评论:{{ foo.comments|length }}</a> <br> <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}</span> <hr size="1"> <br> <br> </li> {% endfor %} </ul> </div>
八、完成问答详情页布局
(1)包含问答的全部信息,评论区,以往评论列表显示区;
(2)在首页点击问答标题,链接到相应详情页;
(3)主PY文件写视图函数,带id参数。
(4)首页标题的标签做带参数的链接,在详情页将数据的显示在恰当的位置。
@app.route(‘/detail/<question_id>‘) def detail(question_id): quest=Question.query.filter(Question.id==question_id).first() return render_template(‘detail.html‘, ques=quest)
九、完成评论功能
1、尝试实现发布评论。读取前端页面数据,保存到数据库中;
2、用<input type="hidden" 方法获取前端的"question_id" ,显示评论次数,调用登录装饰器
3、要求评论前登录,尝试实现详情页面下的评论列表显示。
@app.route(‘/comment/‘, methods=[‘POST‘]) @loginFirst def comment(): comment = request.form.get(‘new_comment‘) ques_id = request.form.get(‘question_id‘) author_id = User.query.filter(User.username == session.get(‘user‘)).first().id comm= Comment(author_id=author_id, question_id=ques_id, detail=comment) db.session.add(comm) db.session.commit() return redirect(url_for(‘detail‘, question_id=ques_id))
{% extends ‘base2.html‘ %} {% block title %}问答详情{% endblock %} {% block main %} <link rel="stylesheet" type="text/css" href="{{ url_for(‘static‘,filename=‘../static/css/q.css‘) }}"> <h3>评论详情</h3> <div class="question"> <h4>★title:{{ ques.title }}<br><small><a href="{{ url_for(‘usercenter‘,user_id=session[‘id‘],tag="1") }}">★author:{{ ques.author.username }}</a><br><span class="badge">time:{{ ques.creat_time }}</span></small><br> <span class="badge">detail:{{ ques.detail }}</span></h4> </div> <form action="{{ url_for(‘comment‘) }}" method="post"> <div class="form-group"> <textarea name="new_comment" class="form-control" rows="6" id="new_comment" placeholder="write your comment"></textarea> <input name="question_id" type="hidden" value="{{ ques.id }}"/> <button type="submit" class="fabu" >发布</button> </div> </form> <h6>评论数:({{ ques.comments|length }})</h6> <ul class="form-group"> {% for foo in ques.comments %} <li class="form-group"> <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span> <a href="{{ url_for(‘usercenter‘,user_id=foo.author_id,tag="1") }}">作者★{{ ques.author.username }}</a> <br> <a href="#">标题:{{ ques.title }}</a> <br> <p>评论:{{ foo.detail }}</p> <span class="badge" style="margin-left: 60%">评论时间:{{ foo.create_time }}</span> <hr size="1"> </li> {% endfor %} </ul> {% endblock %}
十、完成个人中心相关信息
1、个人中心的页面布局(html文件及相应的样式文件);
2、定义视图函数def usercenter(user_id)向前端页面传递参数;
3、页面显示相应数据:发布的全部问答、发布的全部评论、个人信息;
4、各个页面链接到个人中心。
十一、个人中心标签也导航
1、新页面userbase.html,用<ul ><li role="presentation"> 实现标签页导航。
2、让userbase.html继承base.html。重写title,head,main块,将上述<ul>的样式放在head块,<ul>放在main块中,定义新的块user。
3、个人中心页面,继承userbase.html,原个人中心就自动有了标签页导航。
4、制作个人中心的三个子页面,重写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 = { ‘username‘: user.username, ‘question‘: user.question, ‘comments‘: user.comments, ‘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)
userbase.html
<ul class="nav_ul"> <li role="presentation"><a href="{{ url_for(‘usercenter‘,user_id=user.id,tag="1") }}">全部问答</a></li> <li role="presentation"><a href="{{ url_for(‘usercenter‘,user_id=user.id,tag="2") }}">全部评论</a></li> <li role="presentation"><a href="{{ url_for(‘usercenter‘,user_id=user.id,tag="3") }}">个人信息</a></li> </ul>
十二、实现导航条中的搜索功能
1.修改base.html 中搜索输入框所在的
- <form action="{{ url_for(‘search‘) }}" method="get">
- <input name="q" type="text" placeholder="请输入关键字">
2.完成视图函数search()
- 获取搜索关键字
q = request.args.get(‘q’) - 条件查询
qu = Question.query.filter(Question.title.contains(q)).order_by(‘-creat_time’) - 加载查询结果:
return render_template(‘index.html‘, question=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(‘index.html‘,questions = ques)
<form action="{{ url_for(‘search‘) }}" method="get" style="margin-left: 1100px;margin-top: -50px"> <input name="q" type="text" class="form-control" style="width: 250px; height: 25px" placeholder="请输入关键字" > <input type="submit" style="" value="搜索"></input> </form>
十三、密码保护
1、实现密码保护功能;更新User对象,设置对内的_password,编写对外的password,实现密码验证和登录验证。
2、登录验证:
password1 = request.form.get(‘password‘)
user = User.query.filter(User.username == username).first()
if user:
if user.check_password(password1):
class User(db.Model): __tablename__ = ‘user‘ id = db.Column(db.Integer,primary_key=True,autoincrement=True) username = db.Column(db.String(20),nullable=False) _password = db.Column(db.String(200), nullable=False)#内部使用
@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
以上是学习使用Python的Flask框架+MysqL完成简单的网页设计总结,我会继续努力学习这门课程的。