个人学期总结
总结Python+Flask+MysqL的web建设技术过程,标准如下:
- 即是对自己所学知识的梳理
- 也可作为初学入门者的简单教程
- 也可作为自己以后复习的向导
- 也是一种向外展示能力的途径
这篇文章总结了我这个学期的学习结果:使用Flask框架搭建一个可扩展的小型web service,并在其中加上一些原理的阐述或者链接,并用上一些简单的css,js,html。
一、 Flask & 概览
下面是Flask最简单的一个示例,这篇文章要做的就是将其充实、扩展、拆分,使代码具有良好的可扩展性和可读性。
from flask import Flask app = Flask(__name__) @app.route('/') def base(): return render_template("base.html") if __name__ == '__main__': app.run()
上述代码中的route方法是一个装饰器。这里我们使用python3.5的解释器,可以实现static文件、templates文件与py文件。
二.数据库连接池
项目使用了MySQL数据库和Redis数据库,根据不同情况选择使用。
MySQL
pip安装flask-sqlalchemy。sqlalchemy是实现ORM的库,然后进行数据库连接,用mysql创建数据库:
from flask import Flask, render_template, request, redirect, url_for, session from flask_sqlalchemy import SQLAlchemy from datetime import datetime import config from functools import wraps from sqlalchemy import or_ from werkzeug.security import generate_password_hash, check_password_hash app = Flask(__name__) app.config.from_object(config) db=SQLAlchemy(app)
当要使用数据库时,调用db即可。
然后进行数据库配置信息config.py:
import os SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/mis15?charset=utf8' SQLALCHEMY_TRACK_MODIFICATIONS = False SECRET_KEY =os.urandom(24)
下一步是建立mysql和app的连接。
最后创建用户模型。
三.通过用户模型,对数据库进行增删改查
from flask import Flask from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) app.config.from_object('config') db=SQLAlchemy(app) 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(20),nullable=False) nickname = db.Column(db.String(20)) #db.create_all() #查 user =User.query.filter(User.username=='krislst').first() print(user,id,user.username,user.password) #增 user =User(username='krislst',password='666666') db.session.add(user) db.session.commit() #删 user =User(username='krislst',password='666666') db.session.delete(user) db.session.commit() #改 user =User.query.filter(User.username=='krislst').first() user.username ='kriswu' print(user.username,user.password) db.session.add(user) db.session.commit() @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()
四.完整的注册接口
@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') user = User.query.filter(User.username == username).first() if user: return '用户名已存在' else: user = User(username=username, password=password) db.session.add(user) # 数据库,添加操作 db.session.commit() return redirect(url_for('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['userid'] =user.id session.permanent = True return redirect(url_for('base')) else: return '密码错误' else: return '用户名不存在'
设置JS:
function foLogin() { var oUname = document.getElementById("uname"); var oError = document.getElementById("error_box"); var oUpass = document.getElementById("upass"); var isError = true; oError.innerHTML = "<br>"; if (oUname.value.length < 6 || oUname.value.length > 12) { oError.innerHTML = "用户名要6-12位"; isError = false; return; }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)<58)&&(oUname.value.charCodeAt(i)>97)){ oError.innerHTML="只能为数字和字母"; isError = false; return isError; } } if (oUpass.value.length < 6 || oUpass.value.length > 12) { oError.innerHTML = "密码要6-20位"; isError = false; isError = false; return isError; } return true; }
六.登录之后更新导航功能
用上下文处理器app_context_processor定义函数
- 获取session中保存的值
- 返回字典
from flask import Flask,render_template,request,redirect,url_for,session from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) 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(20), nullable=False) db.create_all() @app.route('/') def index(): return render_template('index.html') @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,User.password==passw).first() if user: session['user']=usern session.permanent=True return redirect(url_for('index')) else: return u'error username or password' @app.route('/regist/',methods=['get','post']) def regist(): if request.method=='GET': return render_template('regist.html') else: usern=request.form.get('username') passw =request.form.get('password') user=User.query.filter(User.username==usern).first() if user: return u'username existed' else: user1=User(username=usern,password=passw) db.session.add(user1) db.session.commit() return redirect(url_for('login')) @app.route('/logout/') def logout(): session.clear() return redirect(url_for('index')) @app.context_processor def context(): username = session.get('user') if username: return {'username':username} else: return() if __name__ == '__main__': app.run(debug=True)
然后在父模板中更新导航,插入登录状态判断代码。
- 注意用{% ... %}表示指令。
- {{ }}表示变量
最后完成注销功能。
- 清除session
- 跳转
七.完成发布功能
- 编写要求登录的装饰器
from functools import wraps
def loginFirst(func): #参数是函数
@wraps(func)
def wrapper(*args, ** kwargs): #定义个函数将其返回
#要求登录
return func(*args, ** kwargs)
return wrapper #返回一个函数
from functools import wraps def loginFrist(func): @wraps(func) def wrappers(*args, **kwargs): if session.get('user'): return func(*args, **kwargs) else: return redirect(url_for('login')) return wrappers
- 应用装饰器,要求在发布前进行登录,登录后可发布。
@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():
- 建立发布内容的对象关系映射。
class Question(db.Model):
- 完成发布函数。
保存到数据库。
重定向到首页。
@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'))
八.制作首页的显示列表
第一,在首页添加显示问答的列表,并定义好相应的样式。
无序列表
<ul >
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
html{% extends 'base.html' %} {% block title %}首页{% endblock %} {% block head %} <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="../static/css/index.css"> {% endblock %} {% block main %} <div class="question-box"> <img src=https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg style="width: 50px"> <ul class="list-group"> <li clsss="list=group-item"> <span class="glyphicon glyhicon-leaf" aria-hidden="true"></span> <a href="https://wx2.sinaimg.cn/mw690/637dee21ly1fm12yb1cqrj20w01d8tq1.jpg">Kris wu{{ user }}</a><br> <a href="https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg">最新街拍{{ title }}</a><br> <span class="badge">上线时间{{ time }}</span> <p style="color: indianred">pictures{{ detail }} </p> <div class="img"> <a herf="https://wx2.sinaimg.cn/mw690/637dee21ly1fm12yb1cqrj20w01d8tq1.jpg"> <img src="https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg"></a> <div class="desc"><a href="https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg>burberry</a></div> </div> </li> </ul> </div> {% endblock %}
第二步. 用字典向index.html传递参数。
@app.route('/index/') def index(): context={ 'user':'kriswu:', 'title': '最新街拍', 'time': 'today', 'detail':'burberry*kriswu'} return render_template('index.html',**context)
九.从首页问答标题到问答详情页
1.主PY文件写视图函数,带id参数。
@app.route('/detail/<question_id>')
def detail(question_id):
quest =
return render_template('detail.html', ques = quest)
2.首页标题的标签做带参数的链接。
{{ url_for('detail',question_id = foo.id) }}
{% for foo in questions %} <li class="list-group-item" style="width: 600px"> <a class="wrap-img" href="#" target="_blank"> <img src="{{ foo.author.image }}" width="35px"> </a> <span class="glyphicon glyphicon-left" aria-hidden="true"></span> <a href="#" target="_blank">{{ foo.author.username }}</a> <br> <a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a> <br> <span class="badge">发布时间:{{ foo.creat_time }}</span> <p style="">{{ foo.detail }} </p> </li> {% endfor %}
3.在详情页将数据的显示在恰当的位置。
{{ ques.title}}
{{ ques.id }}{{ ques.creat_time }}
{{ ques.author.username }}
{{ ques.detail }}
4.建立评论的对象关系映射:
class Comment(db.Model):
__tablename__='comment'
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')) creat_time = db.Column(db.DateTime, default=datetime.now) detail=db.Column(db.Text,nullable=False) question=db.relationship('Question',backref=db.backref('comments')) author=db.relationship('User',backref=db.backref('comments'))
十.完成评论功能
1.定义评论的视图函数
@app.route('/comment/',methods=['POST'])
def comment():
读取前端页面数据,保存到数据库中
@app.route('/comment/',methods=['POST']) def comment(): comment =request.form.get('new_comment') ques_id =request.form.get('question_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'))
2.用<input type="hidden" 方法获取前端的"question_id"
<input name="question_id" type="hidden" value="{{ques.id}}"/>
3.显示评论次数
<h4>评论({{ ques.comments|length }}</h4>
4.要求评论前登录
@app.route('/comment/',methods=['POST']) @loginFrist 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))
5.尝试实现详情页面下的评论列表显示
{% for com in ques.comment %} <a href="#" >{{ com.author.username }}</a> <small>{{ com.creat_time }}</small> <p class="">{{ com.detail }}</p> {% endfor %}
十一.评论列表显示及排序,个人中心显示
- 显示所有评论
{% for foo in ques.comments %} - 所有评论排序
uquestion = db.relationship('Question', backref=db.backref('comments', order_by=creat_time.desc)) - 显示评论条数
{{ ques.comments|length }} - 完成个人中心
1.个人中心的页面布局(html文件及相应的样式文件)
2.定义视图函数def usercenter(user_id):
3.向前端页面传递参数
4.页面显示相应数据
发布的全部问答
发布的全部评论
个人信息
5.各个页面链接到个人中心
{% extends "base.html" %} {% block detailtitle%}问答详情{% endblock %} {% block detailhead %} {% endblock %} {% block mywebbody %} <div class="page-header" style="color: pink" align="center"> <h3>{{ ques.title }}<br><small>{{ ques.author.username }} <span class="badge">{{ ques.creat_time }}</span> </small></h3> </div> <p class="lead">{{ ques.detail }}</p> <hr> <form action="{{ url_for('comment') }}"method="post">写评论 <div class="form-group"> <textarea name="new_comment"class="form-control"rows="3"id="new-comment"placeholder=""></textarea> <input type="hidden" name="question_id" value="{{ ques.id }}"> </div> <button type="submit"class="btn btn-default">发送</button> </form> <h4>评论:({{ ques.comments|length }})</h4> <ul class="list-group"style="margin:10px"> {% for foo in ques.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)}}">{{foo.author.username }}</a> <span class="badge">{{foo.creat_time}}</span> <p style="">{{foo.detail}}</p> </li> {% endfor %} </ul> {% endblock %}
usercenter.html {% extends 'base.html' %} {% block title %}个人中心 {% endblock%} {% block main%} <div class="page-header"> <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span> {{username}} <br> <small>问答><span class="badge"></span> </small></h3> <ul class="list-group" style=""> {% for foo in user.question %} <li class="list-group-item"> <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span> <a href="#">{{foo.author.username }}</a> <span class="badge">{{foo.creat_time}}</span> <p style="">{{foo.detail}}</p> </li> {% endfor %} </ul> </div> 详情 <div class="page-header"> <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span> {{user}} <br> <small>个人信息><span class="badge"></span> </small></h3> <ul class="list-group" style=""> {% for foo in user.comments %} <li class="list-group-item"> <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span> <a href="#">{{foo.author.username }}</a> <span class="badge">{{foo.creat_time}}</span> <p style="">{{foo.detail}}</p> </li> {% endfor %} </ul> </div> <div class="page-header"> <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span> {{user}} <br> <small>个人信息><span class="badge"></span> </small></h3> <ul class="list-group" style=""> <li class="list-group-item">user:{{username}}</li> <li class="list-group-item">number:</li> <li class="list-group-item">nickname:</li> <li class="list-group-item">评论数量:</li> </ul> </div> {% endblock %}
十二.个人中心标签页导航及导航标签
新页面userbase.html,用<ul ><li role="presentation"> 实现标签页导航。
<ul class="nav nav-tabs">
<li role="presentation"><a href="#">Home</a></li>
<li role="presentation"><a href="#">Profile</a></li>
<li role="presentation"><a href="#">Messages</a></li>
</ul>
- 让userbase.html继承base.html。
重写title,head,main块.
将上述<ul>的样式放在head块,<ul>放在main块中.
定义新的块user。 - 继承userbase.html,原个人中心就自动有了标签页导航。
- 制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。
- 个人中心—视图函数带标签页面参数tag
@app.route('/usercenter/<user_id>/<tag>')
def usercenter(user_id, tag):
if tag == ‘1':
return render_template('usercenter1.html', **context) - 个人中心—导航标签链接增加tag参数
<li role=“presentation”><a href=“{{ url_for(‘usercenter’,user_id = user.id,tag = ‘1’) }}">全部问答</a></li> - 个人中心—有链接到个人中心页面的url增加tag参数
<a href="{{ url_for('usercenter',user_id = session.get('userid'), tag=1) }}">{{ session.get('user') }}</a>
usercenter {% extends "userbase.html" %} {% block usercenterbody %} <div class="page-header"> <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ username }}<br><small>全部问答<span class="badge>"></span> </small> </h3> <ul class="list-group"style="margin:10px"> {% for foo in comments %} <li class="list-group-item"> <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span> <a href="#">{{ foo.user.username }}</a> <span class="badge">{{ foo.creat_time }}</span> <p style="align-content: center">{{ foo.detail }}</p> </li> {% endfor %} </ul> </div> <div class="page-header"> <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ user }}<br><small>全部评论<span class="badge>"></span> </small> </h3> <ul class="list-group"style="margin:10px"> {% for foo in comments %} <li class="list-group-item"> <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span> <a href="#">{{ foo.user.username }}</a> <span class="badge">{{ foo.creat_time }}</span> <p style="align-content: center">{{ foo.detail }}</p> </li> {% endfor %} </ul> </div> <div class="page-header"> <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ user }}<br><small>个人信息<span class="badge>"></span> </small> </h3> <ul class="list-group"style="margin:10px"> <li class="list-group-item">user:{{ username }}</li> <li class="list-group-item">number:</li> <li class="list-group-item">nickname:</li> </ul> </div> {% endblock %}
@app.route('/usercenter/<user_id>/<tag>') @log def usercenter(user_id,tag): user=User.query.filter(User.id==user_id).first() context={ 'username':user.username, 'questions':user.question, 'comments':user.comments } if tag =='1': return render_template('wenda.html',**context) elif tag =='2': return render_template('comment.html',**context) else : return render_template('grxx.html',**context)
detail.html <a href="{{ url_for('usercenter',user_id=ques.author_id,tag=1) }}">{{ ques.author.username }}</a> base.html <li><a href="{{ url_for('usercenter',user_id=session.get('user_id'),tag=1)}}">{{session.get('user')}}</a></li> index.html <li><a href="{{ url_for('usercenter',user_id=foo.author_id,tag=1)}}">{{foo.author.username }}</a></li>
十三.实现搜索功能
- 准备视图函数search()
- 修改base.html 中搜索输入框所在的
- <form action="{{ url_for('search') }}" method="get">
- <input name="q" type="text" placeholder="请输入关键字">
<form action="{{ url_for('search')}}" method="get"></form> <div class="form-group"> <input type="text" class="form-control" placeholder="please input key words"> <button type="submit" class="btn btn-default">搜索</button> </div>
- 完成视图函数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)
- 获取搜索关键字
- 组合条件查询
from sqlalchemy import or_, and_
@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('index.html',questions =ques)
十四.实现密码保护
1.更新User对象,设置对内的_password
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)
2.编写对外的password
from werkzeug.security import generate_password_hash, check_password_hash @property def password(self): return self._password @password.setter def password(self, row_password): self._password = generate_password_hash(row_password)
3.密码验证:
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['user_id'] =user.id return redirect(url_for('base')) else: return '密码错误' else: return '用户名不存在'
总结及展望
以上是这个学期在Python+Flask+MysqL的web建设技术过程学习内容的总结和梳理,通过这些知识我算是在python web入门,也了解到这方面许多需求和知识,如有疏漏请谅解。我会继续努力,在这方面加强学习,希望可以学得更好。still i rise!
浙公网安备 33010602011771号