flask框架基础

内容:

1.基础的flask框架示例

2.flask配置文件

3.flask路由系统

4.请求和响应

5.模板

flask框架预备知识:https://www.cnblogs.com/wyb666/p/9460598.html

flask框架详细学习:http://www.cnblogs.com/wupeiqi/articles/7552008.html 

1.基础的flask框架示例

(1)基础flask框架示例程序结构

其中app.py是主程序,utils.py是功能函数模块(log),templates文件夹中是HTML文件

(2)代码

程序功能:访问'/'显示欢迎信息和链接,访问'/message'显示留言板,然后可以用get提交数据,post提交数据,post提交的数据最后将显示在页面上

app.py:

 1 from flask import (
 2     Flask,
 3     render_template,
 4     request,
 5     redirect,
 6     url_for,
 7 )
 8 from utils import log
 9 
10 
11 # 先要初始化一个 Flask 实例
12 app = Flask(__name__)
13 
14 # message_list 用来存储所有的 message
15 message_list = []
16 
17 
18 # 定义路由和路由处理函数的方式如下
19 # ==========================
20 # 用 app.route 函数定义路由,参数是一个 path 路径
21 # 下一行紧跟着的函数是处理这个请求的函数
22 # @ 是一个叫装饰器的东西, 现在无必要知道具体的原理, 只要用它就好了
23 # 注意 methods 参数是一个 list,它规定了这个函数能接受的 HTTP 方法  默认是GET
24 @app.route('/', methods=['GET'])
25 def hello_world():
26     return '<h1>Hello wyb666</h1><br><a href="/message">message</a>'
27 
28 
29 @app.route('/message')
30 def message_view():
31     log('请求方法', request.method)
32     # render_template 读取并返回 templates 文件夹中的模板文件
33     # messages 是传给模板的参数,这样就能在模板中使用这个变量
34     return render_template('message_index.html', messages=message_list)
35 
36 
37 # 这个路由函数只支持 POST 方法
38 @app.route('/message/add', methods=['POST'])
39 def message_add():
40     log('message_add 请求方法', request.method)
41 
42     # 把POST请求的数据生成一个 dict 存到 message_list 中去
43     msg = {
44         'content': request.form.get('msg_post', ''),
45     }
46     message_list.append(msg)
47 
48     # 重定向:
49     return redirect('/message')
50     # 一般来说,我们会用 url_for 生成路由  注意url_for的参数是路由函数的名字(格式为字符串)
51     # return redirect(url_for('message_view'))
52 
53 
54 # 运行服务器
55 if __name__ == '__main__':
56     config = dict(
57         debug=True,         # debug 模式可以自动加载你对代码的变动, 所以不用重启程序
58         host='localhost',   # 指定域名
59         port=80,            # 指定端口
60     )
61     app.run(**config)

utils.py:

 1 # 一些工具函数
 2 import time
 3 
 4 
 5 # 用 log 函数把所有输出写入到屏幕中 方便debug
 6 def log(*args, **kwargs):
 7     formats = '%Y/%m/%d %H:%M:%S'
 8     value = time.localtime(int(time.time()))
 9     dt = time.strftime(formats, value)
10     print(dt, *args, **kwargs)

message_index.html:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <!-- 指明字符编码为 utf-8 否则中文会乱码 -->
 5     <meta charset="utf-8">
 6     <title>留言板</title>
 7 </head>
 8 <body>
 9     <h1>留言板</h1>
