个人学期总结

总结Python+Flask+MysqL的web建设技术过程,标准如下:

  1. 即是对自己所学知识的梳理
  2. 也可作为初学入门者的简单教程
  3. 也可作为自己以后复习的向导
  4. 也是一种向外展示能力的途径

这篇文章总结了我这个学期的学习结果:使用Flask框架搭建一个可扩展的小型web service,并在其中加上一些原理的阐述或者链接,并用上一些简单的css,js,html。

一、 Flask & 概览

下面是Flask最简单的一个示例,这篇文章要做的就是将其充实、扩展、拆分,使代码具有良好的可扩展性和可读性。

from flask import Flask
app = Flask(__name__)

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

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

上述代码中的route方法是一个装饰器。这里我们使用python3.5的解释器,可以实现static文件、templates文件与py文件。

二.数据库连接池

项目使用了MySQL数据库和Redis数据库,根据不同情况选择使用。

MySQL

pip安装flask-sqlalchemy。sqlalchemy是实现ORM的库,然后进行数据库连接,用mysql创建数据库:

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


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

当要使用数据库时,调用db即可。

然后进行数据库配置信息config.py:

import os

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

SECRET_KEY =os.urandom(24)

下一步是建立mysql和app的连接。

最后创建用户模型。

 三.通过用户模型,对数据库进行增删改查

from flask import Flask
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=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    password = db.Column(db.String(20),nullable=False)
    nickname = db.Column(db.String(20))
#db.create_all()

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


#
user =User(username='krislst',password='666666')
db.session.add(user)
db.session.commit()

#
user =User(username='krislst',password='666666')
db.session.delete(user)
db.session.commit()

#
user =User.query.filter(User.username=='krislst').first()
user.username ='kriswu'
print(user.username,user.password)
db.session.add(user)
db.session.commit()

@app.route('/')
def hello_world():
    return 'Hello World!'


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

四.完整的注册接口

@app.route('/zhuce/', methods=['GET', 'POST'])
def zhuce():
    if request.method == 'GET':
        return render_template("zhuce.html")
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        user = User.query.filter(User.username == username).first()
        if user:
            return '用户名已存在'
        else:
            user = User(username=username, password=password)
            db.session.add(user)  # 数据库,添加操作
            db.session.commit()
            return redirect(url_for('denglu'))

五.完成登录功能

@app.route('/denglu/', methods=['GET', 'POST'])
def denglu():
    if request.method == 'GET':
        return render_template("denglu.html")
    else:
        username = request.form.get('username')
        password= request.form.get('password')
        user = User.query.filter(User.username == username).first()
        if user:
            if user.check_password(password):
                session['user']=username
                session['userid'] =user.id
                session.permanent = True
                return redirect(url_for('base'))
            else:
                return '密码错误'
        else:
            return '用户名不存在'

设置JS:

function foLogin() {
            var oUname = document.getElementById("uname");
            var oError = document.getElementById("error_box");
            var oUpass = document.getElementById("upass");

            var isError = true;
            oError.innerHTML = "<br>";

            if (oUname.value.length < 6 || oUname.value.length > 12) {
                oError.innerHTML = "用户名要6-12位";
                isError = false;
                return;
            }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)<58)&&(oUname.value.charCodeAt(i)>97)){
                oError.innerHTML="只能为数字和字母";
                isError = false;
                return isError;
            }
            }
            if (oUpass.value.length < 6 || oUpass.value.length > 12) {
                oError.innerHTML = "密码要6-20位";
                isError = false;
                isError = false;
                return isError;
             }
            return true;
            }

六.登录之后更新导航功能

