期末作品检查

 

一、个人学期总结

        眨眼间一个学期就要结束了,这学期在杜老师的带领下学习了python语言。Python具有丰富和强大的库。它常被昵称为胶水语言,能够把用其他语言制作的各种模块很轻松地联结在一起。常见的一种应用情形是,使用Python快速生成程序的原型(有时甚至是程序的最终界面),然后对其中有特别要求的部分,用更合适的语言改写,比如3D游戏中的图形渲染模块,性能要求特别高,就可以用C/C++重写,而后封装为Python可以调用的扩展类库。

       首先本课程先开展了理论的学习,讲授了管理信息系统的大概,使我们有了初步了解。然后开始制作web网页,开始学习用html元素制作web网页,观察常用网页的HTML元素,制作自己的导航条,认识css的盒子模型,用div等元素布局形成html文件。完成了登录与注册页面的html+css+js,夜间模式的开启和关闭,制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明等。汇总相关的样式形成独立的css文件,使用 js代码形成独立的js文件,形成完整的base.html+css+js。最后,进行flask项目,理解flask项目主程序,使用装饰器,设置路径与函数之间的关系;加载静态文件,父模板的继承和扩展;连接mysql数据库,创建用户模型,通过用户模型,对数据库进行增删改查,完成登录、注册、发布评论等功能,一步一步地完善我们的项目。在这个过程中遇到了困难也学会了去请教老师和同学,把问题解决,但是还有许多需要学习改进的地方。

二、Python+Flask+MysqL的web建设技术

经过一个学期的学习,实现了Python+Flask+MysqL的web建设,创建了一个图书分享网站,页面具有书籍分享的信息,能够通过用户登录后进行书籍分享活动,还能够发表书评、搜索文章等等。

1.使用工具

在本次实现Python+Flask+MysqL的web建设过程中,用到的主要工具有:pycharm64.exe + Python 3.6 64-bit + MySQL + Navicat for MySQL(辅助工具)

          

 

2.项目文件建设情况

pycharm 文件建设:

mysql数据库情况:

3.页面建设呈现效果

4.具体设计实现过程

(1)制作自己的导航条

效果:

 

代码:

HTML头部元素:

  1. <base>  定义了页面链接标签的默认链接地址
  2. <style>  定义了HTML文档的样式
  3. <link>  定义了一个文档和外部资源之间的关系
<body class="beijing" id="myBody" >
<nav class="navbar navbar-default " role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="{{ url_for('index')}}">首页</a>
            <a class="navbar-brand" href="{{ url_for('question') }}">问答详情</a>
           <form class="navbar-form navbar-left" action="{{ url_for('search') }}" method="get">
              <div class="form-group">
                  <input name="q" type="text"  placeholder="请输入关键字">
              </div>
              <button type="submit" class="btn btn-default" style="margin-top: 8px">搜索</button>
          </form>
        </div><img id="myOnOff" onclick="mySwitch()" src="http://www.runoob.com/images/pic_bulbon.gif" width="40px">
        <ul class="nav navbar-nav navbar-right">
            {% if username %}
                <li><a href="{{ url_for('usercenter',user_id=session.get('userid'),tag=1) }}"><span class="glyphicon glyphicon-user"></span>{{ session.get('user') }}</a></li>
                <!--<li><a href="#"><span class="    glyphicon glyphicon-user"></span>{{ username }}</a> </li>-->
                <li><a href="{{ url_for('logout')}}"><span class="glyphicon glyphicon-repeat"></span>注销</a></li>
            {% else %}
                <li><a href="{{ url_for('register')}}"><span class="glyphicon glyphicon-user"></span> 注册</a></li>
                <li><a href="{{ url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> 登录</a></li>
            {% endif %}
        </ul>

 </div>

</nav>
</body>

 

(2)图片导航块的实现

效果展示:

