期末作品检查

  1. 个人学期总结

      在这个学期里,在老师带领下,我们学习了管理信息系统这门课程。由一开始懵懵懂懂的概念知识到后面基本熟悉的上机操作,这都离不开老师对我们一步步的指导。在这个课程中我发现,跟随老师的步伐,做出一个界面并不代表什么,而是需要课后多加熟悉,上手操作,才能算是掌握这门课程的核心。

      在一开始接触Python,我们首先是做了一系列的基础练习,例如:简单输入输出交互、用户输入两个数字,计算并输出两个数字之和、输入半径,计算圆的面积等等一系列的简单代码训练,然后了解turtle库(海龟库)并在这个环境下进行基础训练,画出同切圆、同心圆、五角星,在慢慢由浅及深画黄色实心五角星、最后画国旗等等。再慢慢地由简单的多句代码实现绘画到利用条件、循环、函数定义减少代码数量实现绘画,其实就是利用简单的例子让我们熟悉Python环境,并从中学习到一些Python语言。接着就开始进行字符串的基本操作、凯撒密码、自制九九乘法表等等,再让我们进行中英文词频统计等组合数据类型练习。最后利用datetime处理日期和时间,将字符串转化成imestamp与timedelta,同时了解管理信息系统概念与基础,理解数据存储的方式如字典、列表、元祖、集合,了解到与Web相关的一些基础知识。让我们再简单的例子中熟悉并对Python产生兴趣,也在一些简单的例子里为之后的网页制作打下良好的基础。

      在中期,我们开始Web的各种练习,首先进行Web的基础训练,练习使用标签制作简单的页面。然后开始用div,form制作登录页面,练习使用下拉列表选择框,无序列表,有序列表,定义列表。也开始制作自己喜欢的导航条,其中包含HTML头部元素:<base>  定义了页面链接标签的默认链接地址、<style>  定义了HTML文档的样式文件、<link>  定义了一个文档和外部资源之间的关系;各种样式表;还有三类样式表。还有开始学习初步运用css做图片导航块,使用JS定义函数进行登录注册验证,完成登录与注册页面的前端HTML设计。到后面就开始了Flask框架制作网页的学习。

      在开始Flask项目开始后,我们学习了夜间模式的开启与关闭、父模板的制作,制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航等形成完整的一个html+css+js,把一些公共的代码放在父模板中,避免每个模板写同样的内容;然后学习了用url_for加载静态文件,用 render_template,用于创建一个Flask对象以及页面的跳转,进行父模板的继承和扩展,实现自己代码的需求。然后就开始安装与配置python3.6+flask+mysql数据库,建立mysql和app的连接,引入flask_sqlalchemy库进行数据库的关联映射,创建用户模型,对数据库进行增删改查操作。完成注册功能,将页面的数据存到数据库,redirect重定向登录页;完成登录功能,用session记住用户名,像操作字典一样操作‘session’:增加用户名‘session[‘username’]’=username。登录之后更新导航,用上下文处理器app_context_processor定义函数,获取session中保存的值,返回字典,在父模板中更新导航,插入登录状态判断代码。让登录后的导航显示登录用户的名字。接着完成注销功能,清除session。让注销后的导航栏上返回原来模样。后面完善发布功能,添加装饰器,需要用户发布前进行登录操作,登录后方可发布。建立发布内容的对象关系映射:class Question(db.Model),完成发布函数。把发布内容保存到数据库。然后返回到首页。然后制作首页的显示列表,数据库查询结果传递到前端页面 Question.query.all(),前端页面循环显示整个列表。完成问答详情页布局: 包含问答的全部信息评论区以往评论列表显示区。在首页点击问答标题,链接到相应详情页。做出一个整体框架后,我们开始完善里面的内容,显示评论次数、要求评论前登录、 尝试实现详情页面下的评论、密码保护、实现标签页导航等。后面基本上都是在完善这个项目了。

      在这一整个学期的学习过程中,也会遇到许许多多的问题,例如一开始怎么也把东西存放不进数据库,后来在一步步检查才发现没有在HTML中加上<from>标签;还有在某个单词拼写错误,在html里会用颜色的不同来报错,这种情况还较好处理,但在JS代码中是不会提示你哪里出错,所以在编写过程中要多加细心谨慎。还有在夜间模式里的JS文件中的两张图片的后缀不一样,但是在代码中后缀写的又是相同的,这样就不成功了。类似这种小错误还有很多,这就告诉我们在写代码的时候一定要细心谨慎,要多加检查。其实在每一个功能可以实现的时候,自己的成就感油然而生,所以我们多去练习多去运用,少用复制粘贴、投机取巧,我们才能在编程道路上越走越远。

