期末作品检查
一、个人学期总结
这学期刚开始接触到python,python的简洁,以及丰富的模块,广阔的应用领域吸引了我。学习python以来,觉得python还是比较简单,容易上手的,就基本语法而言,但是有些高级特性掌握起来还是有些难度,需要时间去消化。python给我最大的印象就是语法简洁,就像写伪代码一样,很多其他语言要用很多行才能实现的操作python可能几行就搞定了,这让人摆脱了繁杂的语法而专注于问题本身,这也正是我为什么不太喜欢Java的原因之一,虽然它很强大。
刚开始学习很多疑惑,到底该如何学python,该从何下手?我回想了一下,根据自己的个人经验,总结了一下。首先,学习一门语言,语言基础很重要,我们需要了解该语言的特性,以及所有的语法规则,关键词等内容,所以,我们需要先把python基础过一遍,我建议去菜鸟教程去过一遍,这里不是广告,只是本人一般都在菜鸟官方看各种语言的编程入门。在基础学习的过程中,我建议快速的过一遍,把能理解的理解消化掉,比较难理解的不要浪费太多的时间去揣摩,因为有些语法或者特性在基础学习中根本不能很好的展示,没有实际操作单靠文字描述,是很难理解,死记硬背下来的东西不利于长期记忆和使用,所以快速浏览一遍,真正的学习放到后面的模块学习和项目实战,在模块学习和实战操作中能看到实实在在的执行效果,更利于理解。
总的来说,这个学期学习到了这么有趣的网页制作,不过现在本人的经验还是匮乏,只是学习到简单的基础知识,还应该继续加强学习,让自己的网页布局更加美化。在这里还要感谢老师这一学期的指导,让我们了解到python的奥妙。
二、总结Python+Flask+MysqL的web建设技术过程
- 所需工具: pycharm64.exe + Python 3.6 64-bit + MySQL + Navicat for MySQL
 - 在自己所在的项目创建py文件、 html文件、css文件、js文件,如下图:
 

(1)主py 文件所需库
from flask import Flask,render_template,request,redirect,url_for,session from flask_sqlalchemy import SQLAlchemy from datetime import datetime from functools import wraps import config from sqlalchemy import or_ from werkzeug.security import generate_password_hash,check_password_hash
(2)创建数据库
A、数据库连接,创建数据库,配置链接数据库信息,建立mysql和app的连接。
import os SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/mis_db?charset=utf8' SQLALCHEMY_TRACK_MODIFICATIONS = False SECRET_KEY = os.urandom(24)
app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app)
B、创建用户模型。
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(20)) @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 Question(db.Model): __table__name = 'question' 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('question')) 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')) detail = db.Column(db.Text,nullable=False) creat_time = db.Column(db.DateTime,default=datetime.now) question = db.relationship('Question', backref=db.backref('comments')) author = db.relationship('User', backref=db.backref('comments')) #db.create_all()
C、通过用户模型,学习对数据库进行增删改查操作。
#增 user = User(username='su0001',password='123456') db.session.add(user) db.session.commit() #改 user=User.query.filter(User.username=='su0002').first() user.password='1234567' db.session.commit() #删 user=User.query.filter(User.username=='su0002').first() db.session.delete(user) db.session.commit() #查 user=User.query.filter(User.username=='su0001').first() print(user.id,user.password)
#增、改
#删、查
 
    
D、实现密码保护功能

(3)页面设计
A、网站父模板统一布局:头部导航条、底部图片导航、中间主显示区域布局
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}Title</title> <link rel="stylesheet"type="text/css"href="{{ url_for('static',filename='css/base.css') }}"> <script src="{{ url_for('static',filename='js/base.js') }}"></script> <base target="_blank" /> {% block head %}{% endblock %} </head> <body background="http://p0.so.qhimgs1.com/t01d2e82c8c8f2be36c.jpg" id="myBody"> <nav class="nav"> <ul> <li><a href="{{ url_for('index') }}"><img src="../static/images/img1.png">首页</a></li> <li><a href=""><img src="../static/images/img2.png">下载</a></li> <li><a href="{{ url_for('question') }}"><img src="../static/images/img5.png">发布问答</a></li> <div> {% if user %} <li><a href="{{ url_for('userbase',user_id = session.get('userid'),tag = 1) }}"><img src="../static/images/img3.png">{{ session.get('user') }}</a></li> <li><a href="{{ url_for('logout') }}"><img src="../static/images/img4.png">注销</a></li> {% else %} <li><a href="{{ url_for('login') }}"><img src="../static/images/img3.png">登录</a></li> <li><a href="{{ url_for('regist') }}"><img src="../static/images/img4.png">注册</a></li> {% endif %} </div> <form action="{{ url_for('search') }}" method="get" class="navbar-form navbar-left"> <img class="on_off" id="on_off" onclick="mySwitch()" src="../static/images/pic_bulbon.gif" width="50px"> <button style="float: right;margin: 5px auto;border-radius: 5px;height: 26px" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span>搜索</button> <input style="float: right;margin: 5px auto;border-radius: 8px;width: 200px;height: 20px;" type="text"name="q" placeholder="输入请关键字"> </form> </ul> </nav> <div id="bottom"> <a href="">关于我们</a> <a href="">意见反馈</a> <a href="">安全保障</a> </div> <div class="copyright"> <p>Copyright © 2017. Created by <a href="#" target="_blank">suxihong</a></p> </div> {% block main %}{% endblock %} </body> </html>