代码实现详情:

 <div class="row clearfix">
        <div class="col-md-12 column">
   <div class="recommend">
    <div class="img">
        <a href="http://store.dangdang.com/gys_0014410_rsgy"><img src="http://img51.ddimg.cn/9003260060812741.jpg" alt=""> </a>
        <div class="desc"><a href="http://store.dangdang.com/gys_0014410_rsgy">2017好书</a></div>
    </div>
    <div class="img">
        <a href="http://store.dangdang.com/gys_0016310_tk35"><img src="http://img59.ddimg.cn/9006170034706179.jpg" alt="" > </a>
        <div class="desc"><a href="http://store.dangdang.com/gys_0016310_tk35">好书分享</a></div>

    </div>
    <div class="img">
        <a href="http://store.dangdang.com/gys_04083_euce"><img src="http://img60.ddimg.cn/topic_img/gys_04083/langshiji382140.jpg" alt=""> </a>
        <div class="desc"><a href="http://store.dangdang.com/gys_04083_euce">好书分享</a></div>

    </div>
    <div class="img">
        <a href="http://store.dangdang.com/gys_0015642_5hay"><img src="http://img50.ddimg.cn/9002790031624100.jpg" alt="" > </a>
        <div class="desc"><a href="http://store.dangdang.com/gys_0015642_5hay">好书分享</a></div>

    </div>
    <div class="img">
        <a href="http://store.dangdang.com/gys_0015642_haib"><img src="http://img52.ddimg.cn/9002790034155752.jpg" alt="" > </a>
        <div class="desc"><a href="http://store.dangdang.com/gys_0015642_haib">好书分享</a></div>

    </div>
    <div class="img">
        <a href="http://book.dangdang.com/20170619_eeiv"><img src="http://img63.ddimg.cn/upload_img/00570/ta/huiyi24243620_19096.jpg" alt="" > </a>
        <div class="desc"><a href="http://book.dangdang.com/20170619_eeiv">好书分享</a></div>

    </div>

</div>


        </div>
    </div>

 

(3)JavaScrip基础,登录验证

效果:

代码:

  1. 登录页面准备:
    1. 增加错误提示框。
    2. 写好HTML+CSS文件。
    3. 设置每个输入元素的id
  2. 定义JavaScript 函数。
    1. 验证用户名6-20位
    2. 验证密码6-20位
  3. onclick调用这个函数。

 

{% block main %}
<div class="box" style="margin-left: 550px;margin-top: 300px;" >
    <h2 >LOGIN</h2>
     <form action="{{url_for('login') }}" method="post">
        <div class="input_box" >
            账户:<input id="uname" type="text"  class="form-control" placeholder="请输入用户名" name="username"><br>
        </div>
        <div class="input_box">
            密码:<input id="upass" type="password"  class="form-control" placeholder="请输入密码" name="password"><br>
        </div>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button onclick="fnLogin()">登录</button>
        </div>
    </form>
</div>
{% endblock %}

(4)完成登录与注册页面

效果:

代码:

1.用户名6-12位

2.首字母不能是数字

3.只能包含字母和数字

4.密码6-12位

5.注册页两次密码是否一致

 

{% block main %}
<div class="box" style="margin-left: 550px;margin-top: 300px;" >
    <h2 >LOGIN</h2>
     <form action="{{url_for('login') }}" method="post">
        <div class="input_box" >
            账户:<input id="uname" type="text"  class="form-control" placeholder="请输入用户名" name="username"><br>
        </div>
        <div class="input_box">
            密码:<input id="upass" type="password"  class="form-control" placeholder="请输入密码" name="password"><br>
        </div>
        <div id="error_box"><br></div>
        <div class="input_box">
            <button onclick="fnLogin()">登录</button>
        </div>
    </form>
</div>
{% endblock %}
{% block main %}
 <div class="box" style="margin-left: 550px;margin-top: 150px;">
    <h2>REGISTER</h2>
     <form action="{{url_for('register') }}" method="post">
         <div class="input_box">

             <div class="col-sm-10">
            用户名:<input labid="uname" type="text" class="form-control"  placeholder="请输入用户名" name="username">
         </div></div>
         <div class="input_box">
              <div class="col-sm-10">
             昵称:<input id="nickname" type="text" class="form-control"  placeholder="请输入昵称" name="nickname">
         </div></div>
         <div class="input_box">
             <div class="col-sm-10">
             密码:<input id="upass" type="password" class="form-control"  placeholder="请输入密码(区分大小写)" name="password">
         </div></div>
         <div class="input_box">
             <div class="col-sm-10">
             验证:<input id="upass1" type="password" class="form-control"  placeholder="再输入密码(区分大小写)">
         </div></div>
        <div id="error_box"> </div><br>

         <div class="input_box">
            <button onclick="fnLogin()" >register</button>
         </div>
     </form>
</div>
{% endblock %}

(5)夜间模式的开启与关闭,父模板的制作

效果:(日间)

(夜间)

 

 

代码:

夜间模式的开启与关闭

  1. 放置点击的按钮或图片。
  2. 定义开关切换函数。
  3. onclick函数调用。

父模板的制作

  1. 制作网站网页共有元素的父模板html,包括顶部导航,中间区块划分,底部导航,底部说明等。
  2. 汇总相关的样式形成独立的css文件。
  3. 汇总相关的js代码形成独立的js文件。
  4. 形成完整的base.html+css+js

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {%block title %}{% endblock %}
        我的页面</title>
    <link rel="stylesheet" type="text/css" href="../static/css/1101.css">
    <script src="../static/js/1101.js"></script>
    <!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

<!-- 可选的Bootstrap主题文件(一般不使用) -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"></script>

<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script>

<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

    {% block head %}
    {% endblock %}
</head>
<body class="beijing" id="myBody" >
<nav class="navbar navbar-default " role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="{{ url_for('index')}}">首页</a>
            <a class="navbar-brand" href="{{ url_for('question') }}">问答详情</a>
           <form class="navbar-form navbar-left" action="{{ url_for('search') }}" method="get">
              <div class="form-group">
                  <input name="q" type="text"  placeholder="请输入关键字">
              </div>
              <button type="submit" class="btn btn-default" style="margin-top: 8px">搜索</button>
          </form>
        </div><img id="myOnOff" onclick="mySwitch()" src="http://www.runoob.com/images/pic_bulbon.gif" width="40px">
        <ul class="nav navbar-nav navbar-right">
            {% if username %}
                <li><a href="{{ url_for('usercenter',user_id=session.get('userid'),tag=1) }}"><span class="glyphicon glyphicon-user"></span>{{ session.get('user') }}</a></li>
                <!--<li><a href="#"><span class="    glyphicon glyphicon-user"></span>{{ username }}</a> </li>-->
                <li><a href="{{ url_for('logout')}}"><span class="glyphicon glyphicon-repeat"></span>注销</a></li>
            {% else %}
                <li><a href="{{ url_for('register')}}"><span class="glyphicon glyphicon-user"></span> 注册</a></li>
                <li><a href="{{ url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> 登录</a></li>
            {% endif %}
        </ul>

 </div>

</nav>
</body>

{% block main %}
{% endblock %}
</body>

</html>

(6)开始flask项目

  1. 新建Flask项目。
  2. 设置调试模式。
  3. 理解Flask项目主程序。
  4. 使用装饰器,设置路径与函数之间的关系。
  5. 使用Flask中render_template,用不同的路径,返回首页、登录员、注册页。
  6. 用视图函数反转得到URL,url_for(‘login’),完成导航里的链接。
from flask import Flask,render_template,request,redirect,url_for,session
from flask_sqlalchemy import SQLAlchemy
import config
from functools import wraps
from datetime import datetime
from werkzeug.security import generate_password_hash,check_password_hash
from sqlalchemy import or_,and_

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))
    tel = db.Column(db.String(50))

    @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'))
    detail=db.Column(db.Text,nullable=False)
    creat_time=db.Column(db.DateTime,default=datetime.now)
    question=db.relationship('Question',backref=db.backref('comments',order_by=creat_time.desc))
    author=db.relationship('User',backref=db.backref('comments'))


db.create_all()


#
#user = User.query.filter(User.username == 'sk').first()
#print(user.id,user.password)

#
#user = User.query.filter(User.username == 'mis1234').first()
#user.password='888888'
#user.username='sk'
#db.session.commit()
#print(user.id,user.password)

#
#user = User.query.filter(User.username=='sk').first()
#db.session.delete(user)
#db.session.commit()


#
#user = User(username='mis1234',password='111111')
#db.session.add(user)
#db.session.commit()

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

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


@app.route('/register/',methods=['GET','POST'])
def register():
    if request.method=='GET':
        return render_template('register.html')
    else:
        usern = request.form.get('username')
        nickn = request.form.get('nickname')
        passw = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            return 'username existed.'
        else:
            user1 = User(username = usern,password = passw,nickname = nickn)
            db.session.add(user1)
            db.session.commit()
            return redirect(url_for('login'))

@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method=='GET':
        return render_template('login.html')
    else:
        usern = request.form.get('username')
        passw = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            if user.check_password(passw):
                session['user']=usern
                session['userid']=user.id
                session.permanent = True
                return redirect(url_for('index'))
            else:
                return 'password error.'
        else:
            return 'username is not existed.'

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