2、总结Python+Flask+MysqL的web建设技术过程

在这学期里,我学习了使用Python的Flask框架+MysqL搭建简单的web项目,实现了具有登录注册发布评论功能等的简单页面。以下是我这学期的学习成果和学习经验:

1、开始新建Flask项目

① 新建Flask项目。② 设置调试模式。③ 理解Flask项目主程序。④ 使用装饰器,设置路径与函数之间的关系。⑤ 使用Flask中render_template,用不同的路径,返回首页、登录员、注册页

复制代码
from flask import Flask,render_template

app = Flask(__name__)


@app.route('/')
def sy():
    return render_template('sy.html')

@app.route('/dl/')
def dl():
    return render_template('dl.html')

@app.route('/zc/')
def zc():
    return render_template('zc.html')

if __name__ == '__main__':
    app.run(debug=True)
复制代码

2、连接数据库

① 数据库配置信息config.py② 建立mysql和app的连接③ 创建用户模型

config.py:

import os

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/dianying?charset=utf8'
SQLALCHEMY_TRACK_MODIFICATIONS = False

SECRET_KEY = os.urandom(24)

建立连接+创建模型:

复制代码
from flask import Flask,request,render_template,redirect,url_for,session
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from sqlalchemy import or_,and_
from functools import wraps
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)




class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer,primary_key=TabError,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    _password = db.Column(db.String(200), 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 Question(db.Model):
    __tablename__='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'))
    creat_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()

@app.route('/')
def sy():
    context = {
        'questions': Question.query.all()
    }
    return render_template('sy.html', **context)

if __name__ == '__main__':
    app.run(debug=True)
复制代码

数据库:

 

3、导航条。

制作一个自己的导航条,在导航条里有HTML头部元素:①<base> 定义了页面链接标签的默认链接地址 ②<style>定义了HTML文档的样式文件 ③<link>定义了一个文档和外部资源之间的关系,还有在这认识的CCS盒子模型。用来实现样式的美化,新建相应CSS文件,并链接到html文件中。还设计了相应的底部导航,底部导航是一些图片的相应友情链接。还有在完成登录之后,导航条也会随之发生改变。并要在主py文件上进行更新操作。

导航HTML:

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %}
        {% endblock %}
        ヾ(≧∇≦*)ゝ</title>
    <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/dh.css') }}">
     <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">   <!-- 用了bootstrap标准导航,导入其css样式-->
    <script src="{{ url_for('static',filename='js/dh.js') }}"></script>
</head>
{% block head %}
{% endblock %}

<nav class="navbar navbar-default" role="navigation">   <!-- class里的代码是显示导航框架 -->
       <div class="navbar-header">   <!-- class里的代码是让导航内容显示在同一行 -->
                <a  href="http://127.0.0.1:5000/nr/"><img class="tubiao" id="tubiao" src="{{ url_for('static',filename='image/tb.jpg')}}"></a>
            </div>
            <form action="{{ url_for('cx') }}" method="get" class="navbar-form navbar-left" role="search">    <!-- class里的代码是让导航内容显示在一行上,并且navbar-left是让搜索框向左边靠-->
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="✍输入您感兴趣的" name="q">
                </div>
                <button type="submit" class="btn btn-default">查找</button>
             </form>
            <ul class="nav navbar-nav navbar-right" id="myBody">
                <li ><img class="tupian" id="myOnOff" onclick="myswitch()" src="{{ url_for('static',filename='image/sun.png')}}"></li>
                <li><a href="{{ url_for('sy') }}"><span class="glyphicon .glyphicon-home"></span> 首页</a></li>
                {% if username %}
                    <li><a href="{{ url_for('gr',user_id=session.get("userid"),tag=1) }}">{{ username }}</a></li>
                    <li><a href='{{ url_for('tc') }}'>退出</a></li>
                {% else %}
                    <li><a href="{{ url_for('zc') }}"><span class="glyphicon glyphicon-user"></span> 注册</a></li>
                    <li><a href="{{ url_for('dl') }}"><span class="glyphicon glyphicon-log-in"></span> 登录</a></li>
                {% endif %}
                    <li><a href="{{ url_for('fk') }}"><span class="glyphicon .glyphicon-pencil"></span> 发表影评</a></li>

            </ul>

        </div>
    </nav>

<body id="myBody">
{% block main %}

{% endblock %}


<nav class="dibu">
     <a class="daohang"  href="http://www.youku.com/"><img src="http://is4.mzstatic.com/image/thumb/Purple71/v4/71/04/5b/71045b9d-3687-f8cc-1457-7055b4e4ed44/source/512x512bb.png"width="50" height="50" alt="gzcc.cn"></a>
     <a class="daohang"  href="http://v.qq.com/?ptag=360.kuzhan"><img src="http://p2.img.cctvpic.com/nettv/newgame/cdn_pic/1956/mzm.zamlltui.png"width="50" height="50" alt="gzcc.cn"></a>
     <a class="daohang"  href="https://www.mgtv.com/"><img src="http://imga.mumayi.com/android/img_mumayi/2014/12/10/88/885578/icon/885578_5b92a.png"width="50" height="50" alt="gzcc.cn"></a>
     <a class="daohang"  href="http://www.iqiyi.com/?vfm=f_268_360d&fv=07668579fcb3b76994a863f602b0dce3"><img src="http://pic.paopaoche.net/up/2014-7/2014711152858.png"width="50" height="50" alt="gzcc.cn"></a>
     <a class="daohang"  href="http://www.pptv.com/"><img src="http://sr1.pplive.com/cms/19/45/23f41cc6977ca745cce69cdf92e4a1f9.png"width="50" height="50" alt="gzcc.cn"></a>
     <a class="daohang"  href="https://tv.sohu.com/"><img src="http://www.d9soft.com/uploadfile/2013/0718/20130718061513909.png"width="50" height="50" alt="gzcc.cn"></a>
        <p>Copyright ©2017 silky-L</p>
</nav>
</body>
</html>
复制代码

CSS文件:

复制代码
.tupian{
    width:50px;
    height:50px;
}
.tubiao{
    width:50px;
    height:50px;
}
.dibu{
    width:100%;
    background-color:gainsboro;
    position:fixed;
    bottom:0;/**距离底部为0*/left:0;z-index:1;
    text-align:center;
}
复制代码

 

效果如图:

头部导航条:

底部导航条:

 登录后的导航条:

 

4、开关灯功能。

在导航条里有一个开关灯的按钮,要是要这个按钮的功能实现,就要上一个JS文件。JS文件用来定义开关切换函数,在HTML里面用onclick函数调用。在导航的HTML里用url_for加载静态文件<script src="{{ url_for('static',filename='js/dh.js') }}"></script>。HTML+CSS+JS这三个文件组成了一个父模板,在其他页面也可以继承这个父模板,不用每一个页面都去制作一个导航条。

JS文件:

复制代码
function myswitch() {
            var oBody = document.getElementById("myBody");
            var oOnoff = document.getElementById("myOnOff");
            if(oOnoff.src.match("sun")){
                oOnoff.src="../static/image/moon.jpg";
                oBody.style.background="black";
                oBody.style.color ="white";
            }else{
                oOnoff.src="../static/image/sun.png";
                oBody.style.background="white";
                oBody.style.color ="black";
            }
        }
复制代码

效果如图:

开灯:

关灯:

5、注册与登录页面。

注册与登录页面也有三个文件组成,HTML+CSS+JS。在注册与登录页面上还增加了三种输出数据的方式:① 使用 document.write() 方法将内容写到 HTML 文档中。② 使用 window.alert() 弹出警告框。③ 使用 innerHTML 写入到 HTML 元素。在JS文件里定义JavaScript 函数。并在主py文件里进行更新操作。

在注册页面里,

1 js文件: onclick函数return True时才提交表单,return False时不提交表单。

2 html文件:

<form>中设置 action和method="post"

<input> 中设置 name

3 主py文件中:

from flask import  request, redirect, url_for

@app.route('/regist/', methods=['GET', 'POST’])

def regist():

   if request.method == 'GET':

        return render_template('regist.html')

   else:

        username = request.form.get(‘username’)#获取form中的数据

        判断用户名是否存在:存在报错

        不存在,存到数据库中

5 redirect重定向到登录页

注册HTML:

复制代码
{% extends 'dh.html' %}
{% block title %}
注册
{% endblock %}
{% block main %}
    <link rel="stylesheet" type="text/css" href="../static/css/zc.css">
    <script src="../static/js/zc.js"></script>
</head>
<body  class="zcbg" background="{{ url_for('static',filename='../static/image/zcbg.jpg') }}">

<div class="box" >
    <form action="{{url_for('zc')}}" method="post">
    <div class="container" style="width: 400px"align="center">
    <div class="dl"><h2 align="center" style="margin-bottom: 0; width: 400px">注 ✉ 册</h2></div>
    <div class="content" style="">
    <div class="xx" align="center">
        <p> </p><br>
        用户账号:<input id="name" type="name"placeholder="请输入用户名" name="name"><br>
        输入密码:<input id="password" type="password"placeholder="请输入密码" name="password"><br>
        确认密码:<input id="againpass" type="password"placeholder="请再次输入密码" name="againpass">
        <p> </p>
        </div>
        <div id="error_box"><br></div>
        <p>  </p>
      <div class="an" >
         <button onclick="myLogin()">注册</button>
         <button type="button" onclick=window.alert("是否取消注册!")>取消</button>

         </div>

    </div>
     </div>
    </form>
    </div>

</body>
</html>

{% endblock %}
复制代码

JS文件:

复制代码
function myLogin() {
        var oUname = document.getElementById("name");
        var oError = document.getElementById("error_box");
        var opassword = document.getElementById("password");
        var oAgainname = document.getElementById("againpass");

        oError.innerHTML="<br>"
        //name
        if(oUname.value.length<6||oUname.value.length>20){

            oError.innerText="☞用户名请输入6-20个字符";
            return false;
            }
            else if ((oUname.value.charCodeAt(0)>=48)&&oUname.value.charCodeAt(0)<=57){
                oError.innerText="✘用户名首字母不能为数字";
                return false;
        }
        else for(var i=0; i<oUname.value.length; i++){
                if((oUname.value.charCodeAt(i)<48)||(oUname.value.charCodeAt(i)>57) && (oUname.value.charCodeAt(0)<97) || (oUname.value.charCodeAt(0)>122)){
                    oError.innerHTML="✘用户名只能是小写字母与数字";
                    return false;
                }
        }
        //password
        if(opassword.value.length<6||oAgainname.value.length>20){

            oError.innerText="☛密码请输入6-20个字符内";
            return false;
        }
        else if (password.value!= againpass.value) {
            oError.innerHTML = "✘两次密码不一致"
            return false;
        }
        window.alert("✌注册成功!\\(^o^)/YES!")
        return true;
        }
复制代码

效果如图:

 

登录功能完成:

1 js:设置:return

2 html:设置:form、input、onclick="return fnLogin()"

3 py:

@app.route设置methods:GET、POST

读取表单数据、查询数据库、用户名密码对、记住用户名、跳转到首页、用户名密码不对、提示相应错误。

session:从`flask`中导入`session`、设置`SECRET_KEY`、操作字典一样操作`session`:增加用户名`session['username']=`username

登录HTML:

复制代码
{% extends 'dh.html' %}
{% block title %}
登录
{% endblock %}
{% block main %}
    <link rel="stylesheet" type="text/css" href="../static/css/dl.css">
    <script src="../static/js/dl.js"></script>
</head>
<body  class="bg" background="{{ url_for('static',filename='../static/image/dlbg.jpg') }}"> {# 背景图 #}

<div class="box" >
    <form action="{{url_for('dl')}}" method="post">
    <div class="container" style="width: 400px"align="center">
    <div class="dl"><h2 align="center" style="margin-bottom: 0;width:400px">✉登  录✉</h2></div>{# 登录标题 #}
    <div class="content">   {#登录框#}
    <div class="xx" align="center">
        <p> </p>
        账  户:<input id="name" type="text"placeholder="请输入用户名" name="name"><br>
        密  码:<input id="password" type="password"placeholder="请输入密码" name="password">
        <p> </p>
        </div>
        <div id="error_box"><br></div>
        <p>  </p>
      <div class="an" >
         <button onclick="myLogin()">登录</button>
         <button type="button" onclick=window.alert("是否取消登录!")>取消</button>

         </div>

    </div>
     </div>
    </form>
</div>
</body>
</html>

{% endblock %}
复制代码

JS文件:

复制代码
function myLogin() {
        var oUname = document.getElementById("name");
        var oError = document.getElementById("error_box");
        var opassword = document.getElementById("password");
        oError.innerHTML="<br>"
        //name
        if(oUname.value.length<6||oUname.value.length>20){
                oError.innerText="☞用户名请输入6-20个字符";
                return false;
            }
            else if ((oUname.value.charCodeAt(0)>=48)&&oUname.value.charCodeAt(0)<=57){
            oError.innerText="✘用户名首字母不能为数字";
                return false;
        }
        else for(var i=0; i<oUname.value.length; i++){
                if((oUname.value.charCodeAt(i)<48)||(oUname.value.charCodeAt(i)>57) && (oUname.value.charCodeAt(0)<97) || (oUname.value.charCodeAt(0)>122)){
                    oError.innerHTML="✘用户名只能是小写字母与数字";
                    return false;
                }
        }
        //password
        if(opassword.value.length<6||opassword.value.length>20){
                oError.innerText="☛密码请输入6-20个字符内";
                return false;
            }
         return true;
         }
复制代码

 效果如图:

 

7、发布页面。

制作带label的文本输入区域的页面,实现发布功能。最后要在主py文件里进行更新操作。

1 在主py文件里编写要求登录的装饰器

from functools import wraps

def loginFirst(func): #参数是函数

@wraps(func)

      def wrapper(*args, ** kwargs): #定义个函数将其返回

          #要求登录

          return func(*args, ** kwargs)

      return wrapper #返回一个函数

2 应用装饰器,要求在发布前进行登录,登录后可发布。

@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():

3 建立发布内容的对象关系映射。

class Question(db.Model):

4 完成发布函数。

5 保存到数据库。

6 重定向到首页。

HTML:

复制代码
{% extends 'dh.html' %}
{% block title %}
   反馈页面
{% endblock  %}
{% block head %}
        <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='../static/css/fk.css') }}">
{% endblock  %}
{% block main %}
    <body>
<div class="question-feedback">
<h2> 影评发布 </h2>
<form action="{{ url_for('fk') }}" method="post" >
   <div class="question-control">
       <div>
            <label for="question">标题:</label>
            <br>
            <textarea class="form-control" rows="6" id="questionTitle" placeholder="请输入影评标题"
                      style="height: 50px" name="title" ></textarea>
        </div>
       <div>
            <label for="questionDetail">评论:</label>
            <br>
            <textarea class="form-control" rows="6" id="questionDetail" placeholder="请描述你对电影的感受"
                      style="height: 130px" name="detail"></textarea>
       </div>
       <input type="checkbox" id="c1">发布影评<br>
   </div>
    <div class="submit-button">
       <br>
       <button type="submit" style="float:right" id="submit-button">发送</button>
    </div>
</form>
</div>
    </body>
{% endblock  %}
复制代码

效果如图:

8、首页列表。

在影评发布后,会显示在首页的列表上。1 首页列表显示全部问答:将数据库查询结果传递到前端页面 Question.query.all() 2 前端页面循环显示整个列表。 3 问答排序。最后并在主py文件上进行更新操作。

首页HTML:

复制代码
{% extends 'dh.html' %}
{% block title %}
    首页
{% endblock %}
{% block head %}
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="../static/css/sy.css">
{% endblock %}
{% block main %}
    <body  class="sybg" background="{{ url_for('static',filename='../static/image/sybg.jpg') }}">
    <div class="nr-box">
        <ul class="list-group">
            {% for foo in questions %}
            <li class="list-group-item">
            <img style="width: 30px" src="{{ url_for('static',filename='../static/image/tx.jpg') }}" alt="64">
                <a href="{{ url_for('gr',user_id=foo.author.id,tag=1) }}">{{ foo.author.username }}</a><br>
                 <a href="{{ url_for('xq',question_id = foo.id) }}">题目:{{ foo.title }}</a><br>
                <p>影评:{{ foo.detail }}</p><br>
                <span class="badge" style="margin-left: 60%">{{ foo.creat_time }}发布时间</span>
                <p style="margin-left: 25%"></p>
            </li>
            {% endfor %}
        </ul>
    </div>
    </body>
{% endblock %}
复制代码

效果如下:

 

 9、详情页面。

制作详情页面,详情页布局:1 包含问答的全部信息 2 评论区 3 以往评论列表显示区。最后在主py文件上进行更新操作。

还要制作首页标题的标签做带参数的链接:{{ url_for('detail',question_id = foo.id) }}

1 在详情页将数据的显示在恰当的位置。 

{{ ques.title}}
{{ ques.id  }}{{  ques.creat_time }}

{{ ques.author.username }} 
{{ ques.detail }}

2 建立评论的对象关系映射:

class Comment(db.Model):
    __tablename__='comment'

3 尝试实现发布评论。

HTML:

复制代码
{% extends 'dh.html' %}
{% block title %}
    反馈详情
{% endblock  %}
{% block head %}
        <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='../static/css/xq.css') }}">
{% endblock  %}
{% block main %}
   <div class="page-header">
   <h3>问题:{{ ques.title }}<br>
       <small>作者:{{ ques.author.username }}<br>
           <span class="">
               发布时间:{{ ques.creat_time }}
           </span></small></h3>
    <p class="lead">详情:{{ ques.detail }} </p>
       <form role="form" action="{{ url_for('comment') }}" method="post">
    <div class="form-group">
        <textarea  name="new_comment" class="form-control" rows="6" id="questionTitle" placeholder="请写下你的评论" style="height: 100px" ></textarea>
        <input name="question_id" type="hidden" value="{{ ques.id }}">
        <br>
           <button type="submit" style="float:right" id="submit-button">发送</button>
    </div>
   </form></div>
    <div class="pl-box">
       <h4>评论区:
       ({{ ques.comments|length }})</h4><br>

    <ul class="list-group">
            {% for ques in ques.comments %}
            <li class="list-group-item">
            <img style="width: 30px" src="{{ url_for('static',filename='../static/image/tx.jpg') }}" alt="64">
                <a href="{{ url_for('gr',user_id=ques.author.id,tag=1) }}">{{ ques.author.username }}</a><br>
                <p>评论详情:{{ ques.detail }}</p><br>
                <span class="badge" style="margin-left: 60%">{{ ques.creat_time }}评论时间</span>
                <p style="margin-left: 25%"></p>
            </li>
            {% endfor %}
        </ul>
    </div>


