初识 Flask

一. Python 现阶段三大主流Web框架 Django Tornado Flask 对比

1.Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架

2.Tornado 主要特点是原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优势,属于专注型框架

3.Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架

Django 通常用于大型Web应用由于内置组件足够强大所以使用Django开发可以一气呵成

Tornado 通常用于API后端应用,游戏服务后台,其内部实现的异步非阻塞真是稳得一批

Flask 通常应用于小型应用和快速构建应用,其强大的三方库,足以支撑一个大型的Web应用

Django 优点是大而全,缺点也就暴露出来了,这么多的资源一次性全部加载,肯定会造成一部分的资源浪费

Tornado 优点是异步,缺点是干净,连个Session都不支持

Flask 优点是精悍简单

总结:

Flask:
    优点:小而精,短小精悍,第三方组件特别多
    缺点:组件更新速度取决于开源者,你不会
    
Tornado:
    优点:原生的WebSocket,异步任务,IO非阻塞
    缺点:组件没有,Session都没有
    
Django:
    优点:大而全,组件非常全面
    缺点:太大,加载太大,浪费资源

 二、Flask 的安装与简单使用

pip install Flask

最简单的Flask项目,Flask三行:

from flask import Flask
    apl = Flask(__name__)
    apl.run()

三、三种返回页面的方式

from flask import Flask, render_template, redirect

# 一个flask对象
app = Flask(__name__)

STUDENT_LIST = [ {'name': 'Old', 'age': 38, 'gender': '中'},
           {'name': 'Boy', 'age': 73, 'gender': '男'},
           {'name': 'EDU', 'age': 84, 'gender': '女'} ]
# render 注意, templates文件要和当前py文件同级,不然会找不到,报一个Jinja2的异常哦 @app.route('/index') def index(): html_msg = '<h1>my html</h1>' markup_tag = Markup(html_msg) # 相当于在html页面加上 safe ,这里写了,前端页面就不用写了 return render_template('index.html', stu=STUDENT_LIST, markup_tag=markup_tag, tag="") # HTTPResponse @app.route('/') def one_test(): return 'hello girl' # redirect @app.route('/hello') def hello(): return redirect('/index')


if __name__ == '__main__':
    # debug模式运行
    app.run(debug=True)

四、模版语言

1.模版函数

2、数据安全

3、 for if 等的用法和django里的一样

4、模版继承的用法也和django一样,就不写了

举个栗子:

在 app.py 中

#########  在Jinja2中执行Python函数(模板中执行函数) ############
@app.template_global()  # 定义全局模板函数
def a_b_sum(a, b):
    return a + b


@app.template_filter()  # 定义全局模板函数
def a_b_c_sum(a, b, c):
    return a + b + c


def index():
    html_msg = '<h1>my html</h1>'
    markup_tag = Markup(html_msg)  # 相当于在html页面加上 safe ,这里写了,前端页面就不用写了
    return render_template('index.html', stu=STUDENT_LIST, markup_tag=markup_tag, tag="")

在index.html页面里

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <!-- 在Jinja2中执行Python函数(模板中执行函数) -->
     {{ a_b_sum(99,1) }}
    <br>
    {{ 1 | a_b_c_sum(197,2) }}

    <!-- 插入 markup 处理后的html标签 -->
    {{ markup_tag }}     

  <table>
      <thead>
      <tr>
          {% for foo in stu[0] %}
            <td>{{ foo }}</td>
          {% endfor %}
      </tr>
      </thead>
      <tbody>
        {% for st in stu %}
            <tr>
                {% for t in st %}
                    <td>{{ st[t] }}</td>
                {% endfor %}

            </tr>
        {% endfor %}
      </tbody>
  </table>

</body>
</html>

五、一个简单的登录认证

1、request 的使用

2、session的应用

  • Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪
  • secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的
  • cookies 中 session 存储的是通过 secret_key 加密后的 key , 通过这个 key 从flask程序的内存中找到用户对应的session信息