@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

@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():
    if request.method=='GET':
        return render_template('question.html')
    else:
        titleq = request.form.get('title')
        detailq = request.form.get('detail')
        user = User.query.filter(User.username==session.get('user')).first()
        author_id=user.id
        question = Question(title=titleq,detail=detailq,author_id=author_id)
        question.author=user
        db.session.add(question) #保存到数据库
        db.session.commit()
        return redirect(url_for('index'))

# @app.route('/questiondetail/<question_id>',methods=['GET','POST'])
@app.route('/questiondetail/<question_id>')
def questiondetail(question_id):
    quest=Question.query.filter(Question.id==question_id).first()
    return render_template('questiondetail.html',ques=quest)

@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(author_id=auth_id,question_id=ques_id,detail=comment)
    db.session.add(comm)
    db.session.commit()
    return redirect(url_for('questiondetail',question_id=ques_id))

@app.route('/usercenter/<user_id>/<tag>')
@loginFirst
def usercenter(user_id,tag):
    user=User.query.filter(User.id==user_id).first()
    context={
        'user':user,
        'comments':user.comments,
        'questions':user.question
    }
    if tag=='1':
        return render_template('user1.html',**context)
    elif tag=='2':
        return render_template('user2.html',**context)
    else:
        return render_template('user3.html',**context)



@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)

if __name__ == '__main__':
    app.run()

(7)加载静态文件,父模板的继承和扩展

  1. 用url_for加载静态文件
    1. <script src="{{ url_for('static',filename='js/login.js') }}"></script>
    2. flask 从static文件夹开始寻找
    3. 可用于加载css, js, image文件
  2. 继承和扩展
    1. 把一些公共的代码放在父模板中,避免每个模板写同样的内容。base.html
    2. 子模板继承父模板
      1.   {% extends 'base.html’ %}
    3. 父模板提前定义好子模板可以实现一些自己需求的位置及名称。block
      1. <title>{% block title %}{% endblock %}-MIS问答平台</title>
      2. {% block head %}{% endblock %}
      3. {% block main %}{% endblock %}
    4. 子模板中写代码实现自己的需求。block  {% block title %}登录{% endblock %}
{% extends 'base.html' %}
{% block title %}
LOGIN
{% endblock %}

{% block head %}
 <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/1031.css') }}">
    <script src="{{ url_for('static',filename='js/1031.js') }}"></script>
{% endblock %}

{% block main %}
略
{% endblock %}

 

(8)链接mysql数据库,创建用户模型

  1. 安装与配置python3.6+flask+mysql数据库
    1. 下载安装MySQL数据库
    2. 下载安装MySQL-python 中间件
    3. pip install flask-sqlalchemy (Python的ORM框架SQLAlchemy)
  2. mysql创建数据库  
  3. 数据库配置信息config.py
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@localhost:3306/mis_db?charset=utf8'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
  4. 建立mysql和app的连接
    复制代码
    from flask import Flask,render_template
    from flask_sqlalchemy import SQLAlchemy
    import config
    
    
    app = Flask(__name__)#初始化一个Flask对象,需要传递一个参数__name__
    app.config.from_object(config)
    db=SQLAlchemy(app)
    
    db.create_all()
    复制代码
  5. 创建用户模型
    复制代码
    # /创建用户模型
    class User(db.Model):
        __tablename__ ='user'
        id=db.Column(db.Integer,primare_key=TabError,autoincrement=True)
        username=db.Column(db.String(20),nullable=False)
        password=db.Colum(db.String(20),nullable=False)
    复制代码

(9)通过用户模型,对数据库进行增删改查操作

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

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))
    tel = db.Column(db.String(50))

    @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'))
    detail=db.Column(db.Text,nullable=False)
    creat_time=db.Column(db.DateTime,default=datetime.now)
    question=db.relationship('Question',backref=db.backref('comments',order_by=creat_time.desc))
    author=db.relationship('User',backref=db.backref('comments'))


db.create_all()


#
#user = User.query.filter(User.username == 'sk').first()
#print(user.id,user.password)

#
#user = User.query.filter(User.username == 'mis1234').first()
#user.password='888888'
#user.username='sk'
#db.session.commit()
#print(user.id,user.password)

#
#user = User.query.filter(User.username=='sk').first()
#db.session.delete(user)
#db.session.commit()


#
#user = User(username='mis1234',password='111111')
#db.session.add(user)
#db.session.commit()

