Flask程序运行过程

  • 所有Flask程序必须有一个程序实例。
  • 当客户端想要获取资源时,一般会通过浏览器发起HTTP请求。
  • 此时,Web服务器使用WSGI(Web Server Gateway Interface)协议,把来自客户端的所有请求都交给Flask程序实例,程序实例使用Werkzeug来做路由分发(URL请求和视图函数之间的对应关系)。
  • 根据每个URL请求,找到具体的视图函数并进行调用。
    • 在Flask程序中,路由的实现一般是通过程序实例的装饰器实现。
  • Flask调用视图函数后,可以返回两种内容:
    • 字符串内容:将视图函数的返回值作为响应的内容,返回给客户端(浏览器)
    • HTML模版内容:获取到数据后,把数据传入HTML模板文件中,模板引擎负责渲染HTTP响应数据,然后返回响应数据给客户端(浏览器)

示例:

  • 新建文件hello.py
  • 导入Flask类
  • Flask函数接收一个参数name,它会指向程序所在的模块
  • 装饰器的作用是将路由映射到视图函数index
  • Flask应用程序实例的run方法启动WEB服务器

# -*- coding:utf-8 -*-


from flask import Flask, render_template


# 第一个参数:表示当前应用运行的模块名字,并且可以决定从哪里查找静态文件
# 如果传入的模块名字不存在的,会从当前应用运行的模块查找静态文件
# 如果传入的模块名字是存在的,会从传入的模块名中加载静态文件
app = Flask(__name__,
static_url_path='/python', # 指定静态文件加载时url的前缀
static_folder='static', # 指定静态文件存放我文件夹
template_folder='templates') # 指定模板文件存储的文件夹,《默认从项目的根路径查找模板》


@app.route('/')
def index():
# return 'index'

# 响应模板
return render_template('index.html')


if __name__ == '__main__':
app.run(debug=True, port=5001, host='192.168.72.58')

 

  • 在程序运行过程中,程序实例中会使用 url_map 将装饰器路由和视图的对应关系保存起来,打印结果如下图:

  Flask02-从 Hello World 开始

 

 

 

配置参数

  • app.config.from_pyfile() # 从配置文件中加载
  • app.config.from_object() # 从对象中加载
  • app.config.from_envvar() # 从环境变量中加载# -*- coding:utf-8 -*-

# 导入Flask
from flask import Flask

class Config(object):
    """加载配置参数的类  等价于django中的setting"""
    # 开启调试模式
    DEBUG = True


# 创建Falsk应用实例
app = Flask(__name__)


# 加载配置:从对象中加载配置参数
# app.config.from_object(Config)
# 加载配置:从配置文件中加载配置参数
# app.config.from_pyfile('config.conf')
# 加载配置:从环境变量中加载配置参数
# app.config.from_envvar('envvar_config')
# app.config['DEBUG'] = True
app.debug = True


# 定义视图函数,并绑定路由
@app.route('/')
def index():
    # 演示异常
    a = 10 / 0
    return 'index'

# 启动该应用的入口 if __name__ == '__main__': # 启动应用 app.run()

 

读取配置参数

  • app.config.get()
  • 在视图中 current_app.config.get()

      

app.run的参数

  • app.run(host=”0.0.0.0”, port=5000, debug = True)

 

    

# -*- coding:utf-8 -*-


from  flask import Flask, request


app = Flask(__name__)

# 
@app.route('/', methods=['GET', 'POST'])
def index():
    method = request.method
    return 'index %s' % method


@app.route('/index2')
def index2():
    return 'index2'


if __name__ == '__main__':

    # 打印路由和视图的映射关系
    print app.url_map

    app.run(debug=True)

 

给路由传参示例

有时我们需要将同一类URL映射到同一个视图函数处理,比如:使用同一个视图函数 来显示不同用户的个人信息。

路由传递的参数默认当做string处理,这里指定int,尖括号中的内容是动态的,也可不指定类型

@app.route('/user/<int:id>')
def hello_itheima(id):
    return 'hello world %d' %id

 

重定向redirect示例,反向解析,重新定向穿参

# -*- coding:utf-8 -*-

