期末作品检查
1.个人学期总结
Python语言近些年越来越火,其特点是开发迅速,语法简单,可移植等。Python是一门面向对象的解释性语言(脚本语言),这一类语言的特点就是不用编译,程序在运行的过程中,由对应的解释器向CPU进行翻译,个人理解就是一边编译一边执行。而JAVA这一类语言是需要预先编译的。没有编译最大的痛苦就是无法进行断点调试,唯一的办法就是在有疑问的地方打印各个变量的值来进行调试。这一类语言也没用类型,也就是说一个变量即可能是int型,但是也可能是String型,而且可以随时变化。
Python对于代码格式要求也相当严格,通过对于缩进的距离来判断代码是否处于同一个代码块。这样做的好处在于代码编写看上去很统一。Python Web开发框架常用的包括Django,Flask,Tornado,Bottle等。Django功能比较全面,比较重,相对来说,Flask更加轻巧,适合新手学习和上手。Flask是一个基于Python的web框架,它的设计目的是提供Web开发所需的最小功能子集。Flask与别的框架(尤其是采用其他编程语言的框架)的不同之处在于:它没有绑定诸如数据库查询或者表单处理等功能库,以及它们所组成的整个生态系统。它倾向于对这些功能的实现方式不做任何限定。
本学期在老师的带领下,首先进行了一些python的基础练习,比如学习turtle库;条件、循环、函数的相关定义;字符串的基本操作;中英文词频统计的实例等。然后,开始学习做项目的前期准备工作,比如认识URL,观察常用网站网址,区分不同组成部分;学习HTML基础,练习使用标签制作简单的页面;结合实例,学习css样式的制作;学习JavaScript基础。接下来,就是开始做Flask项目了。
2.总结Python+Flask+MysqL的web建设技术过程
本学期实现了Python+Flask+Mysql的web建设技术的过程,以下是详细解析该技术的实现过程。
(1)父模板的制作
制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明等;汇总相关的样式形成独立的css文件;汇总相关的js代码形成独立的js文件;形成完整的base.html+css+js文件模式。
html
<body> <div class="dhl" > <div> <img src="http://p5.so.qhimgs1.com/bdr/_240_/t0121d7bb41fe5c36bb.jpg" width="100" height="70" > <a class="dhg" href="{{ url_for('index') }}">首页</a> {% if username %} <a class="dll" href="{{url_for('usercenter',user_id = session.get('userid'),tag=1)}}">{{ session.get('user') }}</a> <a class="dll" href="{{ url_for('logout') }}">注销</a> {% else %} <a class="dll" href="{{ url_for('ll') }}">登录</a> <a class="dll" href="{{ url_for('zc') }}">注册</a> {% endif %} <a class="dll" href="{{ url_for('question') }}" >问答</a> </div> <form action="{{url_for('search')}}" method="get" > <input name="q" type="text" cols="40" rows="1" class="soua" placeholder="请输入关键字"> <button type="submit" class="soub">查找</button> </form> </div> <div> <nav> <div class="hs"> <a href="">联系我们·</a> <a href="">加入我们·</a> <a href="">帮助中心</a> <p>版权 @ whl</p> </nav> </div>
css
body{ background-image: url(../imges/mao.jpg); background-size:cover; } .dll{ margin-top:10px; color:black; text-decoration:none; font-weight:bold; float:right; font-family: "宋体"; font-size: xx-large; } .dhg{ margin-top:120px; color:#C0C0C0; text-decoration:none; font-weight:bold; font-family: "隶书"; font-size:xx-large; } .dhl{ background-color: #FFFAFA; } .hs { width: 100%; height: 60px; color:#008080; background-color:none; position: fixed; bottom: 0; /**距离底部为0*/ left: 41%; z-index: 1; }
js
function myswitch() { var oBody = document.getElementById("myBody"); var oOnoff = document.getElementById("myOnOff"); if(oOnoff.src.match("bulbon")){ oOnoff.src="http://www.runoob.com/images/pic_bulboff.gif"; oBody.style.background="black"; oBody.style.color ="white"; }else{ oOnoff.src="http://www.runoob.com/images/pic_bulbon.gif"; oBody.style.background="white"; oBody.style.color ="black"; } }


(2)登录注册页面
1.完成登录与注册页面的HTML+CSS+JS,其中的输入项检查包括:1.用户名6-12位;2.首字母不能是数字;3.只能包含字母和数字;4.密码6-12位;5.注册页两次密码是否一致。
登录页面html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> <link href="../static/ll.css" rel="stylesheet" type="text/css"> <script src="../static/ll.js"></script> </head> <body> <div class="box"> <h2 class="d">登录</h2> <div class="input_box"> <input style="background-color: deepskyblue;" id="uname" type="text" placeholder="请输入用户名"> </div> <br> <div class="input_box"> <input style="background-color: deepskyblue;" id="upass" type="password" placeholder="请输入密码"> </div> <br> <div id="error_box"><br></div> <div class="input_box"> <button class="dl" onclick="fnLogin()">enter</button> </div> <br> </div> </div> </body> </html>
登录页面js
function fnLogin() { var oUname=document.getElementById("uname") var oUpass=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; }else if((oUname.value.charCodeAt(0)>=48) && (oUname.value.charCodeAt(0)<=57)){ oError.innerHTML="first.number." return; }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 = "only letter or number."; return; } } if(oUpass.value.length<6|| oUpass.value.length > 20){ oError.innerHTML="密码至少6-20位" return; } if((oUname.value.length < 6 || oUname.value.length > 20) && (oUpass.value.length < 6 || oUpass.value.length > 20)){ oError.innerHTML="用户名密码至少6-20位" return; } window.alert("登录成功!") }
注册页面html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <link href="../static/ll.css" rel="stylesheet" type="text/css"> </head> <body> <div class="box"> <h2 class="d">注册</h2> <div class="input_box"> <input style="background-color: deepskyblue;" id="uname" type="text" placeholder="请输入你的昵称"> </div> <br> <div class="input_box"> <input style="background-color: deepskyblue;" id="uname" type="text" placeholder="请输入你的密码"> </div> <br> <div class="input_box"> <input style="background-color: deepskyblue;" id="upass" type="password" placeholder="请再输入密码"> </div> <br> <div id="error_box"><br></div> <div class="input_box"> <button class="dl" onclick="fnLogin()">注册</button> </div> <br> </div> </div> </body> </html
注册页面js
function tnlogin() { var oUname = document.getElementById("uname") var oError = document.getElementById("error_box") var oUpass = document.getElementById("upass") var oUpass1 = document.getElementById("upass1") oError.innerHTML = "<br>" if (oUname.value.length < 6 || oUname.value.length > 20) { oError.innerHTML = "用户名必须在6-20之间"; return; } else if ((oUname.value.charCodeAt(0) >= 48) && (oUname.value.charCodeAt(0) <= 57)) { oError.innerHTML = "首字母不能为数字"; return; } 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; } } // oUpass if (oUpass.value.length > 20 || oUpass.value.length < 6) { oError.innerHTML = "密码必须在6-20之间"; return; } else if (oUpass.value!= oUpass1.value) { oError.innerHTML = "两次密码不一致" return; } window.alert("注册成功!") }
登录和注册页面的css
.d { font-size: 22px; padding-left: 40px; background:none; margin-right: 20px; color: #9932CC ; } .box{ align-content: center; background-color:#BBFFEE;height:250px;width:400px;float:left; text-align: center; vertical-align: middle; position: absolute; top: 50%; left: 50%; margin: -150px 0 0 -150px; border: 1px solid #ccc; width: 340px; } .input_box{ width: 325px; height: 40px; padding-left: 5px; padding-right: 5px; border: 1px #BBFFEE solid; border-radius: 4px; background: none; line-height: 40px; font-size: 14px; color: #6699FF; vertical-align: middle; } .dl { text-align: center; color: #9932CC; background: deepskyblue; width: 50%; padding: 9px 18px; font-size: 18px; border: none; border-radius: 25px; cursor: pointer; } .body { background-color: burlywood; }
2.登录和注册界面


(3)连接mysql数据库,创建用户模型。
1.在mysq中l创建数据库

2.数据库配置信息,创建config.py文件
import os DEBUG=True SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@127.0.0.1:3306/misdb?charset=utf8' SQLALCHEMY_TRACK_MODIFICATTONS = False SECRET_KEY=os.urandom(24)
3.建立mysql和app的连接
from flask import Flask from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app)
4.创建用户模型
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()
(4)完成登录功能
1.在主py文件定义注册和登录的视图函数。
登录按钮和注册按钮都得返回onclick="return myLogin(),return myregister()。 从flask中导入session、设置secret_key、操作字典一样操作session增加用户名`session['username']=`username。
//登录
@app.route('/ll/',methods=['GET','POST']) def ll(): if request.method=='GET': return render_template('ll.html') else: username=request.form.get('username') password1=request.form.get('password') user=User.query.filter(User.username==username).first() if user: if user.check_password(password1): session['user']=username session['userid'] = user.id session.permanent=True return redirect(url_for('index')) else: return u'error username or password' //注册 @app.route('/zc/',methods=['GET','POST']) def zc(): if request.method=='GET': return render_template('zc.html') else: username=request.form.get('username') password=request.form.get('password') user = User.query.filter(User.username==username).first() if user: return u'username existed' else: user = User(username=username, password= password) db.session.add(user) db.session.commit() return redirect(url_for('ll'))
2.登录之后更新导航
制作首页显示列表。
{% if username %} <a href="#">{{ username }}</a> <a href="{{ url_for('logout') }}">注销</a> {% else %} <a href="{{ url_for('login') }}">登录</a> <a href="{{ url_for('regist') }}">注册</a>
在主py文件中定义登出的视图函数。
@app.context_processor def mycontent(): usern=session.get('user') if usern: return{ 'username':usern } else: return{} @app.route('/logout/') def logout(): session.clear() return redirect(url_for('index'))
3.注销功能界面