(10)完成注册功能

@app.route('/register/',methods=['GET','POST'])
def register():
    if request.method=='GET':
        return render_template('register.html')
    else:
        usern = request.form.get('username')
        nickn = request.form.get('nickname')
        passw = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            return 'username existed.'
        else:
            user1 = User(username = usern,password = passw,nickname = nickn)
            db.session.add(user1)
            db.session.commit()
            return redirect(url_for('login'))

(11)完成登录功能,用session记住用户名

session:

  1. 从`flask`中导入`session`
    from flask import Flask,render_template,request,redirect,url_for,session
  2. 设置`SECRET_KEY`
    复制代码
    import os
    
    DEBUG =True
    
    SECRET_KEY = os.urandom(24)
    
    DIALECT ='mysql'
    DRIVER ='mysqldb'
    USERNAME='root'
    PASSWORD=''
    HOST='localhost'
    PORT='3306'
    DATABASE='Y_db'
    
    # SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@127.0.0.1:3306/yuan_db?charset=utf8'
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@localhost:3306/Y_db?charset=utf8'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    复制代码
  3. 操作字典一样操作`session`:增加用户名`session['username']=`username
    @app.route('/login/',methods=['GET','POST'])
    def login():
        if request.method == 'GET':
            return render_template('1031.html')
        else:
            usern = request.form.get('username')
            passw = request.form.get('password')
            user = User.query.filter(User.username == usern).first()
            # 判断用户名是否存在
            if user:
                session['user'] = usern
                session.permanent = True
                if user.password == passw:
                    return redirect(url_for('shouye'))
                else:
                    return 'password error' 
            else:
                return 'username is not existed'

     

(12)登录之后更新导航

效果:

 

代码:

@app.context_processor
def mycontext():
    usern = session.get('user')
    if usern:
        return {'username': usern}
    else:
        return {}
<ul class="nav navbar-nav navbar-right">
            {% if username %}
                <li><a href="{{ url_for('usercenter',user_id=session.get('userid'),tag=1) }}"><span class="glyphicon glyphicon-user"></span>{{ session.get('user') }}</a></li>
                <!--<li><a href="#"><span class="    glyphicon glyphicon-user"></span>{{ username }}</a> </li>-->
                <li><a href="{{ url_for('logout')}}"><span class="glyphicon glyphicon-repeat"></span>注销</a></li>
            {% else %}
                <li><a href="{{ url_for('register')}}"><span class="glyphicon glyphicon-user"></span> 注册</a></li>
                <li><a href="{{ url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> 登录</a></li>
            {% endif %}
        </ul>

 

(13)发布功能的完成

效果:

代码:

  • 编写要求登录的装饰器

from functools import wraps

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

@wraps(func)

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

          #要求登录

          return func(*args, ** kwargs)

      return wrapper #返回一个函数

复制代码
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('/question/',methods=['GET','POST'])
@loginFirst
def question():

 

  • 建立发布内容的对象关系映射。
class Question(db.Model):
复制代码
# /创建用户模型
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)
    nickname=db.Column(db.String(50))
    
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'))
#db.create_all()
复制代码

 

  • 完成发布函数。

保存到数据库。

重定向到首页。

@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():
    if request.method=='GET':
        return render_template('question.html')
    else:
        titleq = request.form.get('title')
        detailq = request.form.get('detail')
        user = User.query.filter(User.username==session.get('user')).first()
        author_id=user.id
        question = Question(title=titleq,detail=detailq,author_id=author_id)
        question.author=user
        db.session.add(question) #保存到数据库
        db.session.commit()
        return redirect(url_for('index'))

(14)制作首页的显示列表

效果:

 

代码:

 <div id="list-container">
        <ul class="list-group" style="...">
            {% for foo in questions %}
                <li>
                    <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                    用户:<a href="{{ url_for('usercenter',user_id=foo.author_id,tag=2) }}" target="_blank">{{ foo.author.username }}</a>
                    <br>
                    <a href="{{ url_for('questiondetail',question_id=foo.id) }}" >{{ foo.title }}</a>
                    <span class="badge">{{ foo.creat_time }}</span>
                    <p style="text-indent: 18px">{{ foo.detail }}</p>
                    <span class="badge">评论数:{{ foo.comments|length }}</span>

                </li>
            {% endfor %}
        </ul>
    </div>

 