from flask import Flask, redirect, url_for

app = Flask(__name__)


@app.route('/')
def index():
    return 'index'


@app.route('/demo1')
def demo1():
    # 重定向到外网
    # return redirect('http://www.baidu.com')
    # 重定向到内部路由
    # return redirect('/')
    # 重定向使用反向解析  传入视图名字: url_for('index') == '/'
    return redirect(url_for('index'))


# 以下代码演示重定向并传参
@app.route('/order/<int:order_id>')
def order(order_id):
    return 'order %s' % order_id


@app.route('/demo2')
def demo2():
    return redirect(url_for('order', order_id='123'))   # url_for第一个参数为路由名字,第二个为参数名字

if __name__ == '__main__':
    print app.url_map
    app.run(debug=True)

 

路由转换器:BaseConverter &正则

基础版本:

# -*- coding:utf-8 -*-

from flask import Flask, redirect, url_for
from werkzeug.routing import BaseConverter


class RegexConverter(BaseConverter):
    """自定义路由正则转换器:实现order_id必须是三位数字"""

    # 该类属性用于匹配order_id
    regex = r'\d{3}'


app = Flask(__name__)


# 将自定义的路由正则转换器,添加到默认的转换器列表中
app.url_map.converters['re'] = RegexConverter


@app.route('/')
def index():
    return 'index'

@app.route('/')
def index2():
    return 'index2'


# 需求: order_id必须是三位数字
@app.route('/order/<re:order_id>')
def order(order_id):

    print type(order_id)

    return 'order %s' % order_id


@app.route('/demo')
def demo():
    return redirect(url_for('order', order_id='123'))


if __name__ == '__main__':
    print app.url_map
    app.run(debug=True)

 

升级版本:

# -*- coding:utf-8 -*-


from flask import Flask, redirect, url_for
from werkzeug.routing import BaseConverter


class RegexConverter(BaseConverter):
    """实现外界传入什么正则,我就匹配什么条件"""

    def __init__(self, url_map, *args):
        super(RegexConverter, self).__init__(url_map)

        self.regex = args[0]

    # 机制:在匹配成功之后,MapAdapter执行匹配和调用视图函数,调用视图函数之前,可以得到要匹配的参数
    # 作用:可以在这个方法中,对要匹配的参数进行进一步的处理,比如转换数据类型
    def to_python(self, value):
        value = int(value)
        return value

    # 需要搭配url_for使用的
    # 机制:在匹配成功之前,在视图函数调用之前,获取要匹配的参数
    # 作用:可以在这个方法中,对要匹配的参数进行第一次的处理,比如对不合格的参数进行校正或者修复,尽量满足正则
    # 保证能够顺利的进入到to_python
    # 只要能够进入到to_python就说明匹配成功,匹配成功视图函数才会调用
    def to_url(self, value):
        return value


app = Flask(__name__)


# 将自定义的路由转换器的类添加到默认的转换器列表中
app.url_map.converters['re'] = RegexConverter


@app.route('/')
def index():
    return 'index'


@app.route('/order/<re("\d{3}"):order_id>')
def order(order_id):
    return 'order %s' % order_id


@app.route('/demo')
def demo():
    return redirect(url_for('order', order_id='12'))


if __name__ == '__main__':
    print app.url_map
    app.run(debug=True)

 

defultconverter.py

# -*- coding:utf-8 -*-

from flask import Flask


app = Flask(__name__)


@app.route('/<any("hehe, help, imprint, class, "foo,bar""):page_name>')
def any(page_name):
    return 'page_name %s' % page_name

@app.route('/<uuid:uuid_num>')
def test_uuid(uuid_num):
    return 'uuid %s' % uuid_num


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

 

返回JSON

# -*- coding:utf-8 -*-

from flask import Flask, json, jsonify


app = Flask(__name__)


@app.route('/json2')
def json2():

    # 定义字典:方便转json
    json_dict = {
        'name':'zxc',
        'age':18
    }

    # Content-Type: application/json
    # 工作中使用的
    return jsonify(json_dict)