(5)完成发布问答功能及其详情页。
1.问答html页面
<form action="{{ url_for('wd') }}" method="post"> <div class="label"> <h1 >发布问答</h1> <div class="form-group"> <label for="question">标题</label> <textarea id="question" cols="40" rows="1" placeholder="请输入标题" name='title'></textarea> </div> <div class="form-group"> <label for="questionDetail">内容</label> <textarea class="form-control" id="questionDetail" cols="50" rows="5" placeholder="请输入内容" name='detail'></textarea> </div> <br> <div class="input-area"> <button onclick="fnQuestion">发布问答</button> </div> </div> </body> </html> </form>
2.编写要求登录的装饰器,完成发布函数。
def loginFirst(func): @wraps(func) def wrapper(*args, **kwargs): if session.get('user'): return func(*args, **kwargs) else: return redirect(url_for('ll')) return wrapper @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'))
3.建立发布内容的对象关系映射
class Question(db.Model): __tablename__='wd' 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('wd')) db.create_all()
4.问答详情页html
<body> <div class="post"> <h3 class="title ">{{ques.title}}<br><small>{{ ques.author.username }}<span>{{ ques.create_time }} </span> </small></h3> </div> <p style="color: #333;">{{ ques.detail }}</p> <hr> <form action="{{ url_for('comment') }}"method="post"> <div class="new-comment"> <textarea name="new_comment" id="new-comment" cols="85" rows="5" placeholder="write your comment"></textarea> <input name="question_id" type="hidden" value="{{ ques.id }}" /> </div> <button class="btn-send" type="submit">发送</button> </form> <h4>评论:({{ ques.comment | length }})</h4> <ul class="list"> {% for foo in ques.comments %} <li class="post_item"> <a href="{{ url_for('usercenter',user_id=ques.author.id,tag=1) }}" class="light">{{foo.author.username }}</a> <br> <p class="post_item">{{ foo.detail }}</p> <span class="foot">发布于 {{ foo.create_time }}</span> </li> <hr>
5.定义详情页视图函数。
主PY文件写视图函数,带id参数。
@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)
6.问答页及其详情页的界面