夜间模式的开启与关闭。定义script开关切换函数,用onclick函数进行调用。
     
B、注册、登录、注销py文件:
注册界面完成注册功能。在主py文件定义函数,获取form中的数据且判断用户名是否存在:存在报错,若不存在则存进数据库中,redirect重定向到登录页。
登录界面。完成登录功能:与注册一样完成js文件,在主py文件定义函数,读取表单数据查询数据库。当用户名密码正确时,记住用户名并跳转到首页;当用户名密码不正确时,提示相应错误。同时,用session记住用户名。
#登录函数 @app.route('/login/',methods=['GET','POST']) def login(): if request.method == 'GET': return render_template('login.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 'password error' else: return 'username error' #注册函数 @app.route('/regist/',methods=['GET','POST']) def regist(): if request.method == 'GET': return render_template('regist.html') else: username = request.form.get('username') nickname = request.form.get('nickname') password = request.form.get('password') user = User.query.filter(User.username == username).first() if user: return 'username existed.' 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 redirect(url_for('index')) # 行动前需要登录,定义装饰器 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
定义JavaScript 函数,设置登录注册页面验证用户名与登录密码6-20位,注册还需包括验证用户名首字母不能是数字,只能包含字母和数字,输入的两次密码必须一致,并在各自html页面的button标签onclick调用这个函数。实现js文件,onclick函数return True时才提交表单,return False时不提交表单。
1)regist.html
{% extends 'base.html' %} {% block title %}Regist{% endblock %} {% block head %} <link href="{{ url_for('static',filename='css/js31.css') }}" rel="stylesheet" type="text/css"> <script src="{{ url_for('static',filename='js/regist.js') }}"></script> {% endblock %} {% block main %} <div class="box"> <h2>注册页面</h2> <form action="{{ url_for('regist') }}" method="post"> <div class="input_box"> 输入用户名: <input id="uname" type="text" placeholder="请输入用户名" name="username"></div> <div class="input_box"> 昵称:<input id="unickname" type="text" placeholder="昵称" name="nickname"> </div> <div class="input_box"> 输入密码: <input id="upass" type="password" placeholder="请输入密码" name="password"></div> <div class="input_box"> 确认密码: <input id="checkpass" type="password" placeholder="请确认密码"> </div> <div id="error_box"><br></div> <div class="input_box"> <button onclick="fnRegist()">注册</button> <button onclick=window.alert("此页面询问您是否要离开:您输入的数据可能不会被保存")>取消</button></div> </form> </div> {% endblock %}
rejist.js
function fnRegist() { var oPass=document.getElementById("upass").value; var oPass1=document.getElementById("checkpass").value; if(oPass!=oPass1){ document.getElementById("error_box").innerHTML="两次密码不一致!"; return false; } return true; }
2)login.html
{% extends 'base.html' %}
{% block title %}欢迎您的登录{% endblock %}
{% block head %}
    <link href="{{ url_for('static',filename='css/js31.css') }}" rel="stylesheet" type="text/css">
    <script src="{{ url_for('static',filename='js/login.js') }}"></script>
{% endblock %}
{% block main %}
    <div class="box">
            <h2>登录页面</h2>
            <form action="{{ url_for('login') }}" method="post">
            <div class="input_box">
               用户名: <input id="uname" name="username" type="text" placeholder="请输入用户名">
        </div>
             <div class="input_box">
                密码: <input id="upass" name="password" type="password" placeholder="请输入密码">
             </div>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button onclick="return fnLogin()">登录</button>
            <button onclick=window.alert("此页面询问您是否要离开:您输入的数据可能不会被保存")>取消</button></div>
            </form>
    </div>
{% endblock %}
login.js
function fnLogin() {
    var oUname=document.getElementById("uname");
    var oUpass=document.getElementById("upass");
    var oError=document.getElementById("error_box");
    var isError=true;
    oError.innerHTML="<br>";
    if(oUname.value.length<6||oUname.value.length>20){
        oError.innerHTML="用户名的长度:6-20位";
        isError=false;
        return isError;
    }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) < 97 || oUname.value.charCodeAt(i) > 122)) {
                oError.innerHTML = "只能包含字母或数字。";
                isNotError = false;
                return isError;
            }
        }
    }
    if (oUpass.value.length<6||oUpass.value.length>20){
        oError.innerHTML="密码的长度:6-20位";
        isError=false;
        return isError;
    }
    return isError;
}
  
