• 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对应后面的参数
  • 相关阅读:
    css3 径向渐变
    进度条-线性渐变
    echars 图表提示框自定义显示
    Android Ndef Message解析
    android 应用程序记录AAR
    android的nfc卡模拟开发
    《NFC开发实战详解》笔记
    1、Altium Designer 入门
    Stm32之通用定时器复习
    external与static的用法
  • 原文地址:https://www.cnblogs.com/wyb666/p/9502694.html
Copyright © 2020-2023  润新知