(6)首页列表显示全部问答,完成问答详情页布局
1.首页列表显示全部问答
{% extends 'base.html' %} {% block title %} 首页 {% endblock %} {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/index.css') }}"> {# <p>{{ user }}context</p>#} {% endblock %} {% block main %} <img width="150" height="100" class="pfs" src="https://img3.doubanio.com/lpic/s7625404.jpg" alt=""> <ul class="list-group"> {% for foo in wd %} <li class="list-group-item"> <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span> <a href="{{ url_for('detail',question_id = foo.id)}}">{{foo.title}}</a> <p style="">{{foo.detail}}</p> <span class="glyphicon glyphicon-user" aria-hidden="true"></span> <a href="{{url_for('userconter',user_id = foo.author_id)}}">{{foo.author.username}}评论:({{foo.comments length}})</a> <span class="badge">{{foo.creat_time}}</span> </li> </ul> {% endblock %}
2.在首页点击问答标题,链接到相应详情页
@app.route('/')
def base():
context={
'questions': Question.query.all()
}
return render_template('home.html',**context)
3.首页界面

(7)完成评论功能。
1.建立评论的对象关系映射
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')) create_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')) db.create_all()
2.定义评论的视图函数,读取前端页面数据,保存到数据库中。
@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( detail=comment, question_id=ques_id,author_id=auth_id) db.session.add(comm) db.session.commit() return redirect(url_for('detail',question_id = ques_id))
3.尝试实现详情页面下的评论列表显示
<h4>评论:({{ ques.comment | length }})</h4> <ul class="list"> {% for foo in ques.comments %} <li class="post_item"> <a href="#" class="light">{{foo.author.username }}</a> <br> <p class="post_item">{{ foo.detail }}</p> <span class="foot">发布于 {{ foo.create_time }}</span> </li> <hr>
4.评论列表显示界面