用上下文处理器app_context_processor定义函数

  1. 获取session中保存的值
  2. 返回字典
    from flask import Flask,render_template,request,redirect,url_for,session
    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=True, autoincrement=True)
        username = db.Column(db.String(20), nullable=False)
        password = db.Column(db.String(20), nullable=False)
    
        db.create_all()
    
    @app.route('/')
    def index():
        return render_template('index.html')
    
    @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,User.password==passw).first()
            if user:
                session['user']=usern
                session.permanent=True
                return redirect(url_for('index'))
            else:
                return u'error username or password'
    
    @app.route('/regist/',methods=['get','post'])
    def regist():
        if request.method=='GET':
            return render_template('regist.html')
        else:
            usern=request.form.get('username')
            passw =request.form.get('password')
            user=User.query.filter(User.username==usern).first()
            if user:
                return u'username existed'
            else:
                user1=User(username=usern,password=passw)
                db.session.add(user1)
                db.session.commit()
                return redirect(url_for('login'))
    
    @app.route('/logout/')
    def logout():
        session.clear()
        return redirect(url_for('index'))
    
    @app.context_processor
    def context():
        username = session.get('user')
        if username:
            return {'username':username}
        else:
            return()
    
    if __name__ == '__main__':
        app.run(debug=True)

    然后在父模板中更新导航,插入登录状态判断代码。

    1. 注意用{% ... %}表示指令。
    2. {{ }}表示变量

    最后完成注销功能。

    1. 清除session
    2. 跳转

 七.完成发布功能

  • 编写要求登录的装饰器

from functools import wraps

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

@wraps(func)

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

          #要求登录

          return func(*args, ** kwargs)

      return wrapper #返回一个函数

from functools import wraps
def loginFrist(func):
    @wraps(func)
    def wrappers(*args, **kwargs):
        if session.get('user'):
            return func(*args, **kwargs)
        else:
            return redirect(url_for('login'))

    return wrappers
  • 应用装饰器,要求在发布前进行登录,登录后可发布。
@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():

 

  • 建立发布内容的对象关系映射。
class Question(db.Model):
  • 完成发布函数。

      保存到数据库。

      重定向到首页。

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

八.制作首页的显示列表

 第一,在首页添加显示问答的列表,并定义好相应的样式。

无序列表

<ul >

  <li>Coffee</li>

  <li>Tea</li>

  <li>Milk</li>

</ul>

html{% extends 'base.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/index.css">
{% endblock %}
{% block main %}
    <div class="question-box">
        <img src=https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg style="width: 50px">
        <ul class="list-group">
            <li clsss="list=group-item">
                <span class="glyphicon glyhicon-leaf" aria-hidden="true"></span>
                <a href="https://wx2.sinaimg.cn/mw690/637dee21ly1fm12yb1cqrj20w01d8tq1.jpg">Kris wu{{ user }}</a><br>
                <a href="https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg">最新街拍{{ title }}</a><br>
             <span class="badge">上线时间{{ time }}</span>
                <p style="color: indianred">pictures{{ detail }}
                </p>
                <div class="img">
                    <a herf="https://wx2.sinaimg.cn/mw690/637dee21ly1fm12yb1cqrj20w01d8tq1.jpg">
                        <img src="https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg"></a>
                    <div class="desc"><a href="https://wx2.sinaimg.cn/mw690/72ae04f1gy1fm1282v31sj218g1wde82.jpg>burberry</a></div>
                </div>
            </li>
        </ul>
        </div>
{% endblock %}

 

第二步. 用字典向index.html传递参数。

@app.route('/index/')
def index():
     context={
        'user':'kriswu:',
        'title': '最新街拍',
        'time': 'today',
        'detail':'burberry*kriswu'}
     return render_template('index.html',**context)

九.从首页问答标题到问答详情页

1.主PY文件写视图函数,带id参数。 

@app.route('/detail/<question_id>')
def detail(question_id):
    quest = 
    return render_template('detail.html', ques = quest) 

 

2.首页标题的标签做带参数的链接。
      {{ url_for('detail',question_id = foo.id) }}

 {% for foo in questions %}

            <li class="list-group-item" style="width: 600px">
                <a class="wrap-img" href="#" target="_blank">
                    <img src="{{ foo.author.image }}" width="35px">
                </a>
                <span class="glyphicon glyphicon-left" aria-hidden="true"></span>
                <a href="#" target="_blank">{{ foo.author.username }}</a>
                <br>
                <a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a>

                <br>
                <span class="badge">发布时间:{{ foo.creat_time }}</span>
                <p style="">{{ foo.detail }}
                </p>

            </li>
        {% endfor %}

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

{{ ques.title}}
{{ ques.id  }}{{  ques.creat_time }}
{{ ques.author.username }} 
{{ ques.detail }}

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

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

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

十.完成评论功能

1.定义评论的视图函数
@app.route('/comment/',methods=['POST'])
def comment():
读取前端页面数据,保存到数据库中

@app.route('/comment/',methods=['POST'])
def comment():
     comment =request.form.get('new_comment')
     ques_id =request.form.get('question_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'))

 