@app.route('/json1')
def json1():

    # 定义字典:方便转json
    json_dict = {
        'name':'zxc',
        'age':18
    }

    # Content-Type: text/html; charset=utf-8
    return json.dumps(json_dict)


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

 

状态码

- 直接return 
    - 可以自定义返回状态码,可以实现不符合http协议的状态码,例如:error=666,errmsg='查询数据库异常',其作用是为了实现前后端数据交互的方便
- abort方法
    - 只会抛出符合http协议的异常状态码,用于手动抛出异常
自定义响应头和状态码
Flask02-从 Hello World 开始

 

 Flask02-从 Hello World 开始

 

 

# -*- coding:utf-8 -*-

from flask import Flask, abort


app = Flask(__name__)


@app.route('/')
def index():
    # 演示异常
    a = 10 / 0
    return 'index', 666, {'name':'zxj'}

@app.route('/demo1')
def demo1():
    abort(404)


@app.errorhandler(404)
def demo2(e):
    """专门捕获指定的状态码异常信息,然后处理异常"""
    print e
    return '服务器搬家了'


@app.errorhandler(ZeroDivisionError)
def demo3(e):
    """专门捕获指定的异常信息,然后处理异常"""
    print e
    return '写这个代码的程序员已经祭天了'



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

 

request.py

Flask02-从 Hello World 开始

 

 

# -*- coding:utf-8 -*-

from flask import Flask, request


app = Flask(__name__)


# http://127.0.0.1/upload?name=zxc&age=18
@app.route('/upload', methods=['POST'])
def upload():

    print request.url, request.method

    # 获取查询字符串
    name = request.args.get('name')
    age = request.args.get('age')

    # 演示表单数据的读取
    pic = request.files.get('pic')
    pic.save('./123.jpg')

    return 'index %s %s' % (name, age)


# http://127.0.0.1/index1?name=zxc&age=18
@app.route('/index1', methods=['POST'])
def index1():

    print request.url, request.method

    # 获取查询字符串
    name = request.args.get('name')
    age = request.args.get('age')

    # 演示表单数据的读取
    w = request.form.get('w')

    return 'index %s %s %s' % (name, age, w)


# http://127.0.0.1/?name=zxc&age=18
@app.route('/')
def index():

    print request.url, request.method

    # 获取查询字符串
    name = request.args.get('name')
    age = request.args.get('age')

    return 'index %s %s' % (name,age)


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

 

hook.oy

# -*- coding:utf-8 -*-

from flask import Flask


app = Flask(__name__)


@app.route('/')
def index():
    print 'index'
    return 'index'

# 第一次请求开始前调用的,还没有执行请求
# 作用:可以做一些初始化的操作。比如连接到数据库
@app.before_first_request
def demo1():
    print 'demo1'


# 请求开始执行前调用的
# 对请求做一些校验操作,如果请求信息有异常,或者发现自己被攻击,可以在这里直接返回,不会进入到视图函数中
@app.before_request
def demo2():
    print 'demo2'


# 请求结束之后调用的、视图函数执行结束后调用的
# 可以接受视图函数执行之后的响应结果
# 可以对响应进行统一的处理,比如在响应中统一设置cookie或者响应头信息
@app.after_request
def demo3(response):
    print 'demo3'

    # 设置响应头
    response.headers['Content-Type'] = 'application/json'

    return response


# 捕获到服务器异常后调用的
# 可以接受异常信息,处理异常信息
@app.teardown_request
def demo4(e):
    print 'demo4', e


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

 

cookie.py

# -*- coding:utf-8 -*-

from flask import Flask, make_response


app = Flask(__name__)


@app.route('/set_cookie')
def set_cookie():

    # 创建response对象
    response = make_response('index')

    # 使用response对象写入cookie到浏览器,会话结束就过期
    response.set_cookie('name','zxc')
    # 设置过期时间,单位是秒
    response.set_cookie('age', '18', max_age=3600)

    return response


@app.route('/del_cookie')
def del_cookie():
    response = make_response('del_cookie')
    response.delete_cookie('name')
    return response



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

 

session.py

# -*- coding:utf-8 -*-

from flask import Flask, session


app = Flask(__name__)