实现登录后更新导航:用上下文处理器app_context_processor定义函数,获取session中保存的值,返回字典。在父模板中更新导航,插入登录状态判断代码。注意用{% ... %}表示指令、{{ }}表示变量。完成注销功能:清除session并进行跳转页面。
@app.context_processor
def mycontext():
    user = session.get('user')
    if user:
        return {'user': user}
    else:
        return {}
        
C、发布、列表显示
1)发布问答界面、编写要求登录的装饰器,定义函数将其返回。应用装饰器,要求在发布前进行登录,登录后可发布。建立发布内容的对象关系映射,完成发布函数。
@app.route('/question/',methods=['GET','POST'])
@loginFirst   # 把loginFirst放在要登录才能进入的界面中
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:
            question = Question(title=title, detail=detail, author_id=author_id)
            question.author = user
            db.session.add(question)    # 数据库,添加操作
            db.session.commit()
            return redirect(url_for('index'))
question.html
{% extends 'base.html' %} {% block title %}发布问答{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/question.css')}}"> {% endblock %} {% block main %} <div class="question"> <p class="name">欢迎你,{{ user }}</p> <h3>发布问答</h3> <form class="box" action="{{ url_for('question') }}" method="post" > <div class="form-group"> <label for="questionTitle">标题</label> <input type="text" name="title" class="form-control" id="questionTitle" placeholder="输入标题"> </div> <div class="form-group"> <label for="questionDetail">详情</label> <textarea name="detail" class="form-control" rows="5" id="questionDetail" placeholder="输入内容"></textarea> </div> <div class="checkbox"> <label> <input type="checkbox">Check me out </label> </div> <button type="submit" class="btn-default">发布</button> </form> </div> {% endblock %}
  
2)在首页添加显示问答的列表,并定义好相应的CSS样式。首页列表显示全部问答:将数据库查询结果传递到前端页面,前端页面循环显示整个列表,进行问答排序。
@app.route('/')
def index():
    context = {
          'question': Question.query.order_by('-creat_time').all()
    }
    return render_template('index.html',**context)
