1.个人学期总结
2.总结Python+Flask+MysqL的web建设技术过程,标准如下:
- 即是对自己所学知识的梳理
- 也可作为初学入门者的简单教程
- 也可作为自己以后复习的向导
- 也是一种向外展示能力的途径
学习初期第一方面,我认为学习每一知识点的开始则是了解其知识点的概念及基础。首先则是认识URL,观察那些常用网站的网址,区分它们不同组成部分。然后,观察web的浏览过程。最后,最为重要的则是实操,了解HTML基础并联系使用标签制作最简单的页面。自行了解各个标签的用法以及整体标签的规范。第二方面,认识div块与form表单的作用,利用div块与form表单制作登录页面。同时,练习使用各种列表,例如下拉列表选择框、无序列表、有序列表以及定义列表。 观察常用网页的HTML元素,并在实操过程中,用已学的标签模仿制作。通过网络搜索补充自己所想要的知识点,不要仅仅依赖于课堂。
Python是一种面向对象的解释型计算机程序设计语言,Python是纯粹的自由软件, 源代码和解释器CPython遵循 GPL(GNU General Public License)协议。Python语法简洁清晰,特色之一是强制用空白符(white space)作为语句缩进。Flask是一个面向简单需求小型应用的“微框架(microframework)”,Flask选择组件的额外工作给那些使用案例不适用标准ORM的开发者提供了更多的灵活性,同样也给使用不同工作流和模版化系统的开发者们带来了灵活性。MySQL是一个关系型数据库管理系统,MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。
制作网页初期,应制作一个有主题性的导航条。首先认识HTML头部元素:<base> 定义了页面链接标签的默认链接地址;<style> 定义了HTML文档的样式文件;<link> 定义了一个文档和外部资源之间的关系。其次练习样式表:行内样式表;内嵌样式表;外部样式表。最后分别练习定义三类选择器:HTML 选择器;CLASS 类选择器;ID 选择器。
<nav> <div></div> </nav>
当制作出了导航条之后,则需要实现样式的美化,这就需要用到CSS知识点的运用。首先要认识CSS的 盒子模型。然后了解CSS选择器的灵活使用。CSS可以通过三种方式实现:第一,图片文字用div等元素布局形成HTML文件;第二,新建相应CSS文件,并link到html文件中;第三,在HTML中的head标签中使用style标签块进行布局美化。
<div> <div></div> <div>
了解了HTML基础以及CSS基础后,同时还需要了解JS基础。同CSS一样,<script></script>也存在三种用法:第一,放在<body>中;第二,放在<head>中;第三,放在外部JS文件中。同时还需要了解三种输出数据的方式:使用 document.write() 方法将内容写到 HTML 文档中;使用 window.alert() 弹出警告框;使用 innerHTML 写入到 HTML 元素(用 "id" 属性来标识 HTML 元素、用document.getElementById(id) 方法访问 HTML 元素、用innerHTML 来获取或插入元素内容)。
基础了解完后,则就开始了登录页面准备:通过JS语句增加错误提示框,并实现写好HTML+CSS文件,设置每个输入元素的id。定义JavaScript 函数,设置登录注册页面验证用户名与登录密码6-20位,注册还需包括验证用户名首字母不能是数字,只能包含字母和数字,输入的两次密码必须一致,并在各自html页面的button标签onclick调用这个函数。
function MyLogin() { //登录 var oUname=document.getElementById("uname"); var oUpass=document.getElementById("upass"); var oError=document.getElementById("errorbox"); //uname if(oUname.value=="Username"&&oUpass.value=="Password"){ oError.innerHTML="Please input username"; return; }else if(oUname.value.length<6||oUname.value.length>20){ oError.innerHTML="Username must be 6 to 20"; return; }else if(oUname.value.charCodeAt(0)>=48 && oUname.value.charCodeAt(0)<=57){ oError.innerHTML="Frist 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; } } //upass if(oUpass.value.length<6||oUpass.value.length>20) { oError.innerHTML = "Password must be 6 to 20"; return; } window.alert("Login Successful") } function MyRegister() { //注册 var oUname=document.getElementById("uname"); var oFUpass=document.getElementById("fupass"); var oSUpass=document.getElementById("supass"); var oError=document.getElementById("errorbox"); //uname if(oUname.value=="Username"&&oFUpass.value=="Password"&&oSUpass.value=="Password"){ oError.innerHTML="Please input username"; return; }else if(oUname.value.length<6||oUname.value.length>12){ oError.innerHTML="Username must be 6 to 12"; return; }else if(oUname.value.charCodeAt(0)>=48 && oUname.value.charCodeAt(0)<=57){ oError.innerHTML="Frist 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; } } //upass if(document.getElementById("fupass").value!=document.getElementById("supass").value){ oError.innerHTML="The password must be the same"; return; }else if(oFUpass.value.length<6||oFUpass.value.length>12) { oError.innerHTML = "Password must be 6 to 12"; return; } window.alert("Register Successful") }
实现完页面的设计后,新建Flask项目,实现功能的使用。设置调试模式,理解Flask项目主程序。使用装饰器,设置路径与函数之间的关系;使用Flask中render_template,用不同的路径,返回首页、登录员、注册页;再用视图函数反转得到URL,{{url_for(‘login’)}},完成导航条里的链接。
@app.route('/链接路径/')
def 函数名():
return render_template('register.html')
夜间模式的开启与关闭,放置点击的按钮或图片。定义script开关切换函数,用onclick函数进行调用。进行父模板的制作:制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明等。汇总相关的样式形成独立的css文件,汇总相关的js代码形成独立的js文件,使其形成完整的base.html+css+js项目。
function MySwitch() { var on_off=document.getElementById("on_off") if(on_off.src.match("on")){ on_off.src="../static/image/off1.PNG" document.getElementById("mybody").style.background="darkgray" }else{ on_off.src="../static/image/on1.PNG" document.getElementById("mybody").style.background="wheat" } }
用url_for加载静态文件,flask 从static文件夹开始寻找可用于加载css, js, image文件。实现继承和扩展把一些公共的代码放在父模板中,避免每个模板写同样的内容。子模板继承父模板,父模板提前定义好子模板可以实现一些自己需求的位置及名称,子模板中写代码实现自己的需求。
配置链接数据库信息,建立mysql和app的连接,创建用户模型。通过用户模型,学习对数据库进行增删改查操作。
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@localhost:3306/wuwen?charset=utf8' SQLALCHEMY_TRACK_MODIFICATIONS = False
class User(db.Model): __tablename__='user'
完成注册功能:实现js文件,onclick函数return True时才提交表单,return False时不提交表单。在主py文件定义函数,获取form中的数据且判断用户名是否存在:存在报错,若不存在则存进数据库中,redirect重定向到登录页。
@app.route('/regist/',methods=['GET','POST']) def regist(): if request.method == 'GET': return render_template("regist.html") else : username = request.form.get('username') password = request.form.get('password') user = User.query.filter(User.username == username).first() if user: return 'Username existed' else: user1 = User(username=username, password=password) db.session.add(user1) db.session.commit() return redirect(url_for('login'))
完成登录功能:与注册一样完成js文件,在主py文件定义函数,读取表单数据查询数据库。当用户名密码正确时,记住用户名并跳转到首页;当用户名密码不正确时,提示相应错误。同时,用session记住用户名。
def login(): if request.method=='GET': return render_template('login.html') else: username = request.form.get('username') password = request.form.get('password') user = User.query.filter(User.username==username).first() if user: if user.password==password: session['user'] = username session.permanent = True return redirect(url_for('base')) else: return 'Password error' else: return 'Username inexistent'
实现登录后更新导航:用上下文处理器app_context_processor定义函数,获取session中保存的值,返回字典。在父模板中更新导航,插入登录状态判断代码。注意用{% ... %}表示指令、{{ }}表示变量。完成注销功能:清除session并进行跳转页面。
@app.context_processor def mycontext(): usern=session.get('user') if usern: return {'username':usern} else: return {} @app.route('/logout/') def logout(): session.clear() return redirect(url_for('home'))
编写要求登录的装饰器,定义函数将其返回。应用装饰器,要求在发布前进行登录,登录后可发布。建立发布内容的对象关系映射,完成发布函数。
@app.route('/question/',methods=['GET','POST']) @loginFrist def question(): if request.method == 'GET': return render_template('question.html') else: title = request.form.get('title') detail = request.form.get('detail') user=User.query.filter(User.username == session.get('user')).first() author_id = user.id question = Question.query.filter(Question.title == title).first() if question: return 'Question existed' else: question1 = Question(title=title, detail=detail, author_id=author_id) question1.author = user db.session.add(question1) # 保存到数据库 db.session.commit() # 提交 return redirect(url_for('home')) def loginFrist(func): @wraps(func) def wrapper(*args,**kwargs): if session.get('user'): return func(*args,**kwargs) else: return redirect(url_for('login')) return wrapper
在首页添加显示问答的列表,并定义好相应的CSS样式。首页列表显示全部问答:将数据库查询结果传递到前端页面,前端页面循环显示整个列表,进行问答排序。
<ul > <li></li> </ul>
@app.route('/question/',methods=['GET','POST']) @loginFrist def question(): if request.method == 'GET': return render_template('question.html') else: title = request.form.get('title') detail = request.form.get('detail') user=User.query.filter(User.username == session.get('user')).first() author_id = user.id question = Question.query.filter(Question.title == title).first() if question: return 'Question existed' else: question1 = Question(title=title, detail=detail, author_id=author_id) question1.author = user db.session.add(question1) # 保存到数据库 db.session.commit() # 提交 return redirect(url_for('home')) @app.route('/detail/') def detail(): return render_template('detail.html')
主PY文件写视图函数,带id参数。 首页标题的标签做带参数的链接,在详情页将数据的显示在恰当的位置。建立评论的对象关系映射,尝试实现发布评论。
完成评论功能:定义评论的视图函数,读取前端页面数据,保存到数据库中。用<input type="hidden" 方法获取前端的"question_id" ,显示评论次数,要求评论前登录(调用登录装饰器),尝试实现详情页面下的评论列表显示。
@app.route('/comment/',methods=['POST']) @loginFirst def comment(): detail=request.form.get('detail') author_id = User.query.filter(User.username == session.get('user')).first().id question_id = request.form.get('question_id') comment = Comment(author_id=author_id,question_id=question_id,detail=detail) db.session.add(comment) # 保存到数据库 db.session.commit() # 提交 return redirect(url_for('detail',question_id=question_id))
实现评论列表显示及排序。完成个人中心:个人中心的页面布局(html文件及相应的样式文件),定义视图函数向前端页面传递参数,页面显示相应数据:发布的全部问答、发布的全部评论、个人信息;各个页面链接到个人中心。
实现标签页导航:利用嵌套继承,制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。个人中心—视图函数、导航标签与HTML页面链接增加tag参数。
@app.route('/usercenter/<user_id>/<tag>') @loginFirst def usercenter1(user_id,tag): user=User.query.filter(User.id==user_id).first() context={ 'user':user } if tag=='1': return render_template('userques.html',**context) elif tag=='2': return render_template('usercom.html', **context) else: return render_template('userinfo.html', **context) <a href="{{ url_for('usercenter1',user_id =session.get('id'),tag=1) }}" style="font-weight: 600">{{ username }}</a> <a href="{{ url_for('usercenter1',user_id=foo.author_id,tag=1) }}">{{ foo.author.username }}</a> <a href="{{ url_for('usercenter1',user_id=user.id,tag=1) }}"> {{ user.username }}</a>
实现搜索功能:准备视图函数search(),修改父模 中搜索输入框所在的;完成视图函数获取搜索关键字,条件查询并加载查询结果,实现组合条件查询。
@app.route('/search/') @loginFirst def search(): que=request.args.get('q') ques=Question.query.filter( or_( Question.title.contains(que), Question.detail.contains(que), ) ).order_by('-creat_time') return render_template('home.html',questions=ques)
最后实现密码保护功能。
@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
如此则完成了一集齐登录、注册、发布问答简单功能的web项目系统。