2.用<input type="hidden" 方法获取前端的"question_id" 

 <input name="question_id" type="hidden" value="{{ques.id}}"/>

 

3.显示评论次数

  <h4>评论({{ ques.comments|length }}</h4>

 

4.要求评论前登录

@app.route('/comment/',methods=['POST'])
@loginFrist
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))

 

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

{% for com in ques.comment %}

    <a href="#" >{{ com.author.username }}</a>
    <small>{{ com.creat_time }}</small>
    <p class="">{{ com.detail }}</p>
    {% endfor %}

十一.评论列表显示及排序,个人中心显示

 

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

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

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

  4. 完成个人中心

 

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

 

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

 

3.向前端页面传递参数

 

4.页面显示相应数据

 

发布的全部问答

 

发布的全部评论

 

个人信息

 

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

{% extends "base.html" %}
{% block detailtitle%}问答详情{% endblock %}
 
{% block detailhead %}
{% endblock %}
 
{% block mywebbody %}
 
    <div class="page-header" style="color: pink" align="center">
        <h3>{{ ques.title }}<br><small>{{ ques.author.username }} <span class="badge">{{ ques.creat_time }}</span> </small></h3>
 
 
    </div>
    <p class="lead">{{ ques.detail }}</p>
    <hr>
 
    <form action="{{ url_for('comment') }}"method="post">写评论
        <div class="form-group">
            <textarea name="new_comment"class="form-control"rows="3"id="new-comment"placeholder=""></textarea>
            <input type="hidden" name="question_id" value="{{ ques.id }}">
        </div>
        <button type="submit"class="btn btn-default">发送</button>
    </form>
    <h4>评论:({{ ques.comments|length }})</h4>
 
    <ul class="list-group"style="margin:10px">
        {% for foo in ques.comments %}
        <li class="list-group-item">
            <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
            <a href="{{url_for('usercenter',user_id=foo.author.id)}}">{{foo.author.username }}</a>
            <span class="badge">{{foo.creat_time}}</span>
            <p style="">{{foo.detail}}</p>
        </li>
{% endfor %}
    </ul>
 
{% endblock %}
usercenter.html
{% extends 'base.html' %}
{% block title %}个人中心 {% endblock%}
{% block main%}
 
<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="">
        {% for foo in user.question %}
            <li class="list-group-item">
                <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
                <a href="#">{{foo.author.username }}</a>
                <span class="badge">{{foo.creat_time}}</span>
                <p style="">{{foo.detail}}</p>
            </li>
    {% endfor %}
    </ul>
</div>
 详情
<div class="page-header">
     <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>
    {{user}} <br> <small>个人信息><span class="badge"></span> </small></h3>
    <ul class="list-group" style="">
          {% for foo in user.comments %}
            <li class="list-group-item">
                <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
                <a href="#">{{foo.author.username }}</a>
                <span class="badge">{{foo.creat_time}}</span>
                <p style="">{{foo.detail}}</p>
            </li>
    {% endfor %}
    </ul>
</div>
 
<div class="page-header">
     <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>
    {{user}} <br> <small>个人信息><span class="badge"></span> </small></h3>
      <ul class="list-group" style="">
          <li class="list-group-item">user:{{username}}</li>
          <li class="list-group-item">number:</li>
          <li class="list-group-item">nickname:</li>
          <li class="list-group-item">评论数量:</li>
      </ul>
</div>
 
{% endblock %}

十二.个人中心标签页导航及导航标签