{% endblock %}
复制代码

效果如图:

 

 

10、个人中心

先新建一个个人中心的导航页,个人中心的页面需要继承总的导航条。然后建立全部文章、全部评论、个人信息三个子页面继承个人中心的导航页。1 userbase.html,用<ul ><li role="presentation"> 实现标签页导航。2 让userbase.html继承父模板。然后三个子页面分别继承个人中心的导航页面。最后在主py文件中进行更新操作。

个人中心导航HTML:

复制代码
{% extends 'dh.html' %}
{% block title %}
   个人中心
{% endblock  %}
  {% block head %}
    <style>
        .nav_ul li{
            float: left;
            list-style: none;
            margin: 10px;
            border-bottom: antiquewhite;
        }
    </style>
{% endblock %}

{% block main %}
    <ul class="nav nav-tabs">
        <li role="presentation"><a href="{{ url_for('gr', user_id = user.id,tag='1') }}">全部问答</a></li>
        <li role="presentation"><a href="{{ url_for('gr',user_id = user.id,tag='2') }}">全部评论</a></li>
        <li role="presentation"><a href="{{ url_for('gr',user_id = user.id,tag='3') }}">个人信息</a></li>

    </ul>
    {% block user %}{% endblock %}
{% endblock %}
复制代码

全部文章HTML:

复制代码
{% extends 'gr-dh.html' %}

{% block user %}
    <div class="page-header">
        <h3><span class="glyphicon glyphicon-user"  aria-hidden="true"></span>{{ username }}<br>
            <small>全部文章<span class="badge"></span></small>
        </h3>
        <ul class="list-group" style="margin: 10px">
            {% for ques in question %}
                <li class="list-group-item" style="word-wrap:break-word;">
                    <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
                    <a href="#">{{ ques.author.username }}</a>
                    <span class="badge" style="margin-left: 60%">{{ ques.creat_time }}发布时间</span>
                    <p>{{ ques.detail }}</p>
                </li>
            {% endfor %}
        </ul>
    </div>

{% endblock %}
复制代码

全部评论HTML:

复制代码
{% extends 'gr-dh.html' %}

{% block user %}
    <div class="page-header">
        <h3><span class="glyphicon glyphicon-user"  aria-hidden="true"></span>{{ username }}<br>
            <small>全部评论<span class="badge"></span></small>
        </h3>
        <ul class="list-group" style="margin: 10px">
            {% for ques in comments %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
                    <a href="#">{{ ques.author.username }}</a>
                    <span class="badge">{{ ques.create_time }}</span>
                    <p>{{ ques.detail }}</p>
                </li>
            {% endfor %}
        </ul>
    </div>

{% endblock %}
复制代码

个人信息HTML:

复制代码
{% extends 'gr-dh.html' %}

{% block user %}
    <div class="page-header">
        <h3><small>个人信息<span class="badge"></span></small></h3>
        <ul class="list-group" style=" ">
            <li class="list-group-item">用户:{{ username }}</li>
            <li class="list-group-item">编号:{{ user.id }}</li>
            <li class="list-group-item">文章数:{{ question|length }}</li>
            <li class="list-group-item">评论数:{{ comments|length }}</li>
            <p>     </p>
        </ul>
    </div>

{% endblock %}
复制代码

效果如图:

 

 

 

11、搜索功能。

修改父模板页面中搜索输入框所在的<form action="{{ url_for('search') }}" method="get">、<input name="q" type="text" placeholder="请输入关键字">

完成视图函数search()、获取搜索关键字:q = request.args.get('q’)、条件查询:qu = Question.query.filter(Question.title.contains(q)).order_by('-creat_time’)

加载查询结果:return render_template('index.html', question=qu)

组合条件查询:from sqlalchemy import or_, and_ 

主py文件:

复制代码
@app.route('/cx/')
def cx():
    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('sy.html',questions = ques)
复制代码

导航页HTML:

 <form action="{{ url_for('cx') }}" method="get" class="navbar-form navbar-left" role="search">
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="✍输入您感兴趣的" name="q">
                </div>
                <button type="submit" class="btn btn-default">查找</button>
             </form>

12、密码保护。

1 更新User对象,设置对内的_password

class User(db.Model):

    __tablename__ = 'user' 

    _password = db.Column(db.String(200), nullable=False) #内部使用 

2 编写对外的password

from werkzeug.security import generate_password_hash, check_password_hash

    @property

    def password(self):  #外部使用,取值

        return self._password

    @password.setter

    def password(self, row_password):#外部使用,赋值

        self._password = generate_password_hash(row_password)

 3 密码验证的方法:

    def check_password(self, row_password): #密码验证

        result = check_password_hash(self._password,row_password)

        return result 

4 登录验证:

        password1 = request.form.get('password')

        user = User.query.filter(User.username == username).first()

        if user:

            if user.check_password(password1):

 主py文件:

复制代码
class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer,primary_key=TabError,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    _password = db.Column(db.String(200), 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


@app.route('/dl/',methods=['GET','POST'])
def dl():
    if request.method == 'GET':
        return render_template("dl.html")
    else:
        usern = request.form.get('name')
        password = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            if user.check_password(password):
                session['user'] = usern
                session['userid'] = user.id
                session.permanent = True
                return redirect(url_for('sy'))
            else:
                return '密码错误(〃>皿<)'
        else:
            return '用户不存在┌(。Д。)┐'
复制代码

效果如图:

 

13、总的py文件:

复制代码
from flask import Flask,request,render_template,redirect,url_for,session
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from sqlalchemy import or_,and_
from functools import wraps
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)




class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer,primary_key=TabError,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    _password = db.Column(db.String(200), 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 Question(db.Model):
    __tablename__='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'))
    creat_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()