10     <form action="/message" method="GET">
11         这是一个发送 GET 请求的表单
12         <br>
13         <textarea name="msg"></textarea>
14         <br>
15         <button type="submit">用 GET 提交表单</button>
16     </form>
17 
18     <form action="/message/add" method="POST">
19         这是一个发送 POST 请求的表单
20         <br>
21         <textarea name="msg_post"></textarea>
22         <br>
23         <button type="submit">用 POST 提交表单</button>
24     </form>
25     <!-- 下面是使用模板的办法 -->
26     {# 这是 Jinja2 模板的注释语法,这样的注释并不会在生成的 HTML 代码中出现 #}
27     {# {% %} 里面的是语句 #}
28     {# {{ }} 里面的是引用变量 #}
29     <!-- 注意 m 本身是一个字典,但是你可以用 . 的语法来引用 -->
30     <!-- 这是 Jinja2 模板的功能 -->
31     {% for m in messages %}
32         <div>{{ m.content }}</div>
33     {% endfor %}
34 </body>
35 </html>

2.flask配置文件

(1)flask默认配置如下:

 1 flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
 2     {
 3         'DEBUG':                                get_debug_flag(default=False),  # 是否开启Debug模式
 4         'TESTING':                              False,                          # 是否开启测试模式
 5         'PROPAGATE_EXCEPTIONS':                 None,                          
 6         'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
 7         'SECRET_KEY':                           None,
 8         'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
 9         'USE_X_SENDFILE':                       False,
10         'LOGGER_NAME':                          None,
11         'LOGGER_HANDLER_POLICY':               'always',
12         'SERVER_NAME':                          None,
13         'APPLICATION_ROOT':                     None,
14         'SESSION_COOKIE_NAME':                  'session',
15         'SESSION_COOKIE_DOMAIN':                None,
16         'SESSION_COOKIE_PATH':                  None,
17         'SESSION_COOKIE_HTTPONLY':              True,
18         'SESSION_COOKIE_SECURE':                False,
19         'SESSION_REFRESH_EACH_REQUEST':         True,
20         'MAX_CONTENT_LENGTH':                   None,
21         'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
22         'TRAP_BAD_REQUEST_ERRORS':              False,
23         'TRAP_HTTP_EXCEPTIONS':                 False,
24         'EXPLAIN_TEMPLATE_LOADING':             False,
25         'PREFERRED_URL_SCHEME':                 'http',
26         'JSON_AS_ASCII':                        True,
27         'JSON_SORT_KEYS':                       True,
28         'JSONIFY_PRETTYPRINT_REGULAR':          True,
29         'JSONIFY_MIMETYPE':                     'application/json',
30         'TEMPLATES_AUTO_RELOAD':                None,
31     }
flask默认配置

(2)flask常用配置方法

 1 方式一:
 2     app.config['DEBUG'] = True
 3     PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
 4  
 5 
 6 方式二:
 7     app.config.from_pyfile("python文件名称")
 8         eg:
 9             settings.py:
10                 DEBUG = True
11             
12             app.py:
13             app.config.from_pyfile("settings.py")
14  
15  
16  方式三:
17     app.config.from_object("python类或类的路径")
18         eg:
19             settings.py:
20                 class Config(object):
21                     DEBUG = False
22                     TESTING = False
23                     DATABASE_URI = 'sqlite://:memory:'
24      
25                 class ProductionConfig(Config):
26                     DATABASE_URI = 'mysql://user@localhost/foo'
27      
28                 class DevelopmentConfig(Config):
29                     DEBUG = True
30      
31                 class TestingConfig(Config):
32                 TESTING = True
33 
34             app.py:
35             app.config.from_object('pro_flask.settings.TestingConfig')
36  
37         PS: 从sys.path中已经存在路径开始写
38      
39 
40 PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录

3.flask路由系统

(1)常用路由

  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @app.route('/post/<float:post_id>')
  • @app.route('/post/<path:path>')
  • @app.route('/login', methods=['GET', 'POST'])

常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:

1 DEFAULT_CONVERTERS = {
2     'default':          UnicodeConverter,
3     'string':           UnicodeConverter,
4     'any':              AnyConverter,
5     'path':             PathConverter,
6     'int':              IntegerConverter,
7     'float':            FloatConverter,
8     'uuid':             UUIDConverter,
9 }

(2)flask路由系统本质(注册路由原理)

flask的路由系统比较特殊,是基于装饰器来实现,关于装饰器:http://www.cnblogs.com/wyb666/p/8748102.html,但是flask路由系统的本质是通过add_url_rule方法来实现,详情看下面:

一个基本的路由:

1 @app.route('/', methods=['GET'], endpoint="hello")
2 def hello_world():
3     return '<h1>Hello wyb666</h1><br><a href="/message">message</a>'

第一行以@开头明显是一个装饰器,源码及其解释如下:

 1 def route(self, rule, **options):
 2     # 这是一个被用来给view函数注册路由的装饰器
 3     # rule是URL规则
 4     # options是一系列参数 比如methods(请求方法)、endpoint(反向查询URL)等   (endpoint不写默认就是函数名)
 5     def decorator(f):
 6         endpoint = options.pop('endpoint', None)
 7         # add_url_rule其实就是将路由规则和相应的处理函数对应起来
 8         # 类似django中的urls.py中的
 9         self.add_url_rule(rule, endpoint, f, **options)
10         return f
11     return decorator

上面那个基本路由的本质:

 1 @app.route('/', methods=['GET'], endpoint="hello")
 2 def hello_world():
 3     pass
 4 上面这段代码相当于:
 5 1.  decorator = app.route('/', methods=['GET'], endpoint="hello")
 6 2.  @decorator -> decorator(hello_world)
 7 3.  endpoint = options.pop('endpoint', None)
 8     # 添加路由对应关系
 9     self.add_url_rule(rule='/', endpoint="hello", f=hello_world, **options)
10     return f

于是这样写也可以:

1 def hello_world():
2     return '你好!'
3 
4 app.add_url_rule('/', "hello", hello_world, methods=['GET'])

总结:

flask的路由系统比较特殊,是基于装饰器来实现,但flask路由系统的本质是通过add_url_rule方法来实现,也就是说在本质上和django并无太大的区别,也可以像django那样使用路由,将上述代码进一步完善可以实现django中的FBV

当然也可以实现django中的CBV:

 1 from flask import views
 2 # 装饰器
 3 def auth(func):
 4     def inner(*args, **kwargs):
 5         print('before')
 6         result = func(*args, **kwargs)
 7         print('after')
 8         return result
 9     return inner
10 
11 class IndexView(views.MethodView):
12     methods = ['GET', 'POST']
13     decorators = [auth, ]
14 
15     def get(self):
16         return 'Index.GET'
17 
18     def post(self):
19         return 'Index.POST'
20 
21 # name其实就是endpoint 
22 # as_view: 返回一个函数,将普通的view函数 -> 捆绑了路由的view函数
23 app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  
flask CBV

@app.route和app.add_url_rule的参数如下:

 1 @app.route和app.add_url_rule参数:
 2     rule,                       URL规则
 3     view_func,                  视图函数名称
 4     defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
 5     endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
 6     methods=None,               允许的请求方式,如:["GET","POST"]
 7     
 8 
 9     strict_slashes=None,        对URL最后的 / 符号是否严格要求,
10                                 如:
11                                     @app.route('/index',strict_slashes=False),
12                                         访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可
13                                     @app.route('/index',strict_slashes=True)
14                                         仅访问 http://www.xx.com/index 
15     
16     redirect_to=None,           重定向到指定地址
17                                 如:
18                                     @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
19 20                                     def func(adapter, nid):
21                                         return "/home/888"
22                                     @app.route('/index/<int:nid>', redirect_to=func)
23     
24     subdomain=None,             子域名访问
25                                         from flask import Flask, views, url_for
26 
27                                         app = Flask(import_name=__name__)
28                                         app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
29 
30 
31                                         @app.route("/", subdomain="admin")
32                                         def static_index():
33                                             """Flask supports static subdomains
34                                             This is available at static.your-domain.tld"""
35                                             return "static.your-domain.tld"
36 
37 
38                                         @app.route("/dynamic", subdomain="<username>")
39                                         def username_index(username):
40                                             """Dynamic subdomains are also supported
41                                             Try going to user1.your-domain.tld/dynamic"""
42                                             return username + ".your-domain.tld"
43 
44 
45                                         if __name__ == '__main__':
46                                             app.run()
View Code

(3)自定义正则路由匹配

很少用到,用到再看看下面的吧:

 1 from flask import Flask, views, url_for
 2 from werkzeug.routing import BaseConverter
 3 
 4 app = Flask(import_name=__name__)
 5 
 6 # 这个类一定要写,并且继承BaseConverter
 7 class RegexConverter(BaseConverter):
 8     """
 9     自定义URL匹配正则表达式
10     """
11     def __init__(self, map, regex):
12         super(RegexConverter, self).__init__(map)
13         self.regex = regex
14 
15     def to_python(self, value):
16         """
17         路由匹配时,匹配成功后传递给视图函数中参数的值
18         :param value: 
19         :return: 
20         """
21         return int(value)
22 
23     def to_url(self, value):
24         """
25         使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
26         :param value: 
27         :return: 
28         """
29         val = super(RegexConverter, self).to_url(value)
30         return val
31 
32 # 添加到flask中
33 app.url_map.converters['regex'] = RegexConverter
34 
35 
36 @app.route('/index/<regex("d+"):nid>')
37 def index(nid):
38     print(url_for('index', nid='888'))
39     return 'Index'
40 
41 
42 if __name__ == '__main__':
43     app.run()
自定义正则路由匹配

(4)蓝图与子域名实现

蓝图用于为应用提供目录划分和模块化路由的功能,在flask中,蓝图可以拥有自己的静态资源路径、模板路径,从而实现结构划分

子域名类似xxx.douban.com的形式,比如book.douban.com、movie.douban.com、music.douban.com、time.douban.com

关于这两者详情看此:https://www.cnblogs.com/wyb666/p/9568197.html

4.请求和响应

(1)flask请求

flask请求相关信息:

 1 request.method -> 请求方法
 2 request.args -> get请求参数
 3 request.form -> post请求参数
 4 request.values -> 所有请求参数
 5 request.cookies -> 请求的cookies
 6 request.headers -> 请求的headers
 7 request.path -> 请求的路径
 8 request.full_path -> 请求的完整路径
 9 request.script_root
10 request.url
11 request.base_url
12 request.url_root
13 request.host_url
14 request.host
15 request.files -> 文件

关于flask上传文件:

1 前端:
2     <form action="" enctype='multipart/form-data' method='POST'>
3         <input type="file" name="file">
4         <input type="submit" value="上传文件">
5     </form>
6 flask:
7 file = request.files.get("file") # 获取文件
8 filename = file.filename  # 获取文件名
9 file.save(os.path.join(FILE_DIR,filename)) # 保存文件

(2)flask响应

flask响应相关信息:

 1 return "字符串"                                            # 直接返回字符串
 2 return render_template('html模板路径')                     # 返回HTML
 3 return render_template('html模板路径', xxx=xxx)            # 返回HTML并传参(xxx=xxx也可以写成**{}的形式)
 4 return redirect('/index.html')                            # 重定向   
 5 
 6 response = make_response(render_template('index.html'))   # response是flask.wrappers.Response类型
 7 response.delete_cookie('key')                             # 删除cookie           
 8 response.set_cookie('key', 'value')                       # 设置cookie         
 9 response.headers['X-Something'] = 'A value'
10 return response

5.模板

(1)模板的使用

Flask使用的是Jinja2模板,其语法和Django无差别

(2)自定义模板方法

Flask中自定义模板方法的方式和Bottle相似,创建一个函数并通过参数的形式传入render_template,然后将执行这个函数并将其最后结果替换到HTML中函数的位置,如:

 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <h1>自定义函数</h1>
 9     {{func()|safe}}
10 
11 </body>
12 </html>
 1 from flask import Flask,render_template
 2 
 3 app = Flask(__name__)
 4  
 5 def index():
 6     return '<h1>index</h1>'
 7  
 8 @app.route('/test', methods=['GET', 'POST'])
 9 def test():
10     # index.html就是上面的HTML
11     return render_template('index.html',  func=index)
12  
13 app.run()

注意为了防止XSS攻击,直接传HTML时会对HTML进行转义,HTML将以字符串的形式直接显示在页面上,需要在模板上函数调用后加上| safe才可以把HTML显示出来

flask模板定制功能:

 1 @app.template_global()
 2 def sb(a1, a2):
 3     return a1 + a2
 4 # HTML中调用方法:
 5 # {{ sb(1, 2)}}   # 1和2分别对应两个参数
 6 
 7 @app.template_filter()
 8 def db(a1, a2, a3):
 9     return a1 + a2 + a3
10 # HTML中调用方法:
11 # {{ 1|db(2, 3)}}  # 1对应第一个参数 2和3对应后面的参数
原文地址:https://www.cnblogs.com/wyb666/p/9502694.html