(15)首页列表显示全部问答,完成问答详情页布局

  1. 首页列表显示全部问答:
    1. 将数据库查询结果传递到前端页面 Question.query.all()
      复制代码
      @app.route('/')
      def index():
          context = {
              # 'user': 'YUAN',
              'questions': Question.query.order_by('-creat_time').all()
          }
          return render_template('1101.html',**context)
      复制代码

       

    2. 前端页面循环显示整个列表。
    3. 问答排序
      复制代码
      {% extends '1101.html' %}
      {% block title %}问答详情{% endblock %}
      {% block main %}
          <div class="page-header">
              <h3>Title{{ ques }}<br>
                  <small>author {{ ques.author_id }}{{ ques.create_time }}</small>
              </h3>
          </div>
          <p class="lead">detail{{ ques.detail }}</p>
          <hr>
          <form action="{{ url_for('question') }}" method="post">
          <div class="form-group">
              <textarea name="new_comment" class="form-control" rows="3" id="new_comment" placeholder="write your comment"></textarea>
          </div>
          <button type="submit" class="btn btn-default">发送</button>
          </form>
          <ul class="list-group" style="margin: 10px"></ul>
      
      {% endblock %}
      复制代码

       

  2. 完成问答详情页布局:
    1. 包含问答的全部信息
    2. 评论区
    3. 以往评论列表显示区。
      复制代码
      <p>{{ user }}context</p>
      
         <ul class="list-group" style="...">
             {% for foo in questions %}
                 <li class="list-group-item">
                 <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                 <a href="#">{{ foo.author.username }}</a>
                 <br>
                 <a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a>
                 <span class="badge">{{ foo.creat_time }}</span>
                 <p style="...">{{ foo.detail }}</p>
      
                 </li>
      
             {% endfor %}
         </ul>
      复制代码

       

  3. 在首页点击问答标题,链接到相应详情页。

 

(16)从首页问答标题到问答详情页

效果:

代码:

{% extends 'base.html' %}
{% block title %}
问答详情
{% endblock %}

{% block head %}
    <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/questiondetail.css') }}">
{% endblock %}

{% block main %}
    <div class="post">
    <div class="artical">
        <h1 style="text-align: center">{{ ques.title }}</h1>
        <br><small>用户:{{ ques.author.username }} <span class="badge">{{ ques.creat_time }}</span></small>
        <hr>
        <p class="lead">{{ ques.detail }}</p>
    </div>
        <form action="{{ url_for('comment') }}" method="post" style="align-content: inherit">
            <div class="sign-container">
                    <textarea class="form-control" rows="8" id="QuestionDetail" name="new_comment"></textarea>
                    <input name="question_id" type="hidden" value="{{ ques.id }}"/>
                <br>
                <input type="submit" value="评论" style="float: right">
                <h4>评论({{ ques.comments|length }})</h4>
                <hr>
            </div>
        </form>
        <ul class="list-group" style="background-size: contain">
            {% for foo in ques.comments %}
            <li>
                <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                用户:<a href="{{ url_for('usercenter',user_id=foo.author_id,tag=1) }}" >{{ foo.author.username }}</a>
                <span class="badge">{{ foo.creat_time }}</span>
                <br>
                <p style="text-indent: 18px">{{ foo.detail }}</p>
            </li>
            {% endfor %}
    </ul>
    </div>

{% endblock %}
# @app.route('/questiondetail/<question_id>',methods=['GET','POST'])
@app.route('/questiondetail/<question_id>')
def questiondetail(question_id):
    quest=Question.query.filter(Question.id==question_id).first()
    return render_template('questiondetail.html',ques=quest)

@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(author_id=auth_id,question_id=ques_id,detail=comment)
    db.session.add(comm)
    db.session.commit()
    return redirect(url_for('questiondetail',question_id=ques_id))

 

(17)完成评论功能

效果:

 

代码:

  1. 定义评论的视图函数
    @app.route('/comment/',methods=['POST'])
    def comment():
    读取前端页面数据,保存到数据库中
    复制代码
    @app.route('/comments/',methods=['POST'])
    @loginFirst
    def comments():
        comment=request.form.get('new_comment')
        questions_id =request.form.get('questions_id')
        author_id = User.query.filter(User.username == session.get('user')).first().id
        comments = Comment(detail=comment, author_id=author_id, questions_id=questions_id)
        db.session.add(comments) 
        db.session.commit()  
    复制代码

     

  2. 用<input type="hidden" 方法获取前端的"question_id" 
     <input type="hidden" name="questions_id" value="{{ questions.id }}">

     

  3. 显示评论次数
    <h4>评论({{ questions.comments|length }})</h4>

     

  4. 要求评论前登录
    @app.route('/comments/',methods=['POST'])
    @loginFirst

     

  5. 尝试实现详情页面下的评论列表显示

 