# #增加
# user = User(username='123456',password = '456789')
# db.session.add(user)
# db.session.commit()
#
# #查询
# user =User.query.filter(User.username =='abcdef').first()
# print(user.username,user.password)
#
# #修改
# user =User.query.filter(User.username =='123456').first()
# user.password='abcdef'
# print(user.username,user.password)
# db.session.commit()
#
# #删除
# user =User.query.filter(User.username =='123456').first()
# print(user.username,user.password)
# db.session.delete(user)
# db.session.commit()

@app.route('/')
def sy():
    context = {
        'questions': Question.query.all()
    }
    return render_template('sy.html', **context)

@app.route('/xq/<question_id>')
def xq(question_id):
    quest = Question.query.filter(Question.id == question_id).first()
    return render_template('xq.html',ques = quest)

def loginFirst(func):
    #行动前需要登录,定义装饰器
    @wraps(func)
    def wrapper(*args,**kwargs):
        if session.get('user'):
            return func(*args,**kwargs)
        else:
            return redirect(url_for('dl'))
    return wrapper

@app.route('/comment/', methods=['POST'])
@loginFirst
def comment():
    comment = request.form.get('new_comment')
    ques_id = request.form.get('question_id')
    author_id = User.query.filter(User.username == session.get('user')).first().id
    comm = Comment(detail=comment, author_id=author_id, question_id=ques_id )
    db.session.add(comm)
    db.session.commit()
    return redirect(url_for('xq', question_id=ques_id))


