- 期末作品检查:基本要求
- 检查时间:18最后四节课,上课之前必须全部完成,上课做基本部署就开始检查
- 方式:逐个运行演示,抽查代码
- 主题:选一个主题,整个网站风格统一,布局合理,尽量美观。
- 期末作品检查:必须完成:
- 网站父模板统一布局:头部导航条、底部图片导航、中间主显示区域布局
- 注册、登录、注销
- 发布、列表显示
- 详情页
- 评论、列表显示
- 个人中心
- 搜索,条件组合搜索
- 一篇完整的博客
- 个人学期总结
- 总结Python+Flask+MysqL的web建设技术过程,标准如下:
- 即是对自己所学知识的梳理
- 也可作为初学入门者的简单教程
- 也可作为自己以后复习的向导
- 也是一种向外展示能力的途径
- 期末作品检查:加分功能
- 文章分类、显示
- 点赞、收藏
- 修改密码、头像、上传头像
- 我的
- 高级搜索
- 个人学期总结
经过一个学期的学习,在老师的教导之下,从一个连网页制作都不会的菜鸟,变成会用Python+Flask+MysqL的web建设技术来制作网页。
一开始是学习简单输入输出交互,算并输出两个数字之和,输入半径,计算圆的面积。到画圆,太阳花,同心圆画五角星,字符串基础操作,恺撒密码的编码,打出99乘法表,英文词频统计,用文件方式实现完整的英文词频统计,中文词频统计,datetime处理日期和时间,timestamp与timedelta,这些都是比较简单的,比较容易上手,逐渐的,web的基础,用html元素制作web网页,导航,css基础,图片导航块,到登录,登录和注册页面的前端验证再到连接myssql数据库,创建用户模型,对数据库进行增删改查操作,完成注册功能,登录后更新导航,发布功能,制作首页的显示列表,显示全部问答,完成问答详情页的布局,点击问答标题时跳转到相应的详情页,评论功能的实现,个人中心的显示,个人中心标签导航,搜索功能的实现,密码的保护等等。在学习的过程中发现了很多乐趣。
Python+Flask+MysqL的web建设技术过程:
首先是软件安装以及环境搭建,我使用的是pycharm这个软件来进行代码编写,数据库用的是Navicat for MySQL。还有装的python3以及MySQL 5.7 CommandLine Client 。
主py文件:
from flask import Flask, render_template, request, redirect, url_for, session from flask_sqlalchemy import SQLAlchemy import config,os from datetime import datetime from functools import wraps from sqlalchemy import or_,and_ from werkzeug.security import generate_password_hash,check_password_hash 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), 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 Wenda(db.Model): __tablename__ = 'wenda' 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('wenda')) 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')) wenda_id = db.Column(db.Integer, db.ForeignKey('wenda.id')) creat_time = db.Column(db.DateTime, default=datetime.now) detail = db.Column(db.Text, nullable=False) wenda = db.relationship('Wenda', backref=db.backref('comment',order_by=creat_time.desc)) author = db.relationship('User', backref=db.backref('comments')) db.create_all() #是否链接成功 # 数据添加 # user=User(username='ma',password='gg') # db.session.add(user) # db.session.commit() # # # 数据更新 # # user = User.query.filter(User.username=='hh').first() # user.password='gg' # db.session.commit() # # # 数据查询 # user = User.query.filter(User.username=='ma').first() # print(user.username,user.password) # # 数据删除 # user = User.query.filter(User.username=='ma').first() # db.session.delete(user) # db.session.commit() # session会话连接 # filter()过滤器 # route制定路径和函数之间的关系 # def定义一个变量 @app.route('/') def moban(): context = { 'wenda': Wenda.query.order_by('-creat_time').all() } return render_template('moban.html',**context) @app.route('/login/', methods=['GET', 'POST']) # 跳转登陆,methods定义它有两种请求方式 def login(): if request.method == 'GET': return render_template('login.html') else: username = request.form.get('user') password = request.form.get('psw') user = User.query.filter(User.username == username).first() # 判断用户名是否存在 if user: if user.check_password(password) : session['user']=username session['id']=user.id session.permanent = True return redirect(url_for('moban')) else: return '密码错误' else: return '用户名不存在' @app.context_processor def mycontext(): username=session.get('user') if username: return {'username':username} else: return {} def loginFirst(func): #参数是函数 @wraps(func) def wrapper(*args, ** kwargs): #定义个函数将其返回 if session.get('user'): return func(*args, ** kwargs) else: return redirect(url_for('login')) return wrapper #返回一个函数 @app.route('/register/', methods=['GET', 'POST']) # 跳转注册,methods定义它有两种请求方式 def register(): if request.method == 'GET': return render_template('register.html') else: username = request.form.get('user') password = request.form.get('psw') 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) db.session.add(user) db.session.commit() return redirect(url_for('login')) @app.route('/logout/') def logout(): session.clear() return render_template('moban.html') @app.route('/wenda/',methods=['GET', 'POST']) # 跳转注册,methods定义它有两种请求方式 @loginFirst def wenda(): if request.method == 'GET': return render_template('wenda.html') else: title = request.form.get('title') detail = request.form.get('detail') author_id = User.query.filter(User.username == session.get('user')).first().id wenda = Wenda(title = title,detail =detail,author_id = author_id) db.session.add(wenda) db.session.commit() return redirect(url_for('moban')) # @app.route('/comment/',methods=['GET', 'POST']) # 跳转注册,methods定义它有两种请求方式 # @loginFirst # def comment(): # if request.method == 'GET': # return render_template('comment.html') # else: # title = request.form.get('title') # detail = request.form.get('detail') # author_id = User.query.filter(User.username == session.get('user')).first().id # comment = Comment(title = title,detail =detail,author_id = author_id) # db.session.add(comment) # db.session.commit() # return redirect(url_for('detail')) @app.route('/detail?<wenda_id>',methods=['GET','POST']) def detail(wenda_id): wen = Wenda.query.filter(Wenda.id == wenda_id).first() comments=Comment.query.filter(Comment.wenda_id==wenda_id).all() return render_template('detail.html',wen=wen,comments=comments) @app.route('/usercenter/<user_id>/<tag>',methods=['GET','POST']) @loginFirst def usercenter(user_id,tag): user = User.query.filter(User.id==user_id).first() context ={ 'user':user, 'comments':user.comments, 'wendas':user.wenda } 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) @app.route('/search/') def search(): cha=request.args.get('q') chaxun=Wenda.query.filter( or_( Wenda.title.contains(cha), Wenda.detail.contains(cha) )).order_by('-creat_time') return render_template('moban.html',wenda=chaxun) @app.route('/comment/',methods=['GET','POST']) @loginFirst def comment(): comment = request.form.get('new_comment') wenda_id= request.form.get('wenda_id') author_id = User.query.filter(User.username == session.get('user')).first().id comm=Comment(author_id = author_id,wenda_id= wenda_id,detail=comment) db.session.add(comm) db.session.commit() return redirect(url_for('detail', wenda_id= wenda_id)) if __name__ == '__main__': app.run(debug=True)
manage.py文件:
from flask_script import Manager from flask_migrate import Migrate,MigrateCommand from untitled import app,db,User,Wenda,Comment manager = Manager(app) migrate = Migrate(app,db)#使用Migrate绑定aap和db manager.add_command('db',MigrateCommand) if __name__=='__main__': manager.run()
config.py文件:
debug = True SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:@localhost:3306/long?charset=utf8' SQLALCHEMY_TRACK_MODIFICATIONS=False import os SECRET_KEY=os.urandom(24)
父模板html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> 首页 {% block logintitle %}{% endblock %} {% block registertitle %}{% endblock %} {% block wendatitle %}{% endblock %} </title> {% block loginhead %}{% endblock %} {% block registerhead %}{% endblock %} {% block wendahead %}{% endblock %} <link rel="stylesheet" href="/static/css/meihua.css"/> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body id="myBody" style="background-color: lightcyan"> <nav> <img src="{{ url_for('static',filename='image/gzsxy.png') }}" width="2200px"> <br> <script> document.write(Date()) </script> <br> <a href="{{ url_for('moban') }}" style="color: orange">首页</a> {% if username %} <a href="{{ url_for('usercenter',user_id= session.get('id'),tag =1) }}" style="color: orange">{{ username }}</a> <a href="{{ url_for('logout') }}" style="color: orange">注销</a> {% else %} <a href="{{ url_for('login') }}" style="color: orange">登录</a> <a href="{{ url_for('register') }}" style="color: orange">注册</a> {% endif %} <a href="{{ url_for('wenda') }}" style="color: orange">问答</a> <form action="{{ url_for('search') }}" method="get"> <input name="q" type="text" placeholder="请输入关键字"> <button type="submit" style="color: orange">搜索</button> </form> </nav> <p style="color: gold">欢迎登陆{{ username }}</p> <div class="list_container"> <ul class="news-list"> {% for foo in wenda %} <li class="list-group-item"> <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span> <a href="{{ url_for('usercenter',user_id=foo.author_id,tag=3) }}" style="color: brown">{{ foo.author.username }}</a> <br> <a href="{{ url_for('detail',wenda_id= foo.id) }}" style="color: orange">{{ foo.title }}</a> <br> <span class="badge" style="color: mediumspringgreen">{{ foo.creat_time }}</span> <p style="color: magenta">{{ foo.detail }}</p> <span class="glyphicon glyphicon-user" aria-hidden="true"></span> </li> {% endfor %} </ul> </div> {% block loginbody %}{% endblock %} {% block registerbody %}{% endblock %} {% block wendabody %}{% endblock %} </body> </html> <style> div { border:5px solid #a1a1a1; padding:10px 10px; background:#dddddd; width:500px; border-radius:25px; } </style>
登录页面html:
{% extends 'moban.html' %} {% block logintitle %}欢迎来到登录界面,请登录{% endblock %} {% block loginhead %} {% endblock %} {% block loginbody %} <form action="{{ url_for('login') }}" method="post"> <script type="text/javascript" src="../static/js/login.js"></script> <div id="header" style="background-color: pink"><h2 align="center">登陆界面</h2></div> <div id="content"> <p align="center">用户名:<input id="uname" type="text" name="user" placeholder="请输入账号"> </p> <p align="center"> 密码:<input id="upass" type="password" name="psw" placeholder="请输入密码"></p> <input type="radio" value="stu">学生 <input type="radio" value="tea">老师 <br> <input type="checkbox" value="true">记住密码 <a href="">登陆遇到问题</a><br> <p align="center"> <button type="submit" onclick="return fnLogin()">登录</button> </p> </div> <div id="footer" style="background-color: pink"><h3 align="center">版权所有@</h3></div> {% endblock %}
注册页面html:
{% extends 'moban.html' %} {% block registertitletitle %}欢迎来到注册界面,请登录{% endblock %} {% block registerhead %}{% endblock %} {% block registerbody %} <form action="{{ url_for('register') }}" method="post"> <script type="text/javascript" src="../static/js/ma.js"></script> <div id="header" style="background-color: pink"><h2 align="center">注册界面</h2></div> <div id="content"> <p align="center">用户名:<input id="uname" type="text" name="user" placeholder="请输入账号"> </p> <p align="center"> 密码:<input id="upass" type="password" name="psw" placeholder="请输入密码"></p> <p align="center">密码:<input id="upass2" type="password" name="psw2" placeholder="请再次输入密码"></p> <input type="radio" value="stu">学生 <input type="radio" value="tea">老师 <br> <input type="checkbox" value="true">记住密码 <a href="">登陆遇到问题</a><br> <p align="center"><button type="submit" onclick=" return fnLogin()">注册</button></p> </div> </form> <div id="footer" style="background-color: pink"><h3 align="center">版权所有@</h3></div> {% endblock %}
登录/注册js:
function fnLogin() { var oUname = document.getElementById("uname") var oUpass = document.getElementById("upass") var oUpass2=document.getElementById("upass2"); var oError = document.getElementById("error_box") oError.innerHTML="<br>" if (oUname.value.length > 20 || oUname.value.length < 6) { oError.innerHTML = "请输入用户名6-20位字符" isErrer = false return isErrer; }else if ((oUname.value.charCodeAt(0)>=48)&&(oUname.value.charCodeAt(0)<=57)){ oError.innerHTML="用户名首字母必须是字母" isErrer = false return isErrer; }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="用户名必须为字母或数字"; isErrer = false return isErrer; } }
发布问答html:
{% extends 'moban.html' %} {% block wendatitle %}问答界面{% endblock %} {% block wendahead %}{% endblock %} {% block wendabody %} <form action="{{ url_for('wenda') }}" method="post"> <div class="from-group"> <label for="gb" style="color: orange"> 标题 </label><br> <textarea class="from-control" cols="50" rows="1" id="gb" name="title"></textarea> </div> <div class="from-group"> <label for="gb1" style="color: orange"> 详情</label><br> <textarea class="from-control" cols="50" rows="8" id="gb1" name="detail"></textarea><br> <button type="submit" style="color: orange">发布</button> </div> </form> {% endblock %}
问答详情html:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>详情页</title> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <a href="{{ url_for('moban') }}" style="color: orange">返回首页</a> <link rel="stylesheet" href="/static/css/meihua.css"/> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div> <h2 style="color: orange">{{ wen.title }} <small style="color: orange">{{ wen.author.username }}<span class="pull-center"><small style="color: orange"><br>{{ wen.creat_time }}</small></span> </small> </h2> <br> <p style="color: orange">{{ wen.detail }}</p> <form action="{{ url_for('comment')}}" method="post" style="margin: 20px;color: orange"> <div class="form-group"> <textarea name="new_comment" class="form-control" rows="6" id="new_comment" placeholder="请输入评论"></textarea> <input name="wenda_id" type="hidden" value="{{ wen.id }}"> </div> <button type="submit" class="btn btn-default" style="color: orange">发送</button> </form> </div> <h4 style="color: orange">评论:({{ wen.comment|length}})</h4> <div class="list-group"> {% for foo in comments %} <a href="" class="list-group-item active">作者:{{ foo.author.username }}</a> <div class="list-group-item "> <a href=""class="list-group-item-heading"></a> <p class="list-group-item-text">{{ foo.detail }}</p> </div> <div class="list-group-item"> <span class="badge">发布时间:{{ foo.creat_time }}</span> </div> {% endfor %} </div> </body> </html>
个人中心html:
<!doctype html> <html lang="en"> <head> <style> .nav_ul li { float: left; list-style: none; margin: 10px; border-bottom: outset; } </style> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>个人中心</title> <link rel="stylesheet" href="/static/css/meihua.css"/> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <ul class="nav_ul"> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=1) }}" style="color: orange">全部问答</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=2) }}" style="color: orange">全部评论</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=3) }}" style="color: orange">个人资料</a></li> <li role="presentation"><a href="{{ url_for('moban') }}" style="color: orange">返回首页</a></li> </ul> <br> {#<h2 >全部提问</h2>#} {#<div class="col-md-6 column ">#} {# <div class="page-header"> {% for foo in wenda %}#} {# <div class="panel panel-default">#} {# <div class="panel-heading">#} {# <br>#} {# <h3 class="panel-title">#} {# <a href="{{ url_for('detail',wenda_id=foo.id) }}">标题:{{ foo.title }}</a><br>#} {# </h3>#} {# <a href="{{ url_for('usercenter',user_id=foo.author_id) }}">作者:{{ foo.author.username }}</a>#} {# </div>#} {##} {# <div class="panel-body">#} {# <a href="#">内容:{{ foo.detail }}</a><br>#} {# </div>#} {# <div class="panel-footer">#} {# <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}发布时间</span>#} {# </div>#} {# </div>#} {# {% endfor %}#} {# </div>#} {#</div>#} {#<h2>全部评论</h2>#} {#<div class="col-md-6 column ">#} {# <div class="page-header">{% for foo in comments %}#} {# <li class="list-group-item">#} {# <a href="{{ url_for('usercenter',user_id=foo.author_id) }}">{{ foo.author.username }}</a>#} {# <span class="badge pull-right">{{ foo.create_time }}</span>#} {# <p>{{ foo.detail }}</p>#} {# <br>#} {# </li>#} {# </div>#} {# {% endfor %}#} {#</div>#} </body> </html>
<!doctype html> <html lang="en"> <head> <style> .nav_ul li { float: left; list-style: none; margin: 10px; border-bottom: outset; } </style> <style> div { border:5px solid #a1a1a1; padding:10px 10px; background:#dddddd; width:500px; border-radius:25px; } </style> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>个人中心</title> <link rel="stylesheet" href="/static/css/meihua.css"/> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <ul class="nav_ul"> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=1) }}" style="color: orange">全部问答</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=2) }}" style="color: orange">全部评论</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=3) }}" style="color: orange">个人资料</a></li> <li role="presentation"><a href="{{ url_for('moban') }}" style="color: orange">返回首页</a></li> </ul> <div class="group" style="clear:both"> <ul class="list-group"> {% for foo in wendas %} <li class="list-group-item"> <a href="#" style="color: brown">{{ foo.author.username }}</a> <a href="#" style="color: orange">{{ foo.author.title }}</a> <span class="badge"style="color: mediumspringgreen">{{ foo.creat_time }}</span> <p class="abstract" style="color: magenta">{{ foo.detail }}</p> </li> {% endfor %} </ul> </div> </body> </html>
<!doctype html> <html lang="en"> <head> <style> .nav_ul li { float: left; list-style: none; margin: 10px; border-bottom: outset; } </style> <style> div { border:5px solid #a1a1a1; padding:10px 10px; background:#dddddd; width:500px; border-radius:25px; } </style> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>个人中心</title> <link rel="stylesheet" href="/static/css/meihua.css"/> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <ul class="nav_ul"> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=1) }}" style="color: orange">全部问答</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=2) }}" style="color: orange">全部评论</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=3) }}" style="color: orange">个人资料</a></li> <li role="presentation"><a href="{{ url_for('moban') }}" style="color: orange">返回首页</a></li> </ul> <div class="page-header" style="clear:both"> {# <div id="content" style="height:800px;1500px;float:left;clear: both;text-align:center;">#} <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="#" style="color: brown">{{ foo.author.username }}</a> <span class="badge"style="color: mediumspringgreen">{{ foo.creat_time }}</span> <p style="align-content: center;color: pink">{{ foo.detail }}</p> </li> {% endfor %} </ul> </div> {# </div>#} </body> </html>
<!doctype html> <html lang="en"> <head> <style> .nav_ul li { float: left; list-style: none; margin: 10px; border-bottom: outset; } </style> <style> div { border:5px solid #a1a1a1; padding:10px 10px; background:#dddddd; width:500px; border-radius:25px; } </style> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>个人中心</title> <link rel="stylesheet" href="/static/css/meihua.css"/> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <ul class="nav_ul"> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=1) }}" style="color: orange">全部问答</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=2) }}" style="color: orange">全部评论</a></li> <li role="presentation"><a href="{{ url_for('usercenter',user_id= user.id,tag=3) }}" style="color: orange">个人资料</a></li> <li role="presentation"><a href="{{ url_for('moban') }}" style="color: orange">返回首页</a></li> </ul> <div class="page-header" style="clear:both"><br> {# <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ user }}<br><small>个人信息<span class="badge>"></span> </small> </h3>#} <ul class="list-group"> <li class="list-group-item" style="color: brown">用户:{{ username }}</li> <li class="list-group-item" style="color: brown">编号:</li> <li class="list-group-item" style="color: brown">昵称:</li> </ul> </div> </body> </html>