新页面userbase.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>

  1. 让userbase.html继承base.html。
    重写title,head,main块.
    将上述<ul>的样式放在head块,<ul>放在main块中.
    定义新的块user。
  2. 继承userbase.html,原个人中心就自动有了标签页导航。
  3. 制作个人中心的三个子页面,重写userbase.html中定义的user块,分别用于显示问答、评论、个人信息。

 

 

    1. 个人中心—视图函数带标签页面参数tag
      @app.route('/usercenter/<user_id>/<tag>')
      def usercenter(user_id, tag):
         if tag == ‘1':
             return render_template('usercenter1.html', **context)

    2. 个人中心—导航标签链接增加tag参数
      <li role=“presentation”><a href=“{{ url_for(‘usercenter’,user_id = user.id,tag = ‘1’) }}">全部问答</a></li>

    3. 个人中心—有链接到个人中心页面的url增加tag参数
       <a href="{{ url_for('usercenter',user_id = session.get('userid'), tag=1) }}">{{ session.get('user') }}</a>

 

usercenter
{% extends "userbase.html" %}

{% block usercenterbody %}
    <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 foo in comments %}
                <li class="list-group-item">
                    <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
                    <a href="#">{{ foo.user.username }}</a>
                    <span class="badge">{{ foo.creat_time }}</span>
                    <p style="align-content: center">{{ foo.detail }}</p>
                </li>
            {% endfor %}
        </ul>
    </div>

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

    </div>

    <div class="page-header">
        <h3><span class="glyphicon glyphicon-user" aria-hidden="true"></span>{{ user }}<br><small>个人信息<span class="badge>"></span> </small> </h3>
        <ul class="list-group"style="margin:10px">
            <li class="list-group-item">user:{{ username }}</li>
            <li class="list-group-item">number:</li>
            <li class="list-group-item">nickname:</li>
        </ul>
    </div>
{% endblock %}

 

@app.route('/usercenter/<user_id>/<tag>')
@log
def  usercenter(user_id,tag):
     user=User.query.filter(User.id==user_id).first()
     context={
        'username':user.username,
        'questions':user.question,
        'comments':user.comments
    }
     if tag =='1':
          return render_template('wenda.html',**context)
     elif tag =='2':
          return render_template('comment.html',**context)
     else :
          return render_template('grxx.html',**context)
detail.html
 <a href="{{ url_for('usercenter',user_id=ques.author_id,tag=1) }}">{{ ques.author.username }}</a>

base.html
<li><a href="{{ url_for('usercenter',user_id=session.get('user_id'),tag=1)}}">{{session.get('user')}}</a></li>

index.html
 <li><a href="{{ url_for('usercenter',user_id=foo.author_id,tag=1)}}">{{foo.author.username }}</a></li>

十三.实现搜索功能

 

    1. 准备视图函数search()

    2. 修改base.html 中搜索输入框所在的
      1. <form action="{{ url_for('search') }}" method="get">
      2.    <input name="q" type="text" placeholder="请输入关键字">
          <form action="{{ url_for('search')}}" method="get"></form>
                       <div class="form-group">
            <input type="text" class="form-control" placeholder="please input key words">
             <button type="submit" class="btn btn-default">搜索</button>
         </div>

         

    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_ 

 

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

 

十四.实现密码保护

 

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

 

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)

 

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..登录验证:

@app.route('/denglu/', methods=['GET', 'POST'])
def denglu():
    if request.method == 'GET':
        return render_template("denglu.html")
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        user = User.query.filter(User.username == username).first()
        if user:
            if user.check_password(password):
                session['user']=username
                session['user_id'] =user.id
                return redirect(url_for('base'))
            else:
                return '密码错误'
        else:
            return '用户名不存在'

总结及展望

以上是这个学期在Python+Flask+MysqL的web建设技术过程学习内容的总结和梳理,通过这些知识我算是在python web入门,也了解到这方面许多需求和知识,如有疏漏请谅解。我会继续努力,在这方面加强学习,希望可以学得更好。still i rise!

 

posted on 2018-01-05 11:15  lishanting  阅读(139)  评论(0)    收藏  举报