@app.route('/gr/<user_id>/<tag>')
@loginFirst
def gr(user_id,tag):
    user=User.query.filter(User.id==user_id).first() #把信息存放到数据库里面
    context={
        'username':user.username,
        'question':user.question,
        'comments':user.comments,
        'user':user
    }
    if tag == '1':
        return render_template('wd.html',**context) #输出显示数据库里的信息
    elif tag == '2':
        return render_template('pl.html',**context)
    else:
        return render_template('zx.html', **context)

@app.route('/nr/')
def nr():
    return render_template('nr.html')


@app.route('/dl/',methods=['GET','POST'])
def dl():
    if request.method == 'GET':
        return render_template("dl.html")
    else:
        usern = request.form.get('name')
        password = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            if user.check_password(password):
                session['user'] = usern
                session['userid'] = user.id
                session.permanent = True
                return redirect(url_for('sy'))
            else:
                return '密码错误(〃>皿<)'
        else:
            return '用户不存在┌(。Д。)┐'

@app.context_processor
def mycontext():
    usern=session.get('user')
    if usern:
        return {'username':usern}
    else:
        return{}

@app.route('/zc/',methods=['GET','POST'])
def zc():
    if request.method == 'GET':
        return render_template("zc.html")
    else:
        usern = request.form.get('name')
        password = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            return '用户名已存在┗|*`0′*|┛ '
        else:
            user1 = User(username=usern, password=password)
            db.session.add(user1)
            db.session.commit()
            return redirect(url_for('dl'))

@app.route('/tc/')
def tc():
    session.clear();
    return redirect(url_for('sy'))

def loginFirst(func):
    #行动前需要登录,定义装饰器
    @wraps(func)
    def wrapper(*args,**kwargs):
        if session.get('user'):
            return func(*args,**kwargs)
        else:
            return redirect(url_for('dl'))
    return wrapper

@app.route('/fk/',methods=['GET','POST'])
@loginFirst
def fk():
    if request.method == 'GET':
        return render_template('fk.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('sy'))

@app.route('/cx/')
def cx():
    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('sy.html',questions = ques)

if __name__ == '__main__':
    app.run(debug=True)
复制代码

总结:以上就是本学期使用Python的Flask框架+MysqL完成简单的网页。Flask是一个使用Python编写的轻量级 Web 应用框架。感觉这一门科目是很有趣的,它运用的语言知识简洁易懂,当成功运行出来的时候,满满的成就感。虽然还是有很多地方还不是很理解,但是只要往后多了解,多练习,就会更好地掌握这些知识。

posted @ 2018-01-05 18:50  101黎思琦  阅读(419)  评论(3编辑  收藏  举报