一、个人学期总结
在一学期里我们学习并实现了基于Python的Flask框架web建设项目,要在一学期里入门一个新的语言并且完成相应的框架项目建,对我这个代码“小白”来说还是非常有难度的。
首先让我们来了解一下Python的一些优势和目前的发展情况,python是一种面向对象的解释型计算机程序设计语言,语法简洁清晰,目前已超越java成为最热门的编程语言之一。作为以后有可能向IT方向发展的学生来说,紧跟潮流进行学习和自我提升是非常重要的事情,也许老师也是考虑到这一点,所以让我们接触了最新最热门的Python以及Pycharm开发工具。
学期初始,我们学习了Python的基础语法,输入、输出、交互、数字计算的方法、字符串基本操作、凯撒密码、自制九九乘法表、中英文词频统计等,还学习了import turtle库,并利用这个库绘制出多种多样的图形,海龟图标有趣可爱,课堂氛围活泼许多,从而激发了我们学习Python的兴趣,提升了我们对编程语言的思维能力,为构建Flask框架制作网页的学习打下基础。
在学习Python+Flask+MysqL的web建设时,需要安装数据库(mysql)、开发工具(pycharm)和开发需要用到的第三方库等。
一开始,我们学习网页前端的制作,第一次知道五花八门的网页原来是由许许多多的标签对组成的,每一对都有它特定的一些功能,包含了标签对里的众多参数,每个参数都有不同的含义,给页面前端带来不同的效果。刚开始接触html+css+js的时候会想各种办法去把网页做好看,尝试了各种各样的样式和标签对,或者从网页上cope别人做好的样式代码去修改,碰到不会的代码就问百度解答或同学探讨,在这过程中又学会了许多课堂上没有教过的知识,但是最终做出的页面也不尽人意,这才感悟做出漂亮好看的前端如此不易。老师在课上推荐了菜鸟教程这个平台(http://www.runoob.com/),里面的bookstrap样式简洁明了,很是好看,为我们做出一个好看的页面提供了便捷的途径。
在后端建设过程中,我们引入了flask库,用于创建一个Flask对象以及页面的跳转,引入flask_sqlalchemy库进行数据库的关联映射等,学习了对数据的增删改查等操作,利用对数据库的查询、添加功能实现了页面的登陆、注册以及发布功能,这些功能的实现根据前端页面的name属性名,后台请求接收同名name的值,再对接收到的值做一系列的操作。在对这些name属性命名时,要注意前后端对应,且同一页面不能出现相同命名,否则会出现数据传递出错,造成一系列的麻烦,所以在编程过程中要时刻注意代码的唯一性、对应性、尽量用更少更优化的代码实现功能。
说到代码,讲了唯一性和对应性,就不得不提简洁性和清晰性了,打代码时可以多用“Ctrl+Alt+L”快捷键进行格式化代码,以便我们清晰的观察和修改代码。养成良好的习惯还在于多用“Ctrl+/”打注释,把个人的理解和思路整理成简单的注释,不仅方便自己复习和修改还有利于使用者及他人查看学习。
一般来说,在着手写代码前,应先明确目标和功能,理请原理和思路,再开始编写,遵循小步快走的原则,在写好每个功能代码后,按原理检查是否出错, 再运行页面验证功能,如此渐渐的把整个系统实现。出错时也不必惊慌,先用F12打开页面控制台查看数据发送、接收情况和红色报错项目,或者到pycharm后台里找相应的报错字眼、提示等等去解决问题。
总之,借用老师的一句话,“编程是一门艺术活”,像做建筑一般,字母是它的钢筋水泥和砖块,只有实打实的基础,地基牢固,才能成就崛起的名胜古迹。
本学期学习了python+flask web开发,我觉的自己真正的学到了东西,从菜鸟到会独立完成自己的项目,过程中遇到很多问题,查阅资料,与同学讨论后一起解决。 虽然这个学期python课程学习结束了,但是我的学习不会止于此,我还会继续学习python语言,不断提升自己的能力。
二、Python+Flask+MysqL的web建设技术过程总结
1、使用工具
工具:pycharm64.exe + Python 3.6 64-bit + MySQL + Navicat for MySQL
2、基本页面展示
(1)导航条
(2)登录页面
(3)注册页面
(4)发布页面
(5)首页
(6)评论页面
(7)个人页面
3、第三方库导入、Flask初始概览与数据库链接
主py文件:
config:数据库连接
app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) class User(db.Model): # 创建类User __tablename__ = 'user' # 类对应的表名user id = db.Column(db.Integer, primary_key=True, autoincrement=True) # autoincrement自增长 username = db.Column(db.String(20), nullable=False) # nullable是否为空 _password = db.Column(db.String(200), nullable=False) #内部使用 nickname = db.Column(db.String(20), nullable=True) @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 Fabu(db.Model): __tablename__ = 'fabu' 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('fabu')) 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')) fabu_id = db.Column(db.Integer, db.ForeignKey('fabu.id')) creat_time = db.Column(db.DateTime, default=datetime.now) detail = db.Column(db.Text, nullable=False) fabu = db.relationship('Fabu',backref=db.backref('comments',order_by=creat_time.desc)) author = db.relationship('User', backref=db.backref('comments')) db.create_all() # 使用装饰器,设置路径与函数之间的关系。 #使用Flask中render_template,用不同的路径,返回首页、登录员、注册页。 # 用视图函数反转得到URL,url_for(‘login’),完成导航里的链接。 @app.route('/') def daohang(): context={ 'fabus': Fabu.query.order_by('-creat_time').all() } return render_template('daohang.html',**context) if __name__ == '__main__': app.run(debug=True)
4、增删改查功能
# 插入功能 user = User(username='15',password='12') db.session.add(user) db.session.commit() # 查询功能 user=User.query.filter(User.username=="15").first() print(user.username,user.password) # 修改功能 user=User.query.filter(User.username=="15").first() user.password='888' db.session.commit() # 删除功能 user=User.query.filter(User.username=="15").first() db.session.delete(user) db.session.commit()
5、加载静态文件、父模板与其他页面继承
url_for运用:
from flask import url_for
跳转后端请求:
加载静态文件:(css、js、image)
继承父模板:
6、注册功能:
(1)html文件:
{% extends 'daohang.html' %} {% block zhucetitle %}注册{% endblock %} {% block zhucehead %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/denglu.css') }}"> <script src="{{ url_for('static',filename='js/denglu.js') }}">script> {% endblock %} {% block daohangbody %} <div class="center-block" id="zhucebox"> <div class="panel panel-primary" id="zhucebox1_1"> <div class="panel-heading"> <h2 class="panel-title">注册h2> div> <br> <form class="bs-example bs-example-form" role="form" action="{{ url_for('zhuce') }}" method="post"> <div class="input-group"> <span class="input-group-addon">span> <input type="text" class="form-control" name="user" id="user" placeholder="请输入用户名"> div> <br> <div class="input-group"> <span class="input-group-addon">span> <input type="password" class="form-control" name="pass" id="pass" placeholder="请设置密码" > div> <br> <div class="input-group"> <span class="input-group-addon">span> <input type="password" class="form-control" id="again" placeholder="请再次输入密码"> div> <div id="error_box1"> <br> div> <br> <label><input type="submit" class="btn btn-default" value="注册" onclick="fnRegistration()">input>label> form> div> div> {% endblock %}
(2)js文件:
function fnRegistration() { var uSer = document.getElementById("user"); var pAss = document.getElementById("pass"); var aGain = document.getElementById("again"); var oError = document.getElementById("error_box"); var isError = true; oError.innerHTML = "
"; // 验证用户名 if (uSer.value.length < 6 || uSer.value.length > 20) { oError.innerHTML = "用户名只能6-20位"; isError = false; return isError; } else if ((uSer.value.charCodeAt(0) >= 48) && (uSer.value.charCodeAt(0) <= 57)) { oError.innerHTML = "用户名首字母不能是数字"; isError = false; return isError; } else for (var i = 0; i < uSer.value.length; i++) { if ((uSer.value.charCodeAt(i) < 48) || (uSer.value.charCodeAt(i) > 57) && (uSer.value.charCodeAt(i) < 97) || (uSer.value.charCodeAt(i) > 122)) { oError.innerHTML = "用户名只能由数字和字母组成"; isError = false; return isError; } } // 验证密码 if (pAss.value.length < 6 || pAss.value.length > 20) { oError.innerHTML = "密码只能6-20位"; isError = false; return isError; } // 验证再次输入的密码 if (aGain.value != pAss.value) { oError.innerHTML = "密码不一致"; isError = false; return isError; } // 验证弹框 window.alert("注册成功!"); return true; }
(3)py文件:
@app.route('/zhuce/', methods=['GET', 'POST']) def zhuce(): if request.method == 'GET': return render_template('zhuce.html') else: username = request.form.get('user') # post请求模式,安排对象接收数据 password = request.form.get('pass') nickname = request.form.get('nickname') user = User.query.filter(User.username == username).first() # 作查询,并判断 if user: return u'该用户已存在' else: user = User(username=username, password=password, nickname=nickname) # 将对象接收的数据赋到User类中,即存到数据库 db.session.add(user) # 执行操作 db.session.commit() return redirect(url_for('denglu')) # redirect重定向
7、登录功能:
(1)html文件:
{% extends 'daohang.html' %} {% block denglutitle %}登陆{% endblock %} {% block dengluhead %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/denglu.css') }}"> <script src="{{ url_for('static',filename='js/denglu.js') }}">script> {% endblock %} {% block daohangbody %} <div class="center-block" id="loginbox"> <div class="panel panel-primary" id="loginbox1_1"> <div class="panel-heading"> <h2 class="panel-title">登陆h2> div> <br> <form class="bs-example bs-example-form" role="form" action="{{ url_for('denglu') }}" method="post"> <div class="input-group"> <span class="input-group-addon">span> <input class="form-control" type="text" name="user" id="user" placeholder="请输入用户名"> div> <br> <div class="input-group"> <span class="input-group-addon">span> <input class="form-control" type="password" name="pass" id="pass" placeholder="请输入密码" > div> <div id="error_box"> <br> div> <div class="checkbox"> <label> <input type="checkbox">记住我 label> div> <br> <label><input type="submit" class="btn btn-default" onclick="fnLogin()" value="登陆"> input> label> form> div> div> {% endblock %}
(2)js文件:
function fnLogin() { var uSer = document.getElementById("user"); var pAss = document.getElementById("pass"); var oError = document.getElementById("error_box"); var isError = true; oError.innerHTML = "
"; // 验证用户名 if (uSer.value.length < 6 || uSer.value.length > 20) { oError.innerHTML = "用户名只能6-20位"; isError = false; return isError; } else if ((uSer.value.charCodeAt(0) >= 48) && (uSer.value.charCodeAt(0) <= 57)) { oError.innerHTML = "用户名首字母不能是数字"; isError = false; return isError; } else for (var i = 0; i < uSer.value.length; i++) { if ((uSer.value.charCodeAt(i) < 48) || (uSer.value.charCodeAt(i) > 57) && (uSer.value.charCodeAt(i) < 97) || (uSer.value.charCodeAt(i) > 122)) { oError.innerHTML = "用户名只能由数字和字母组成"; isError = false; return isError; } } // 验证密码 if (pAss.value.length < 6 || pAss.value.length > 20) { oError.innerHTML = "密码只能6-20位"; isError = false; return isError; } // 验证弹框 window.alert("登陆成功!"); return true; }
(3)py文件:
内有session功能
@app.route('/denglu/', methods=['GET', 'POST']) def denglu(): if request.method == 'GET': return render_template('denglu.html') else: username = request.form.get('user') # post请求模式,安排对象接收数据 password = request.form.get('pass') user = User.query.filter(User.username == username).first() # 作查询,并判断 if user: # 判断用户名 if user.check_password(password):# 判断密码 session['user'] = username # 利用session添加传回来的值username session.permanent = True # 设置session过期的时间 return redirect(url_for('daohang')) else: return u'用户密码错误' else: return u'用户不存在,请先注册'
处理器模板:
8、发布功能:
(1)html文件:
{% extends 'daohang.html' %} {% block fabutitle %}发布{% endblock %} {% block fabuhead %} <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js">script> <script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js">script> {% endblock %} {% block daohangbody %} <style> .center { margin: auto; width: 60%; border: 3px solid #73AD21; padding: 10px; } style> <div class="panel panel-default center" style="height:450px;width:500px"> <div class="panel-body"> <div class="form-group"> <form role="form" action="{{ url_for('fabu') }}" method="post"> <div class="form-group"> <label for="name" style="color: black">选择列表label><br> <select class="form-control" style="height:35px;width:400px"> <option>1option> <option>2option> <option>3option> <option>4option> <option>5option> select> <br> <label for="title" style="color:black">标题label><br> <textarea class="form-control" rows="1" cols="50" id="title" name="title" style="height:35px;width:400px">textarea><br> <label for="detail" style="color: black">详情label><br> <textarea class="form-control" rows="5" cols="50" id="detail" name="detail" style="height:100px;width:400px">textarea><br> <input style="color: whitesmoke" type="checkbox" name="c1" id="c1" value="">记住我<br> <div id=""><br>div> <input type="submit" value="发布" class="btn btn-default" onclick=""> div> form> div> div> div> {% endblock %}
(2)py文件:
class Fabu(db.Model): __tablename__ = 'fabu' 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('fabu')) def loginFirst(fabu): @wraps(fabu) # 加上wraps,它可以保留原有函数的__name__,docstring def wrapper(*args, **kwargs): # 定义wrapper函数将其返回,用*args, **kwargs把原函数的参数进行传递 if session.get('user'): # 只有经过登陆,session才能记住并get到值 return fabu(*args, **kwargs) else: return redirect(url_for('denglu')) return wrapper @app.route('/fabu/', methods=['GET', 'POST']) @loginFirst def fabu(): if request.method == 'GET': return render_template('fabu.html') else: title = request.form.get('title') detail = request.form.get('detail') author_id = User.query.filter( User.username == session.get('user')).first().id fabu = Fabu(title=title, detail=detail, author_id=author_id) db.session.add(fabu) db.session.commit() return redirect(url_for('daohang'))
9、评论功能:
(1)html文件:
{% extends 'daohang.html' %} {% block fabu_viewtitle %}发布{% endblock %} {% block fabu_viewhead %} <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="http://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js">script> <script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js">script> {% endblock %} {% block daohangbody %} <h2 href="#" class="text-center" style="color: oldlace">{{ ques.title }}h2> <br> <p class="text-center"> <a href="#"> <small>{{ ques.author.username }}small> a>    <span class="pull-center" style="color: oldlace"><small>{{ ques.creat_time }}small>span> p> <hr> <div style="width: 700px;margin: auto"> <p style="color: oldlace">{{ ques.detail }}p> div> <hr> <form action="{{ url_for('comment') }}" method="post"> <div class="form-group" style="height: 180px;width: 700px;margin: auto"> <textarea name="pinglun" class="form-control" rows="5" id="pinglun" placeholder="请输入评论">textarea> <input type="hidden" name="hidden_id" value="{{ ques.id }}"> <br> <input type="submit" value="发送" class="btn btn-default" onclick=""> div> <div style="width: 700px;margin: auto"> <h4 style="color: oldlace">评论:({{ ques.comments|length }})h4> <ul class="list-unstyled"> {% for foo in comments %} <li class="list-group-item"> <a>{{ foo.author.username }}a> <span class="badge pull-right">{{ foo.creat_time }}span> <p>{{ foo.detail }}p> <br> li> {% endfor %} ul> div> form> {% endblock %}
(2)py文件:
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')) fabu_id = db.Column(db.Integer, db.ForeignKey('fabu.id')) creat_time = db.Column(db.DateTime, default=datetime.now) detail = db.Column(db.Text, nullable=False) fabu = db.relationship('Fabu',backref=db.backref('comments',order_by=creat_time.desc)) author = db.relationship('User', backref=db.backref('comments')) @app.route('/detail/') def detail(question_id): quest=Fabu.query.filter(Fabu.id==question_id).first() comments = Comment.query.filter(Comment.fabu_id == question_id).all() return render_template('fabu_view.html',ques=quest,comments=comments) @app.route('/comment/',methods=['POST']) @loginFirst def comment(): detail = request.form.get('pinglun') author_id = User.query.filter(User.username == session.get('user')).first().id fabu_id = request.form.get('hidden_id') comment = Comment(detail=detail,author_id=author_id,fabu_id=fabu_id) db.session.add(comment) # 执行操作 db.session.commit() # 提交到数据库 return redirect(url_for('detail',question_id=fabu_id))
10、个人中心实现:
html文件:
(1)user模板:
{% extends 'daohang.html' %} {% block title %}个人中心{% endblock %} {% block head %} {% endblock %} {% block daohangbody %} <div style="width: 700px;margin: auto"> <ul class="nav nav-pills "> <li class="active"><a href="{{ url_for('usercenter',user_id=user_id,tag=1) }}">个人信息a>li> <li class="active"><a href="{{ url_for('usercenter',user_id=user_id,tag=2) }}">全部评论a>li> <li class="active"><a href="{{ url_for('usercenter',user_id=user_id,tag=3) }}">全部发布a>li> ul> {% block user %}{% endblock %} div> {% endblock %}
(2)usercenter1:
{% extends 'user.html' %} {% block user %} <div class="page-header"> <ul class="page-header"> <h3 style="color: whitesmoke"><span class="glyphicon glyphicon-user" aria-hidden="true">span>{{ username }}<br> <small style="color: azure">个人资料信息<span class="badge">span>small> h3> <div class="panel panel-default" style="height:180px;width:400px"> <ul class="list-group" style="..."> <li class="list-group-item">用户名:{{ username }}li> <li class="list-group-item">昵称:li> <li class="list-group-item">性别:li> <li class="list-group-item">年龄:li> ul> div> ul> div> {% endblock %}
(3)usercenter2:
{% extends 'user.html' %} {% block user %} <div class="page-header"> <ul class="page-header"> <h3 style="color: whitesmoke" ><span class="glyphicon glyphicon-user" aria-hidden="true">span>{{ username }}<br> <small style="color: azure">全部评论<span class="badge">span>small> h3> <div class="panel panel-default" style="width:700px"> <ul class="list-group" style="..."> {% for foo in comments %} <li class="list-group-item"> <span class="glyphicon glyphicon-heart-empty" aria-hidden="true">span> <a href="{{ url_for('usercenter',user_id=foo.author_id,tag=1) }}">{{ foo.author.username }}a> <span class="badge">{{ foo.creat_time }}span> <p style="...">{{ foo.detail }}p> li> {% endfor %} ul> div> ul> div> {% endblock %}
(4)usercenter3:
{% extends 'user.html' %} {% block user %} <div class="page-header"> <ul class="page-header"> <h3 style="color: whitesmoke"><span class="glyphicon glyphicon-user" aria-hidden="true">span>{{ username }}<br> <small style="color: azure">全部问答<span class="badge">span>small>h3> <ul class="list-group" style="height:300px;width:700px"> {% for foo in fabus %} <li class="list-group-item"> <span class="glyphicon glyphicon-heart-empty" aria-hidden="true">span> <a href="{{ url_for('usercenter',user_id=foo.author_id,tag=1) }}">{{ foo.author.username }}a> <span class="badge">{{ foo.creat_time }}span> <p style="...">{{ foo.detail }}p> li> {% endfor %} ul> ul> div> {% endblock %}
py文件:
@app.route('/usercenter// ') @loginFirst def usercenter(user_id,tag): user=User.query.filter(User.id==user_id).first() context={ 'user_id':user.id, 'username': user.username, 'fabus': user.fabu, 'comments': user.comments } 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)
11、搜索功能:
@app.route('/search/') def search(): qu = request.args.get('q') ques = Fabu.query.filter( or_( Fabu.title.contains(qu), Fabu.detail.contains(qu) ) ).order_by('-creat_time') return render_template('daohang.html', fabus=ques)
12、密码保护功能:
@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