期末作品检查
1、个人学期总结
前期Python的基础课程中学习到了turtle库的基础练习、字符串的基本操作、凯撒密码 、GDP格式化输出、99乘法表、中英文词频统计、和datetime处理日期和时间等等。
中期学习了web基础,用html元素制作web界面。练习使用下拉列表选择框、无序列表、有序列表、定义列表。开始制作自己的导航条。练习样式表:行内样式表、内嵌样式表、外部样式表。
后期我们开始了Flask项目,加载静态文件,父模板的继承和扩展,连接mysql数据库,创建用户模型,建立mysql和app的连接。通过用户模型,对数据库进行增删改查操作。完成注册功能,将界面的数据存到数据库,redirect重定向登录页。完成登录功能,用session记住用户名,增加用户名。登录之后更新导航。在父模板中更新导航,插入登录状态判断代码。完成注销功能,清除session。发布功能的实现,制作首页的显示列表,首页列表显示全部问答,完成问答详情页布局,从首页问答标题到问答详情页,完成评论功能,完成评论列表显示及排序,个人中心显示,个人中心标签页导航,完成个人中心—导航标签,实现搜索功能(包括高级搜索等),最重要的是实现密码加密功能。还做了模型分离与数据迁移,让数据管理更加高效简洁。
2、总结Python+Flask+MysqL的web建设技术过程
使用的工具:pycharm+mysql+Python+Navicat for mysql
导航栏:样式来源于菜鸟教程网站上的css,用起来界面会简洁明了
首页:
注册、登录、发布页面:
进入帖子详情页:
个人中心:
主要代码:
建立表的函数及主要用到的库:
import pymysql
from flask import Flask, render_template, request, redirect, url_for, session
from flask_sqlalchemy import SQLAlchemy
from functools import wraps
import config
from datetime import datetime
from sqlalchemy import or_, and_
from werkzeug.security import generate_password_hash, check_password_hash
pymysql.install_as_MySQLdb()
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(200), nullable=False) # 内部使用
nickname = db.Column(db.String(50))
userphone = db.Column(db.String(20), 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 Sent(db.Model): #发帖表
__tablename__ = 'sent'
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)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
creat_time = db.Column(db.DateTime, default=datetime.now)
author = db.relationship('User', backref=db.backref('sent'))
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'))
sent_id = db.Column(db.Integer, db.ForeignKey('sent.id'))
creat_time = db.Column(db.DateTime, default=datetime.now)
detail = db.Column(db.TEXT, nullable=False)
sent = db.relationship('Sent', backref=db.backref('comment', order_by=creat_time.desc))
author = db.relationship('User', backref=db.backref('comment'))
db.create_all()
导航栏的html代码(用于其他网页的继承):
<!DOCTYPE html> <html lang="en"> <head> {% extends 'index.html' %} <meta charset="UTF-8"> <title> {% block title %} 登录页 {% endblock %}</title> {% block head %} <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> <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="{{ url_for('static',filename='javascript/dl.js') }}"></script> <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/dl.css') }}"> {% endblock %} </head> <body> {% block body %} <form action="{{ url_for('login') }}" method="post"> <div id="dljm" class="panel panel-info"> <h2 class="deng" class="panel-title">登陆</h2> <div id="nr" class="panel-body"> <div class="input_box"> Username:<input type="text" id="username" placeholder="请输入用户名" name="dlusername"> </div> <br> <div class="input_box"> Password: <input type="password" id="password" placeholder="请输入密码" name="dlpassword"> </div> <div class="error_box" id="error_box"><br></div> <div class="bt"> <button class="zhuce" onclick="fnLogin()">登录</button> </div> <br> <input type="radio" name="role" value="stu">学生 <input type="radio" name="role" value="tea">教师<br> <input type="checkbox" value="true"><span>记住我</span><br><a href="http://www.gzcc.cn/html/yonghufenglei/xuesheng/">登陆遇到问题</a><br> </div> </div> </form> {% endblock %} </body> </html>
首页的html代码:
<!DOCTYPE html> <html lang="en"> <head> {% extends 'index.html' %} <meta charset="UTF-8"> <title> {% block title %} 首页 {% endblock %}</title> {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/shouye.css') }}"> {% endblock %} </head> <body> {% block body %} <div style="margin-bottom:200px;" class="all"> {% for foo in username %} <div class="wai"> <li id="note-20391670" data-note-id="20391670" class="have-img"> <div class="content"> <div class="author"> <a class="avatar" target="_blank" href="/u/deeea9e09cbc"> <img class="img" src="//upload.jianshu.io/users/upload_avatars/1442902/b54c023e8862.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/64/h/64" alt="64"> </a> <div class="info"> <a class="nickname" href="{{ url_for('usercenter',user_id=foo.author_id,tag='wenda') }}">{{ foo.author.username }}</a> <span class="badge" data-shared-at="2017-11-30T08:15:03+08:00">{{ foo.creat_time }}</span> </div> </div> <a style="font-size: 20px" class="stitle" target="_blank" href="{{ url_for('detail',sent_id=foo.id) }}">{{ foo.title }}</a> <p class="abstract"> {{ foo.detail }}</p> {# <div class="meta">#} {# <a class="collection-tag" target="_blank" href="/c/1hjajt">{{ biaoqian }}</a>#} {# </div>#} {# <a href="{{ url_for('usercenter',user_id=foo.author_id,tag='wenda') }}">{{ foo.author.username }}评论({{ foo.comment|length }})</a>#} <a href="{{ url_for('detail',sent_id=foo.id) }}">评论({{ foo.comment|length }})</a> </div> </li> </div> {% endfor %} </div> <div style="margin-top:200px; padding-left:500px" class="lianjie"> <div class="img"> <a href="http://www.gzcc.cn/"><img src="http://www.005.tv/uploads/allimg/160428/13-16042Q43401629.jpg"></a> <div class="desc"><a href="http://www.gzcc.cn/">神奇奇闻</a></div> </div> <div class="img"> <a href="http://www.gzcc.cn/"><img src="http://www.deskier.com/uploads/allimg/170626/1-1F626213616.jpg"></a> <div class="desc"><a href="http://www.gzcc.cn/">神奇世界</a></div> </div> <div class="img"> <a href="http://www.gzcc.cn/"><img src="http://ww2.sinaimg.cn/large/9bfa86dcgw1f3zmypw1rwj21hc0u0765.jpg"></a> <div class="desc"><a href="http://www.gzcc.cn/">神奇宇宙</a></div> </div> <div class="img"> <a href="http://www.gzcc.cn/"><img src="http://www.005.tv/uploads/allimg/160428/13-16042Q43401629.jpg"></a> <div class="desc"><a href="http://www.gzcc.cn/">神奇问答</a></div> </div> </div> {% endblock %} </body> </html>
注册页面的代码:
<!DOCTYPE html> <html lang="en"> <head> {% extends 'index.html' %} <meta charset="UTF-8"> <title>{% block title %} 注册页 {% endblock %}</title> {% block head %} <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> <script src="{{ url_for('static',filename='javascript/zhuce.js') }}"></script> <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/dl.css') }}"> {% endblock %} </head> <body> {% block body %} <form action="{{ url_for('register') }}" method="post"> <div id="zcjm" class="panel panel-info"> <h2 class="deng" class="panel-title">注册</h2> <div id="nr2" class="panel-body"> <div class="input_box"> Username :<input type="text" id="username" placeholder="请输入你的用户名" name="username"> </div> <br> <div class="input_box"> Nickname :<input type="text" id="nickname" placeholder="请输入你的用户名" name="nickname"> </div> <br> <div class="input_box"> Userphone:<input type="text" id="userphone" placeholder="请输入你的手机号" name="userphone"> </div> <br> <div class="input_box"> Password : <input type="password" id="password" placeholder="请输入密码" name="password"> </div> <br> <div class="input_box"> Password : <input type="password" id="password2" placeholder="请再次输入密码"> </div> <div class="error_box" id="error_box"><br></div> <div class="bt"> <button class="zhuce" onclick="return fnzhuce()">注册</button> </div> </div> </div> </form> {% endblock %} </body> </html>
注册的js文件:
function fnzhuce() { var un = document.getElementById("username"); var us = document.getElementById("password"); var uE = document.getElementById("error_box"); var uP = document.getElementById("userphone"); var us2 = document.getElementById("password2"); var isE = true; uE.innerHTML = '<br>'; if (un.value.length < 6 || un.value.length > 20) { uE.innerHTML = "用户名必须在6-20个字符之间"; isE = false; return isE; } else if ((un.value.charCodeAt(0) >= 48) && (un.value.charCodeAt(0) <= 57)) { uE.innerHTML = "用户名首字母不能为数字"; isE = false; return isE; } else for (var i = 0; i < un.value.length; i++) { if (((un.value.charCodeAt(i) < 48) || (un.value.charCodeAt(i) > 57)) && ((un.value.charCodeAt(i) < 97) || (un.value.charCodeAt(i) > 122))) { uE.innerHTML = "用户名只能为数字或字母"; isE = false; return isE; } } for (var i = 0; i < 12; i++) { if (((uP.value.charCodeAt(i) < 48) || (uP.value.charCodeAt(i) > 57)) || uP.value.length != 11) { uE.innerHTML = "请输入正确手机号"; isE = false; return isE; } } if (us.value.length < 6 || us.value.length > 20) { uE.innerHTML = "密码必须在6-20个字符之间"; return false; } else for (var i = 0; i < us.value.length; i++) { if (us.value.charCodeAt(i) != us2.value.charCodeAt(i)) { uE.innerHTML = "密码不一致"; return false; } } return true; }
注册页面用到的函数:
@app.route('/register/', methods=['GET', 'POST'])
def register():
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')
userphone = request.form.get('userphone')
user = User.query.filter(User.username == username).first()
if user:
return "账户已存在"
else:
user = User(username=username, password=password, nickname=nickname, userphone=userphone)
db.session.add(user)
db.session.commit()
return redirect(url_for('login'))
登录页面代码:
<!DOCTYPE html> <html lang="en"> <head> {% extends 'index.html' %} <meta charset="UTF-8"> <title> {% block title %} 登录页 {% endblock %}</title> {% block head %} <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> <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="{{ url_for('static',filename='javascript/dl.js') }}"></script> <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/dl.css') }}"> {% endblock %} </head> <body> {% block body %} <form action="{{ url_for('login') }}" method="post"> <div id="dljm" class="panel panel-info"> <h2 class="deng" class="panel-title">登陆</h2> <div id="nr" class="panel-body"> <div class="input_box"> Username:<input type="text" id="username" placeholder="请输入用户名" name="dlusername"> </div> <br> <div class="input_box"> Password: <input type="password" id="password" placeholder="请输入密码" name="dlpassword"> </div> <div class="error_box" id="error_box"><br></div> <div class="bt"> <button class="zhuce" onclick="fnLogin()">登录</button> </div> <br> <input type="radio" name="role" value="stu">学生 <input type="radio" name="role" value="tea">教师<br> <input type="checkbox" value="true"><span>记住我</span><br><a href="http://www.gzcc.cn/html/yonghufenglei/xuesheng/">登陆遇到问题</a><br> </div> </div> </form> {% endblock %} </body> </html>
登录的js:
function fnLogin() { var un = document.getElementById("username"); var us = document.getElementById("password"); var uE = document.getElementById("error_box") var isE = true; uE.innerHTML = "<br>"; if (un.value.length < 6 || un.value.length > 20) { document.getElementById('error_box').innerHTML = "用户名必须在6-20个字符之间"; isE = false; return isE; } else if ((un.value.charCodeAt(0) >= 48) && (un.value.charCodeAt(0) <= 57)) { uE.innerHTML = "用户名首字母不能为数字"; isE = false; return isE; } else for (var i = 0; i < un.value.length; i++) { if (((un.value.charCodeAt(i) < 48) || (un.value.charCodeAt(i) > 57)) && ((un.value.charCodeAt(i) < 97) || (un.value.charCodeAt(i) > 122))) { uE.innerHTML = "用户名只能为数字或字母"; isE = false; return isE; } } if (us.value.length < 6 || us.value.length > 20) { document.getElementById('error_box').innerHTML = "密码必须在6-20个字符之间"; isE = false; return isE; } return isE; }
登录页面用到的函数:
@app.route('/login/', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('dl.html')
else:
username = request.form.get('dlusername')
password = request.form.get('dlpassword')
user = User.query.filter(User.username == username).first()
if user:
if user.check_password(password):
session['user'] = username
session.permanent = True
return redirect(url_for('base'))
else:
return '密码错误'
else:
return '用户不存在'
详情页面的html:
<!DOCTYPE html> <html lang="en"> <head> {% extends 'index.html' %} <meta charset="UTF-8"> <title> {% block title %} 详情 {% endblock %} </title> {% block head %} <link rel="stylesheet" href="../static/css/detail.css"> {% endblock %} </head> <body> {% block body %} <div class="all have-img"> <div class="container"> <div class="row clearfix"> <div class="col-md-12 column"> <div class="page-header"> <h3> 标题:{{ sen.title }} <br> <a href="{{ url_for('usercenter',user_id=sen.author_id,tag='wenda') }}"><small>作者:{{ sen.author.username }}</small></a> {# <a href="{{ url_for('detail',sent_id=foo.id) }}">评论({{ foo.comment|length }})</a>#} <small class="badge">时间:{{ sen.creat_time }}</small> </h3> </div> </div> </div> <div class="row clearfix"> <div class="col-md-12 column"> <p> {{ sen.detail }} </p> </div> </div> </div> <div> <form role="form" action="{{ url_for('comment') }}" method="post"> <textarea placeholder="写出你的评论" class="form-control" rows="10" id="comment" name="comment"> </textarea> <input type="hidden" name="sent_id" id="sent_id" value="{{ sen.id }}"> <div class="button"> <button type="submit">发布</button> </div> </form> </div> <div> <h4>评论:({{ sen.comment|length }})</h4> {% for foo in sen.comment %} <ul style="padding-left: 0px;margin-bottom: 0px;"> <li class="list-group-item" style="width: 900px"> <a href="{{ url_for('usercenter',user_id=foo.author.id,tag='wenda') }}">{{ foo.author.username }}</a> <span class="badge">评论时间:{{ foo.creat_time }}</span> <p>{{ foo.detail }}</p> </li> </ul> {% endfor %} </div> </div> {% endblock %} </body> </html>
详情页面的函数:
@app.route('/sent/', methods=['GET', 'POST'])
@loginFirst
def sent(): #发帖
if request.method == 'GET':
return render_template('sent.html')
else:
title = request.form.get('titleDetail')
detail = request.form.get('questionDetail')
author_id = User.query.filter(User.username == session.get('user')).first().id
sent = Sent(title=title, detail=detail, author_id=author_id)
db.session.add(sent)
db.session.commit()
return redirect(url_for('base'))
# return render_template('sent.html')
@app.route('/comment/', methods=['POST'])
@loginFirst
def comment(): #评论
comment = request.form.get('comment')
sent_id = request.form.get('sent_id')
auth_id = User.query.filter(User.username == session.get("user")).first().id
comm = Comment(author_id=auth_id, sent_id=sent_id, detail=comment)
db.session.add(comm)
db.session.commit()
return redirect(url_for('detail', sent_id=sent_id))
第二个同于继承的网页,用于个人中心页面:
<!DOCTYPE html> <html lang="en"> <head> {% extends 'index.html' %} <meta charset="UTF-8"> <title>{% block title %} 个人 {% endblock %}</title> {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/user.css') }}"> {% endblock %} </head> <body> {% block body %} <div class="all"> <ul class="nav_ul"> <li role="presentation" class="active"><a href="{{ url_for('usercenter' ,user_id=user.id,tag='wenda') }}">问答</a></li> <li role="presentation"><a href="{{ url_for('usercenter' ,user_id=user.id,tag='pinlun') }}">评论</a></li> <li role="presentation"><a href="{{ url_for('usercenter' ,user_id=user.id,tag='geren') }}">个人信息</a></li> </ul> </div> {% block user %}{% endblock %} {% endblock %} </body> </html>
个人中心的评论、问答、个人信息的html:
<!DOCTYPE html> #评论 <html lang="en"> <head> {% extends 'user.html' %} <meta charset="UTF-8"> <title>{% block title %} 评论 {% endblock %}</title> {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/geren.css') }}"> {% endblock %} </head> <body> {% block user %} <div class="all have-img"> {# {{ user.username }}#} <h4> <br> <small>全部评论</small> </h4> {% for foo in comment %} <ul style="padding-left: 0px;margin-bottom: 0px;"> <li class="list-group-item" style="width: 900px"> <a href="#">{{ foo.author.username }}</a> <span class="badge">评论时间:{{ foo.creat_time }}</span> <p>{{ foo.detail }}</p> </li> </ul> {% endfor %} </div> {% endblock %} </body> </html> <!DOCTYPE html> #问答 <html lang="en"> <head> {% extends 'user.html' %} <meta charset="UTF-8"> <title>{% block title %} 问答 {% endblock %}</title> {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/geren.css') }}"> {% endblock %} </head> <body> {% block user %} <div class="all have-img"> {#{{ username }}#} <h4> <br> <small>全部问答</small> </h4> {% for foo in sent %} <ul style="padding-left: 0px;margin-bottom: 0px;"> <li class="list-group-item" style="width: 900px"> <a href="">{{ foo.author.username }}</a> <span class="badge">评论时间:{{ foo.creat_time }}</span> <p>{{ foo.detail }}</p> </li> </ul> {% endfor %} </div> {% endblock %} </body> </html> <!DOCTYPE html> #个人中心 <html lang="en"> <head> {% extends 'user.html' %} <meta charset="UTF-8"> <title>{% block title %} 个人中心 {% endblock %}</title> {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/geren.css') }}"> {% endblock %} </head> <body> {% block user %} <div class="all have-img"> {# {{ user.username }}#} <h4> <br> <small>用户资料</small> </h4> <ul style="padding-left: 0px;margin-bottom: 0px;"> <li class="list-group-item" style="width: 900px">用户名:{{ username }}</li> <li class="list-group-item" style="width: 900px">用户编号:{{ user.id }}</li> <li class="list-group-item" style="width: 900px">昵称:{{ user.nickname }}</li> </ul> </div> {% endblock %} </body> </html>
个人中心调用的函数:
@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, 'sent': user.sent, 'comment': user.comment, 'user': user } if tag == 'wenda': return render_template('wenda.html', **context) elif tag == 'pinlun': return render_template('pinlun.html', **context) else: return render_template('GRZX.html', **context)
查找函数:
@app.route('/search/')
def search():
qu = request.args.get('q')
ques = Sent.query.filter(
or_(
Sent.title.contains(qu),
Sent.detail.contains(qu)
)
).order_by('creat_time')
return render_template('shouye.html', username=ques)