3、装饰器的使用及遇到的问题

4、类似Django中间件,.@app.before_request 和 @app.after_request    errorheadler

先看代码吧~

在app.py中:

from flask import Markup  # 导入 flask 中的 Markup 模块 
from flask import Flask, render_template, redirect 
from flask import request 
from flask import session

# 一个flask对象 
app = Flask(__name__) 
# cookies 中 session 存储的是通过 secret_key 加密后的 key , 通过这个 key 从flask程序的内存中找到用户对应的session信息 
app.secret_key = "LYJ" 

import functools

# 一个认证装饰器
def my_auth(func):
    @functools.wraps(func)
    def war(*args, **kwargs):
        if session.get('user'):
            return func()
        else:
            return redirect('/login')

    return war


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        print(request.form)  # ImmutableMultiDict([('username', 'qwe'), ('pwd', '123')])
        username = request.form['username']  # 以字典方式取值
        pwd = request.form.get('pwd')
        print(username, pwd)

        # session的应用
        session['user'] = username
        return redirect('/index')
    if request.method == 'GET':
        return render_template('login.html')


# 认证,自定义装饰器的使用
@app.route('/index2', endpoint='index2')
@my_auth
def index2():
    return redirect('/index')  #用的是示例模版的那个index


@app.route('/index3', endpoint='index3')
@my_auth
def index3():
    return redirect('/index')


#  AssertionError: View function mapping is overwriting an existing endpoint function: war
# 因为在经过装饰器后 func 的 __name__都变成了装饰器的名字,所以 route 在处理时,会取到多个一样的方法名
# 有两种解决办法 1、 在装饰器中加上 装饰器修复  @functools.wraps(func)  2、 用endpoint给传入route的函数命名: @app.route('/index3',endpoint='index3')


if __name__ == '__main__':
    # debug模式运行
    app.run(debug=True)

 

如果直接加装饰器的话,会报错

AssertionError: View function mapping is overwriting an existing endpoint function: war

 原因:在经过装饰器后 func 的 __name__都变成了装饰器的名字,所以 route 在处理时,会取到多个一样的方法名
有两种解决办法 

1、 在装饰器中加上 装饰器修复  @functools.wraps(func) 

2、 用endpoint给传入route的函数命名: @app.route('/index3',endpoint='index3')

注意:

  装饰器应该放在最靠近函数的地方,因为装饰器的执行顺序是从最靠近的那个开始的,不这样写的话会不行该函数,详见:多个装饰器的执行顺序

 另一种处理登录认证的方式,类似于Django的中间件 

1.@app.before_request 在请求(request)之前做出响应

from flask import Flask
from flask import request
from flask import redirect
from flask import session

app = Flask(__name__)  # type:Flask
app.secret_key = "DragonFire"


@app.before_request
def is_login():
    if request.path == "/login":
        return None

    if not session.get("user"):
        return redirect("/login")


@app.route("/login")
def login():
    return "Login"


@app.route("/index")
def index():
    return "Index"


@app.route("/home")
def home():
    return "Login"


app.run("0.0.0.0", 5000)

@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数之前执行

request.path 是来读取当前的url地址如果是 /login 就允许直接通过 return None 你可以理解成通过放行

校验session中是否有user 如果没有的话,证明没有登录,所以毫不留情的 redirect("/login") 跳转登录页面

还有一个要提的 @app.before_first_request 它与 @app.before_request 极为相似或者说是一模一样,只不过它只会被执行一次

 

2. @app.after_request 在响应(response)之前做出响应

@app.after_request
def foot_log(environ):
    if request.path != "/login":
        print("有客人访问了",request.path)
    return environ

3. errorheadler(404) 定义错误信息

def error_page(arg)
      错误信息头

4、flash 导入  

  flash("message")
  get_flashed_messages() 导入

一存放,一提取,消失 

很少应用,但是要了解有这么个东西

posted @ 2018-08-20 23:05  道友请多指教  阅读(273)  评论(0编辑  收藏  举报