(8)完成个人中心的页面布局
1.定义视图函数def usercenter(user_id)
@app.route('/usercenter/<user_id>/<tag>') @loginFirst def usercenter(user_id,tag): user=User.query.filter(User.id==user_id).first() context={ 'questions': user.question, 'comments': user.comments, 'user':user } 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)
2.个人中心html
{% extends'base.html' %} {% block title %}个人中心 {% endblock %} {% block head %} <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/detail.css') }}"> <style> .nav_ul li{ float: left; list-style: none; margin: 10px; border-bottom: outset; } </style> {% endblock %} {% block main %} <h3 class="title"><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ user.username }}</h3> <ul class="nav_ul"> <li role="presentation" class="active"><a href="{{ url_for('usercenter',user_id=user.id,tag= 1) }}" class="current_nav">全部问答</a> </li> <li role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag = 2) }}" class="current_nav">全部评论</a> </li> <li role="presentation"><a href="{{ url_for('usercenter',user_id=user.id,tag = 3) }}" class="current_nav">个人信息</a> </li> </ul> {% block user %}{% endblock %} {% endblock %}
3.新页面userbase.html,用<ul ><li role="presentation"> 实现标签页导航。
{% extends "base.html" %}
{% block title %}个人中心{% endblock %}
{% block head %}
<style>
.nav_ul li{
list-style: none;
float: left;
margin: 10px;
}
</style>
{% endblock %}
{% block main %}
<ul class="nav_ul">
<li role="presentation"><a href="{{url_for'usercenter',user_id = user.id }}">questions</a> </li>
<li role="presentation"><a href="#">comments</a> </li>
<li role="presentation"><a href="#">information</a> </li>
</ul>
{% block user %}{% endblock %}
{% endblock %}
4.实现点标签页导航到达不同的个人中心子页面
usercenter1.html
{% extends'usercenter.html' %} {% block user %} <div class="post"> <ul class="list"> {% for foo in questions %} <li class="post_item"> <p class="post_item">标题:{{ foo.title }}</p> <p class="post_item">内容:{{ foo.detail }}</p> <span class="foot">发布于 {{ foo.create_time }}</span> </li> <hr> {% endfor %} </ul> </div> {% endblock %}
usercenter2.html
{% extends'usercenter.html' %}
{% block user %}
<div class="post">
<ul class="list">
{% for foo in comments %}
<li class="post_item">
<p class="post_item">标题:{{ foo.detail }}</p>
<p class="post_item">评论:{{ foo.detail }}</p>
<span class="foot">发布于 {{ foo.create_time }}</span>
</li>
<hr>
{% endfor %}
</ul>
</div>
{% endblock %}
usercenter3.html
{% extends'usercenter.html' %}
{% block user %}
<div class="post">
<ul class="list">
<li class="post_item">用户:{{ username }}</li>
<li class="list-group-item">编号:{{userid}}</li>
<li class="list-group-item">问答条数:{{ questions|length }}</li>
<li class="list-group-item">评论条数:{{ comments|length }}</li>
</ul>
</div>
{% endblock %}
5.个人中心界面

(9)完成搜索功能
1.定义视图函数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('index.html',question = ques)
2.修改base.html 中搜索输入框所在的代码
<form action="{{url_for('search')}}" method="get" class="navbar-form navbar-left"> <input name="q" type="text" cols="40" rows="1" class="soua" placeholder="请输入关键字"> <button type="submit" class="soub">查找</button> </form>
3.实现搜索功能界面

(8)密码保护
1.实现密码保护功能
更新User对象,设置对内的_password;编写对外的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) nickname = db.Column(db.String(50)) db.create_all() @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
2.进行登录验证
@app.route('/ll/',methods=['GET','POST']) def ll(): if request.method=='GET': return render_template('ll.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('index')) else: return u'password error' else: return u'error username '
浙公网安备 33010602011771号