(18)评论列表显示及排序,个人中心显示

效果:

 

代码:

显示所有评论
{% for foo in ques.comments %}

所有评论排序
uquestion = db.relationship('Question', backref=db.backref('comments', order_by=creat_time.desc))

显示评论条数
{{ ques.comments|length }}

1.完成个人中心

2.个人中心的页面布局(html文件及相应的样式文件)

3.定义视图函数def usercenter(user_id):

4.向前端页面传递参数

5.页面显示相应数据

发布的全部问答

发布的全部评论

个人信息

6.各个页面链接到个人中心

{% extends 'base.html' %}

{% block title %}
    用户中心
{% endblock %}

{% block head %}
    <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='css/usercenter.css') }}">
{% endblock %}

{% block main %}
    <div class="list-container">
    <h1 style="align-content: center">{{ user.username }}</h1>
    <br>
    {#<div class="page-header">
        <ul class="list-group" style="background-size: contain">
        <h3>全部分享</h3>
            {% for foo in user.question %}
            <li class="list-group-item">
                <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                <a href="#" target="_blank">{{ foo.author.username }}</a>
                <span class="badge">发布时间:{{ foo.creat_time }}</span>
                <p style="text-indent: 18px">{{ foo.detail }}</p>
            </li>
            {% endfor %}
        </ul>
    </div>
    <hr>
    <div class="page-header">
        <h3>全部书评</h3>
        <ul class="list-group" style="background-size: contain">
            {% for foo in user.comments %}
            <li class="list-group-item">
                <span class="glyphicon-leaf" aria-hidden="true"></span>
                <a href="#" target="_blank">{{ foo.author.username }}</a>
                <span class="badge">发布时间:{{ foo.creat_time }}</span>
                <p style="text-indent: 18px">{{ foo.detail }}</p>
            </li>
            {% endfor %}
        </ul>
    </div>
    <hr>#}
    <div class="page-header">
        <h3>个人信息</h3>
        <ul class="list-group">
            <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">文章篇数:</li>
        </ul>
    </div>
    </div>

{% endblock %}

 

(19)个人中心标签页导航

效果:

 

代码:

  1. 新页面user.html,用<ul ><li role="presentation"> 实现标签页导航。
    <ul class="nav nav-tabs">
      <li role="presentation"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages</a></li>
    </ul>
    复制代码
     <ul class="nav nav-tabs">
        <li class="nav-item">
          <a class="nav-link" href="#">全部问题</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">全部评论</a>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled" href="#">个人信息</a>
        </li>
      </ul>
    复制代码


  2. user.html继承base.html。
    重写title,head,main块.
    将上述<ul>放在main块中.
    定义新的块user。
    复制代码
    {% extends '1101.html' %}
    {% block title %}个人中心{% endblock %}
    {% block head %}
    <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css">
    
    {% endblock %}
    
    {% block main %}
    <div style="padding-left: 300px;padding-right: 300px">
        <ul class="nav nav-pills">
            <li class="active"><a href="#">问答平台</a></li>
            <li><a href="#">全部评论</a></li>
            <li><a href="#">个人资料</a></li>
    
        </ul>
    </div>
    {% block user %}{% endblock %}
    {% endblock %}
    复制代码


  3. 让上次作业完成的个人中心页面,继承user.html,原个人中心就自动有了标签页导航。
    复制代码
    {% extends 'user.html' %}
    {% block user %}
    <div style="padding-left: 300px;padding-right: 300px">
        <div class="page-header">
            <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ username }}</h3>
            <small>全部问答</small>
            <br>
            <ul class="note-list" style="padding-left: 0px;">
                {% for foo in questions %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                    <a href="#">{{ foo.author.username }}</a>
                    <br>
                    <a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a>
                    <span class="badge">{{ foo.time }}</span>
                    <p>{{ foo.detail }}</p>
    
                </li>
                {% endfor %}
            </ul>
        </div>
        <div class="page-header">
            <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ username }}</h3>
            <small>全部评论</small>
            <br>
            <ul class="note-list" style="padding-left: 0px;">
                {% for foo in comments %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                    <a href="#">{{ foo.author.username }}</a>
                    <span class="badge">{{ foo.time }}</span>
                    <br>
                    <p>{{ foo.detail }}</p>
    
                </li>
                {% endfor %}
            </ul>
    
        </div>
    </div>
    {% endblock %}
    复制代码


  4. 重写user.html中定义的user块。
    {% extends'userbase.html' %}
    
    {% block user %}
        <div class="page-header">
        <br>
        <h3>全部分享</h3>
        <br>
            <ul class="list-group" style="background-size: contain">
                {% for foo in user.question %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
                    <a href="#" target="_blank">{{ foo.author.username }}</a>
                    <span class="badge">发布时间:{{ foo.creat_time }}</span>
                    <p style="text-indent: 18px">{{ foo.detail }}</p>
                </li>
                {% endfor %}
            </ul>
        </div>
    {% endblock %}
    {% extends'userbase.html' %}
    
    {% block user %}
        <div class="page-header">
        <br>
            <h3>全部书评</h3>
        <br>
            <ul class="list-group" style="background-size: contain">
                {% for foo in user.comments %}
                <li class="list-group-item">
                    <span class="glyphicon-leaf" aria-hidden="true"></span>
                    <a href="#" target="_blank">{{ foo.author.username }}</a>
                    <span class="badge">发布时间:{{ foo.creat_time }}</span>
                    <p style="text-indent: 18px">{{ foo.detail }}</p>
                </li>
                {% endfor %}
            </ul>
        </div>
    {% endblock %}
    {% extends'userbase.html' %}
    
    {% block user %}
        <div class="page-header">
        <br>
            <h3>个人信息</h3>
            <br>
            <ul class="list-group">
                <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">评论篇数:{{comments|length}}</li>
                <li class="list-group-item">文章篇数:{{questions|length}}</li>
            </ul>
        </div>
    {% endblock %}

     

(20)实现搜索功能

效果:

 

代码:

 

  1. 准备视图函数search()
  2. 修改base.html 中搜索输入框所在的
    1. <form action="{{ url_for('search') }}" method="get">
    2.    <input name="q" type="text" placeholder="请输入关键字">

  3. 完成视图函数search()
    1. 获取搜索关键字
      q = request.args.get('q’)
    2. 条件查询
      qu = Question.query.filter(Question.title.contains(q)).order_by('-creat_time’)
    3. 加载查询结果:
      return render_template('index.html', question=qu)

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

 

示例:

Lobby.query.filter(

    or_(

        and_(

            Lobby.id == Team.lobby_id,

            LobbyPlayer.team_id == Team.id,

            LobbyPlayer.player_id == player.steamid

        ),

      and_(

            Lobby.id == spectator_table.c.lobby_id,

            spectator_table.c.player_id == player.steamid

        )

    )

)

from sqlalchemy import or_,and_

@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',questions=ques)

<form action="{{ url_for('search') }}" method="get"  class="navbar-form navbar-left">
        <input name="q" type="text" class="form-control" placeholder="请输入关键字">
        <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search" aria-hidden="true"></span>查找</button>
    </form>

 

(21)密码保护

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

class User(db.Model):

    __tablename__ = 'user' 

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

 

复制代码
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))
复制代码

 

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)

 

复制代码
 @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
复制代码

 

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):

 

复制代码
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method=='GET':
        return render_template('login.html')
    else:
        usern = request.form.get('username')
        passw = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            if user.check_password(passw):
                session['user']=usern
                session['userid']=user.id
                session.permanent = True
                return redirect(url_for('index'))
            else:
                return 'password error.'
        else:
            return 'username is not existed.'
复制代码

 

(22)数据迁移

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

class User(db.Model):

    __tablename__ = 'user' 

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

 

复制代码
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))
复制代码

 

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)

 

复制代码
 @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
复制代码

 

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):

 

复制代码
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method=='GET':
        return render_template('login.html')
    else:
        usern = request.form.get('username')
        passw = request.form.get('password')
        user = User.query.filter(User.username == usern).first()
        if user:
            if user.check_password(passw):
                session['user']=usern
                session['userid']=user.id
                session.permanent = True
                return redirect(url_for('index'))
            else:
                return 'password error.'
        else:
            return 'username is not existed.'
复制代码

posted @ 2018-01-05 13:41  袁颖琳  阅读(333)  评论(1编辑  收藏  举报