index.html
{% extends 'base.html' %} {% block title %}首页{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}" type="text/css"> {% endblock %} {% block main %} <p>{{ user }}欢迎您来到首页!</p> <div class="list-container"> <div id="content"> <ul class="note-list" style="list-style: none"> {% for foo in question %} <li class="note-list-item"> <span class="glyphion glyphion-leaf" aria-hidden="true"></span> <a href="{{ url_for('detail',question_id = foo.id)}}">{{ foo.title }}</a> <p style="width: 450px;"> 详情 {{ foo.detail }}</p> <span class="glyphion glyphion-user" aria-hidden="true"></span> <a href="{{ url_for('userbase',user_id = foo.author_id,tag = 1)}}">{{ foo.author.username }} 评论:({{ foo.comments|length }})</a> <span class="badge">{{ foo.creat_time }}</span> </li> {% endfor %} </ul> </div> </div> {% endblock %}
3)主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)
@app.route('/comment/',methods=['POST'])
@loginFirst   #把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(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))
detail.html
{% extends 'base.html' %} {% block title %}问答详情{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/detail.css')}}"> {% endblock %} {% block main %} <div class="detail"> <h3 >{{ ques.title }} <small>{{ ques.author.username }} <span class="badge">{{ ques.creat_time }}</span> </small> </h3> <p class="lead" >详情 {{ ques.detail }}</p> <hr> <form action="{{ url_for('comment') }}" method="post" class="box"> <div class="form-group"> <textarea name="new_comment" class="form-control" rows="5" id="new_comment" placeholder="write your comment"></textarea> <input name="question_id" type="hidden" value="{{ ques.id }}" /> </div> <button type="submit" class="btn-default">发送</button> <br> <hr> <div class="form-group"> <h4>评论:({{ ques.comments|length }})</h4> <ul class="list-group" style="list-style: none"> {% for foo in ques.comments %} <li class="list-group-item"> <span class="glyphion glyphion-heart-empty" aria-hidden="true"></span> <a href="{{ url_for('userbase',user_id = foo.author.id,tag = 1)}}">{{ foo.author.username }}</a> <span class="badge">{{ foo.creat_time }}</span> <p style="width: 450px;"> 详情 {{ foo.detail }}</p> </li> {% endfor %} </ul> </div> </form> </div> {% endblock %}


D、个人中心:实现评论列表显示及排序。完成个人中心:个人中心的页面布局(html文件及相应的样式文件),定义视图函数向前端页面传递参数,页面显示相应数据:发布的全部问答、发布的全部评论、个人信息;各个页面链接到个人中心。
实现标签页导航:利用嵌套继承,制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。个人中心—视图函数、导航标签与HTML页面链接增加tag参数。
@app.route('/userbase/<user_id>/<tag>')
@loginFirst
def userbase(user_id,tag):
    user = User.query.filter(User.id == user_id).first()
    mycontext = {
        'user': user,
        #'user_name': user.username,
        #'questions': user.question,
        #'comments': user.comments
    }
    if tag == '1':
        return render_template('user1.html', **mycontext)
    elif tag == '2':
        return render_template('user2.html', **mycontext)
    else:
        return render_template('user3.html', **mycontext)
userbase.html
{% extends 'base.html' %} {% block title %}个人中心{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}"> {% endblock %} {% block main %} <div id="content"> <ul class="nav_ul" style="list-style:none;float:left"> <li role="presentation"><a href="{{ url_for('userbase',user_id = user.id,tag = '1') }}">全部问答</a></li> <li role="presentation"><a href="{{ url_for('userbase',user_id = user.id,tag = '2') }}">全部评论</a></li> <li role="presentation"><a href="{{ url_for('userbase',user_id = user.id,tag = '3') }}">个人信息</a></li> </ul> </div> {% block user %}{% endblock %} {% endblock %}
use1.html
{% extends 'userbase.html' %} {% block title %}全部问答{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}"> {% endblock %} {% block user %} <div class="list-container"> <ul class="note-list" style="list-style: none"> {% for foo in user.question %} <li class="note-list-item"> <span class="glyphion glyphion-leaf" aria-hidden="true"></span> <a href="{{ url_for('detail',question_id = foo.id)}}">{{ foo.title }}</a> <p style="font-family: 幼圆;color: black;"> 详情 {{ foo.detail }}</p> <span class="glyphion glyphion-user" aria-hidden="true"></span> <a href="{{ url_for('userbase',user_id = foo.author_id,tag = 1)}}">{{ foo.author.username }}</a> <span class="badge">{{ foo.creat_time }}</span> </li> {% endfor %} </ul> </div> {% endblock %}
user2.html
{% extends 'userbase.html' %} {% block title %}全部评论{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}"> {% endblock %} {% block user %} <div class="list-container"> <h3 style="font-family:幼圆 ;color:black;width:100px"><span class="glyphion glyphion-user" aria-hidden="true"></span>{{ username }} <br><small>全部评论 <span class="badge"></span></small> </h3> <ul class="list-group" style="margin: 10px;list-style: none"> {% for foo in user.comments %} <li class="note-list-item"> <span class="glyphion glyphion-haert-empty" aria-hidden="true"></span> <a href="#">{{ foo.author.username }}</a> <span class="badge">{{ foo.creat_time }}</span> <p style="font-family: 幼圆;color: black;"> 详情 {{ foo.detail }}</p> </li> {% endfor %} </ul> </div> {% endblock %}
user3.html
{% extends 'userbase.html' %} {% block title %}个人信息{% endblock %} {% block head %} <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css')}}"> {% endblock %} {% block user %} <div class="list-container"> <h3><span class="glyphion glyphion-user" aria-hidden="true"></span>{{ username }} <br><small>个人信息 <span class="badge"></span></small> </h3> <ul class="list-group" style="margin: 10px;list-style: nonefont-family: 幼圆;color:black;"> <li class="list-group-item">用户:{{ user.username}}</li> <li class="list-group-item">编号:{{ user.id }}</li> <li class="list-group-item">昵称:{{ user.nickname}}</li> <li class="list-group-item">文章篇数:{{ user.question|length }}</li> <li class="list-group-item">评论数:{{ user.comments|length }}</li> </ul> </div> {% endblock %}
 


E、搜索,条件组合搜索:实现搜索功能:准备视图函数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('-creat_time')
    return render_template('index.html',question = ques)
  
  
                    
                
                
            
        
浙公网安备 33010602011771号