# 配置秘钥参数
app.config['SECRET_KEY'] = 'n%lq5-oyhv0not14+xv4m=q-@^kt1ptzst5)w$1@o*)=ose&nv'


@app.route('/set_session')
def set_session():

    # 设置session
   # 设置session有效时间
session.permanent = True
   session.permanent_session_lifetime=3600 session[
'name'] = 'zxc' # 读取session name = session['name'] return 'set_session' @app.route('/del_session') def del_session(): # 设置session session.pop('name') return 'del_session' if __name__ == '__main__': app.run(debug=True)

 

上下文context.py

# -*- coding:utf-8 -*-

from flask import Flask, request, session, current_app, g


app = Flask(__name__)
app.config['DEBUG'] = True


# 请求上下文:是在请求生成以后才可以直接使用的,访问路由时才有请求,如果写在这里,还没有请求发生但是已经被编译了
# 请求上下文超出了工作范围
# RuntimeError: working outside of request context
# print request.method
# print session.get('name')


# 应用上下文:只有当应用启动后才能使用,保存了一些配置参数信息
# 应用上下文超出了工作范围
# RuntimeError: working outside of application context
# print current_app.config['DEBUG']


@app.route('/')
def index():

    # 请求上下文使用:一般在视图中使用,因为视图会执行,请求一定有
    print request.method
    print session.get('name')

    # 应用上下文使用,能进入视图,程序一定启动了
    print current_app.config['DEBUG']


    return 'index'


if __name__ == '__main__':

    # 在这里只是启动应用,只有当这个方法run()走完,我们的应用才算启动,也是超出了应用上下文的使用范围
    # print current_app.config['DEBUG']

    app.run(debug=True)

 

script.py

# -*- coding:utf-8 -*-

from flask import Flask

# 1.导入脚本管理类
from flask_script import Manager


app = Flask(__name__)


# 2.实例化脚本管理器
manager = Manager(app)

# 4.自定义脚本:将来会使用脚本完成数据库的迁移
@manager.command
def test_custom_script():
    print u'这里实在测试自定义脚本,实现自己的逻辑'


@app.route('/')
def index():
    a = 10 / 0
    return 'index'


if __name__ == '__main__':
    # app.run(debug=True)

    # 3.使用脚本管理器启动 runserver
    manager.run()

 

template.py

# -*- coding:utf-8 -*-

from flask import Flask, render_template


app = Flask(__name__)


@app.route('/')
def index():

    my_list = [1,2,3,4,5,6,7]
    my_int = 10
    my_dict = {
        'name':'zxj',
        'age':'2'
    }

    # 上下文
    context = {
        'my_list':my_list,
        'my_int':my_int,
        'my_dict':my_dict
    }

    # **context : 将字典展开(模板中的自动提示没有了)
    return render_template('test01_template.html', **context)

    # return render_template('test01_template.html', context=context)

    # return render_template('test01_template.html', my_list=my_list, my_int=my_int, my_dict=my_dict)


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

 

 

filter.py

# -*- coding:utf-8 -*-

from flask import Flask, render_template


app = Flask(__name__)


@app.route('/')
def index():

    my_list = [1,2,3,4,5,6,7]
    my_int = 10
    my_dict = {
        'name':'zxj',
        'age':2
    }
    my_list2 = [my_dict,my_dict]

    # 上下文
    context = {
        'my_list':my_list,
        'my_int':my_int,
        'my_dict':my_dict,
        'my_list2':my_list2
    }

    # **context : 将字典展开(模板中的自动提示没有了)
    return render_template('test02_filter.html', **context)


# 自定义过滤器方式一 : 使用装饰器
# @app.template_filter('listReverse')
def do_listReverse(list_var):
    """自定义反转列表的过滤器"""

    # 注意 : 使用中间变量暂时接受原始数据,为了操作的过程中不影响原始的数据
    temp_list = list_var

    # 注意: reverse() 没有返回值,不要直接return  reverse()
    temp_list.reverse()
    return temp_list

# 自定义过滤器的方式二:把指定的函数添加到默认的过滤器容器中
app.add_template_filter(do_listReverse, 'listReverse')


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

 

分类:

技术点:

相关文章: