01.基本介绍及使用

 

文章目录

 

一、介绍

1.web框架

  • 能够被服务器调用起来,根据客户端请求的执行不同的逻辑处理形成要返回数据的程序
  • **核心:**实现路由和视图(业务逻辑处理)

2.框架的轻重

  • 重量级的框架:为方便业务开发,提供了丰富的工具、组件例如Django。
  • 轻量级的框架:只提供web框架的核心功能,自由,灵活,高度定制。如flask、Tornado。

三大主流框架:

  • django:大而全,重武器,内部提供:ORM、Admin、ModelForm,Session,缓存,型号,CSRF。
  • Flask:短小精悍,可扩展性强,第三方组件丰富
  • tornado:短小精悍,异步非阻塞

其他:

  • web.py
  • bottle.py

3.Flask简介

Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架。

Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现。比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL。

其 WSGI 工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是 Flask 框架的核心。

官方 官方文档(中文)

4.与django对比

django提供了:

  • django-admin快速创建项目工程
  • manage.py管理项目工程
  • ORM模型(数据库抽象层)
  • admin后台管理站点
  • 缓存机制
  • 文件存储系统
  • 用户认证系统

而这些,flask都没有,都需要扩展包来提供。

3.Flask常用第三方扩展包:

Flask-SQLalchemy:操作数据库,ORM. 号称操作数据库最快的框架SQLalchemy;

Flask-script:终端脚本工具,脚手架;

Flask-migrate:管理迁移数据库. 比Django的更加强大, 迁移数据的过程中还可以回滚;

Flask-Session:Session存储方式指定;

Flask-WTF:表单;

Flask-Mail:邮件;

Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;

Flask-OpenID:认证, OAuth;

Flask-RESTful:开发REST API的工具;

Flask JSON-RPC: 开发rpc远程服务[过程]调用

Flask-Bootstrap:集成前端Twitter Bootstrap框架

Flask-Moment:本地化日期和时间

Flask-Admin:简单而可扩展的管理接口的框架

可以通过 https://pypi.org/search/?c=Framework+%3A%3A+Flask 查看更多flask官方推荐的扩展

二、基本使用

1.安装

pip install flask

2.储备知识 werkzeug

依赖 wsgi werkzeug

介绍: Werkzeug是一个WSGI工具包,他可以作为一个Web框架的底层库。

补充: werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等

示例一:

from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

示例二:

from werkzeug.wrappers import Request, Response

class Flask(object):
    def __call__(self.serving,run_simple)
    	return '请求来了'
if __name__== 'main':
    run_simple('localhost', 4000, hello)

示例三:

from werkzeug.wrappers import Request, Response

class Flask(object):
    def __call__(self.serving,self):
    	return '请求来了'
    def run(self):
        run_simple('127.0.0.1',5000,self)
app =Flask()
if __name__== 'main':
    app.run()

3.pycharm创建flask项目

与django不同,flask不会提供任何的自动操作,所以需要手动创建项目目录,需要手动创建启动项目的管理文件

例如,创建项目目录 flaskdemo,在目录中创建manage.py.在pycharm中打开项目并指定上面创建的虚拟环境

Flask基本介绍及使用_flask

4.创建flask框架主程序

名字可随便更改,可以是app.py/run.py/main.py/index.py

from flask import Flask

# 创建flask的应用对象
# __name__表示当前模块的名字
#           模块名,Flask这个模块所在的目录为总目录,默认这个目录中的static为静态目录,templates为模板目录
app = Flask(__name__)


# @app.route('/')
def hello_world():
    '''定义的视图函数'''
    return 'Hello World!'

if __name__ == '__main__':
    # 注意:flask默认端口5000
    app.run()

5.代码分析

# 导入Flask类
from flask import Flask

"""
import_name      Flask程序所在的包(模块),传 __name__ 就可以
                 其可以决定 Flask 在访问静态文件时查找的路径
static_path      静态文件访问路径(不推荐使用,使用 static_url_path 代替)
static_url_path  静态文件访问路径,可以不传,默认为:/ + static_folder
static_folder    静态文件存储的文件夹,可以不传,默认为 static
template_folder  模板文件存储的文件夹,可以不传,默认为 templates
"""
app = Flask(import_name=__name__)


# 编写路由视图
# flask的路由是通过给视图添加装饰器的方式进行编写的。当然也可以分离到另一个文件中。
# flask的视图函数,flask中默认允许通过return返回html格式数据给客户端。
@app.route(rule='/')
def index():
    return '<mark>Hello Word!</make>'

# 加载项目配置
class Config(object):
    # 开启调试模式
    DEBUG = True

# flask中支持多种配置方式,通过app.config来进行加载,我们会这里常用的是配置类
app.config.from_object( Config )


# 指定服务器IP和端口
if __name__ == '__main__':
    # 运行flask
    app.run(host="0.0.0.0", port=5000)

小结:

  • Flask框架基于werkzeug的wsgi实现,flask自己没有wsgi
  • 用户一旦请求来了,就会执行__call__方法
  • 写Flask标准流程
    1. 创建一个Flask对象
    2. 将路由和视图放在一起,可以写多个
    3. 在调用app.run()本质是内部调用了werkzeug

6.案例:登录、显示用户信息

main.py

from flask import Flask,render_template,request,redirect,session,url_for
app = Flask(__name__)
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'

USERS = {
    1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
    2:{'name':'李四','age':28,'gender':'男','text':"搞钱第一条"},
    3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}

@app.route('/detail/<int:nid>',methods=['GET'])
def detail(nid):
    user = session.get('user_info')
    if not user:
        return redirect('/login')

    info = USERS.get(nid)
    return render_template('detail.html',info=info)


@app.route('/index',methods=['GET'])
def index():
    user = session.get('user_info')
    if not user:
        # return redirect('/login')
        url = url_for('l1')
        return redirect(url)
    return render_template('index.html',user_dict=USERS)


@app.route('/login',methods=['GET','POST'],endpoint='l1')
def login():
    if request.method == "GET":
        return render_template('login.html')
    else:
        # request.query_string
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        if user == 'lqz' and pwd == '123':
            session['user_info'] = user
            return redirect('http://www.baidu.com')
        return render_template('login.html',error='用户名或密码错误')

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

detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>详细信息 {{info.name}}</h1>
    <div>
        {{info.text}}
    </div>
</body>
</html>

index.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用户列表</h1>    <table>        {% for k,v in user_dict.items() %}        <tr>            <td>{{k}}</td>            <td>{{v.name}}</td>            <td>{{v['name']}}</td>            <td>{{v.get('name')}}</td>            <td><a href="/detail/{{k}}">查看详细</a></td>        </tr>        {% endfor %}    </table></body></html>

login.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用户登录</h1>    <form method="post">        <input type="text" name="user">        <input type="text" name="pwd">        <input type="submit" value="登录"><span style="color:red">{{error}}</span>    </form></body></html>

小总结:

  1. flask路由

    @app.route('/login')def login():    pass
    
  2. 路由的参数

    @app.route('/login',methods=['GET','POST'],endpoint='l1')def login():    pass'''第一个参数:url第二个参数:支持的请求方法第三个参数:endpoint反向解析,不写默认为函数名,并且不能重名,重名就报错'''
    
  3. 动态路由

    @app.route('/index')def login():    pass@app.route('/index/<name>')def index(name):    pass@app.route('/index/int:<nid>')def index(nid):    pass
    
  4. 获取提交的数据

    from flask import request@app.route('/index')def login():    request.args # GET请求传递的参数    request.form # POST请求传递的参数
    
  5. 返回数据

    @app.route('/index')def login():    return render_template('模板文件')	return jsonify(...)	# 传递json格式的数据	return redirect('/index/') # 传递url	return redirect(url_for('别名'))	# 别名	return '字符串'
    
  6. 模板处理

    {{值}}{%for item in list %}	{{item}}{% endfor %}{# #}  #注释
    

三、配置文件

1.默认配置

flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:

 {        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式        'TESTING':                              False,                          是否开启测试模式        'PROPAGATE_EXCEPTIONS':                 None,                                  'PRESERVE_CONTEXT_ON_EXCEPTION':        None,        'SECRET_KEY':                           None,        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),        'USE_X_SENDFILE':                       False,        'LOGGER_NAME':                          None,        'LOGGER_HANDLER_POLICY':               'always',        'SERVER_NAME':                          None,        'APPLICATION_ROOT':                     None,        'SESSION_COOKIE_NAME':                  'session',        'SESSION_COOKIE_DOMAIN':                None,        'SESSION_COOKIE_PATH':                  None,        'SESSION_COOKIE_HTTPONLY':              True,        'SESSION_COOKIE_SECURE':                False,        'SESSION_REFRESH_EACH_REQUEST':         True,        'MAX_CONTENT_LENGTH':                   None,        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),        'TRAP_BAD_REQUEST_ERRORS':              False,        'TRAP_HTTP_EXCEPTIONS':                 False,        'EXPLAIN_TEMPLATE_LOADING':             False,        'PREFERRED_URL_SCHEME':                 'http',        'JSON_AS_ASCII':                        True,        'JSON_SORT_KEYS':                       True,        'JSONIFY_PRETTYPRINT_REGULAR':          True,        'JSONIFY_MIMETYPE':                     'application/json',        'TEMPLATES_AUTO_RELOAD':                None,    }

2.多种配置方式

方式一:

app.config['DEBUG'] = TruePS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)

方式二:

#通过py文件配置app.config.from_pyfile("python文件名称")如:settings.pyDEBUG = Trueapp.config.from_pyfile("settings.py")#通过环境变量配置app.config.from_envvar("环境变量名称")#app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])环境变量的值为python文件名称名称,内部调用from_pyfile方法app.config.from_json("json文件名称")JSON文件名称,必须是json格式,因为内部会执行json.loadsapp.config.from_mapping({'DEBUG': True})字典格式app.config.from_object("python类或类的路径")

settings.py(用的最多)

app.config.from_object('pro_flask.settings.TestingConfig')class Config(object):    DEBUG = False    TESTING = False    DATABASE_URI = 'sqlite://:memory:'class ProductionConfig(Config):    DATABASE_URI = 'mysql://user@localhost/foo'class DevelopmentConfig(Config):    DEBUG = Trueclass TestingConfig(Config):    TESTING = TruePS: 从sys.path中已经存在路径开始写PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录(Flask对象init方法的参数)

四、路由系统

1.路由的基本定义

  • 注意:路由和视图的名称必须全局唯一,不能出现重复,否则报错。
# 指定访问路径为 demo@app.route(rule='/demo')def demo():    return "demo"

2.典型写法

@app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')

3.路由参数接收

  • 提示:路由参数就是url路径的一部分。

3.1任意路由参数接收

# 不限定类型的路由参数传递@app.route(rule='/user/<id>')def user(id):  # 接受参数    return "id=%s的用户中心" % id# 路由参数理论上可以存在多个# 参数名建议不要使用单字母,因为有些单字母在框架中默认被占用了。@app.route(rule='/user1/<id>/<page>')def user1(id, page):  # 接受参数    return "id=%s,page=%s" % (id, page)

3.2 限定路由参数接收:转换器

系统自带的转换器具体使用方式在每种转换器的注释代码中有写,请留意每种转换器初始化的参数。

转换器名称 描述
string 默认类型,接受不带斜杠的任何文本
int 接受正整数
float 接受正浮点值
path 接收string但也接受斜线
uuid 接受UUID(通用唯一识别码)字符串 xxxx-xxxx-xxxxx-xxxxx
# 限定类型的路由参数传递
# 路由格式:<类型:参数名>
# 路由参数的类型,flask支持 int整型,float浮点数,path路径,uuid唯一识别码
@app.route(rule='/user2/<int:id>')
def user2(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'int'> 1
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user3/<string:id>')
def user3(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'str'> zcdsb123
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user4/<float:id>')
def user4(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'float'> 1.1
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user5/<path:id>')
def user5(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'str'> lxdsb/zcdsb
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user6/<uuid:id>')
def user6(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'uuid.UUID'> 95db2e6c-e7a7-11ea-9ca3-48ba4e4e6384
    return f'<mark>Hello {id}!</make>'

3.3 默认转换器配置

限定路由参数的类型,flask系统自带转换器编写在werkzeug.routing.py文件中。底部可以看到以下字典:

DEFAULT_CONVERTERS = {   "default": UnicodeConverter,   "string": UnicodeConverter,   "any": AnyConverter,   "path": PathConverter,   "int": IntegerConverter,   "float": FloatConverter,   "uuid": UUIDConverter,}

4.路由系统本质

  • Flask 路由基于装饰器
  • 装饰器的执行过程:不加括号的情况下,把装饰器下面的函数传给装饰器(函数)执行,得到结果,再赋值给下面的函数
  • Flask路由本质就是app.add_url_rule()
"""1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1')    def route(self, rule, **options):        # app对象        # rule= /        # options = {methods=['GET','POST'],endpoint='n1'}        def decorator(f):            endpoint = options.pop('endpoint', None)            self.add_url_rule(rule, endpoint, f, **options)            return f        return decorator2. @decorator    decorator(index)"""#同理def login():    return '登录'app.add_url_rule('/login', 'n2', login, methods=['GET',"POST"])#与django路由类似#django与flask路由:flask路由基于装饰器,本质是基于:add_url_rule#add_url_rule 源码中,endpoint如果为空,endpoint = _endpoint_from_view_func(view_func),最终取view_func.__name__(函数名)

简单示例:

from flask import Flaskapp = Flask(__name__)app.config['DEBUG'] = Falsedef index():    return 'index'# Flask路由本质就是`app.add_url_rule()`app.add_url_rule('/', endpoint='index', view_func=index)if __name__ == '__main__':    app.run()

5.app.add_url_rule参数介绍

# 提示: 即是@app.route的参数, 本质也是app.add_url_rule的参数rule='/index'          # 符合URL规则的路由view_func=index        # 视图函数名称defaults=None          # 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}可以为函数提供默认参数endpoint=None          # 名称,用于反向生成URL,即: url_for('名称')methods=None           # 允许的请求方式,如:["GET", "post"] 大小写都可以, 内部会执行upper()strict_slashes=None    # 对URL最后的 / 符号是否严格要求, 默认严格. False就是不严格    @app.route('/index', strict_slashes=False)    # 访问 http://www.xx.com/index/ 或 http://www.xx.com/index 的路由格式都可以        @app.route('/index', strict_slashes=True)    # 仅支持这种路由格式访问: http://www.xx.com/index    redirect_to = None      # 重定向到指定地址    @app.route('/index/<int:nid>', redirect_to='/home/<nid>')    subdomain = None        # 子域名访问    # C:\Windows\System32\drivers\etc\hosts    127.0.0.1       www.liuqingzheng.com    127.0.0.1       admin.liuqingzheng.com    127.0.0.1       buy.liuqingzheng.com        # 示例    from flask import Flask, views, url_for        app = Flask(import_name=__name__)    app.config['SERVER_NAME'] = 'liuqingzheng.com:5000'        @app.route("/", subdomain="admin")    def static_index():        return "static.your-domain.tld"            # 可以传入任意的字符串,如传入的字符串为aa,显示为 aa.liuqingzheng.com    @app.route("/dynamic", subdomain="<username>")    def username_index(username):        return username + ".your-domain.tld"            if __name__ == '__main__':        app.run()            # 支持访问的路由需要包含如下的域名访问格式:www dynamic admin    http://www.liuqingzheng.com:5000/dynamic    http://admin.liuqingzheng.com:5000/dynamic    http://buy.liuqingzheng.com:5000/dynamic

6.路由支持正则: 自定义转换器

基本步骤:

  1. 导入转换器基类:在Flask中,所有的路由的匹配规则都是使用转换器对象进行记录
  2. 写一个自定义转换器:自定义类继承与转换器基类
  3. 注册:添加转换器到默认的转换器字典中
  4. 使用自定义转换器实现自定义匹配规则

6.1GL模式

from flask import Flask, request# 初始化app = Flask(import_name=__name__)# 编写路由视图@app.route(rule='/')def index():    return "<h1>hello world!</h1>"# 关于路由参数的限制,flask内置的类型不够具体,在开发中,我们经常接受参数,需要更加精确的限制# 这时候,可以使用正则匹配路由参数# 正则匹配路由参数,其实就是扩展flask内置的路由限定类型,需要完成4个步骤# 1. 引入flask的路由转换器from werkzeug.routing import BaseConverter# 2. 创建自定义路由转换器class MobileConverter(BaseConverter):    """手机号码类型限制"""    def __init__(self, map, *args):        super().__init__(map)        self.regex = "1[3-9]\d{9}"# 3. 把自定义转换器添加到flask默认的转换器字典中,也就是和原来的int,float等放在一块app.url_map.converters['mob'] = MobileConverter# 4. 类似原来的路由参数限制一样,调用自定义转换器名称即可@app.route(rule='/user/<mob:mobile>')def user(mobile):    return mobile# 1. 引入flask的路由转换器from werkzeug.routing import BaseConverter# 2. 创建自定义路由转换器class RegexConverter(BaseConverter):    """根据正则进行参数限制"""    def __init__(self, map, *args):        super().__init__(map)        self.regex = args[0]  # args=(\w+@\w+\.\w+, )# 3. 把自定义转换器添加到flask默认的转换器字典中,也就是和原来的int,float等放在一块app.url_map.converters['re'] = RegexConverter# 4. 类似原来的路由参数限制一样,调用自定义转换器名称即可@app.route(rule='/user/<re("\w+@\w+\.\w+"):email>')def user2(email):    print(app.url_map)  # 获取所有的路由列表    return email# 声明和加载配置class Config():    DEBUG = Trueapp.config.from_object(Config)if __name__ == '__main__':    # 运行flask    app.run(port=8000)

6.2 LQZ 模式

# 流程: 
"""
1. 写类,继承BaseConverter
2. 注册:app.url_map.converters['regex'] = RegexConverter
3. 使用:@app.route('/index/<regex("\d+"):nid>')  正则表达式会当作第二个参数传递到类中
"""

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

app = Flask(import_name=__name__)


class RegexConverter(BaseConverter):
    """
    自定义URL匹配正则表达式
    """

    def __init__(self, map, regex):
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        """
        return int(value)

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        """
        val = super(RegexConverter, self).to_url(value)
        return val


# 添加到flask中
app.url_map.converters['regex'] = RegexConverter


@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'


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

五、CBV源码分析

django中的三件套:
			Httpresponse   ''
			render         render_template
			redirect       redirect
			JsonResponse   jsonify


def auth(func):
    def inner(*args, **kwargs):
        print('before')
        result = func(*args, **kwargs)
        print('after')
        return result

    return inner

class IndexView(views.View):
    methods = ['GET']
    decorators = [auth, ]

    def dispatch_request(self):
        print('Index')
        return 'Index!'

app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
#或者,通常用此方式
  class IndexView(views.MethodView):
            methods = ['GET']
            decorators = [auth, ]

            def get(self):
                return 'Index.GET'

            def post(self):
                return 'Index.POST'
        app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint

六、模板

1.渲染变量

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用户列表</h1>    <table>        {% for k,v in user_dict.items() %}        <tr>            <td>{{k}}</td>            <td>{{v.name}}</td>            <td>{{v['name']}}</td>            <td>{{v.get('name')}}</td>            <td><a href="/detail/{{k}}">查看详细</a></td>        </tr>        {% endfor %}    </table></body></html>

2.变量的循环

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用户列表</h1>    <table>        {% for k,v in user_dict.items() %}        <tr>            <td>{{k}}</td>            <td>{{v.name}}</td>            <td>{{v['name']}}</td>            <td>{{v.get('name')}}</td>            <td><a href="/detail/{{k}}">查看详细</a></td>        </tr>        {% endfor %}    </table></body></html>

3.逻辑判断

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% if name %}
          <h1>Hello {{ name }}!</h1>
        {% else %}
          <h1>Hello World!</h1>
        {% endif %}
    </table>
</body>
</html>

4.处理XSS攻击

app.py

from flask import Flask, Markup, render_template

app = Flask(__name__)


def func1(arg):
    # Markup 类似于 Django中的make_save
    return Markup("<input type='text' value='%s' />" % (arg,))


@app.route('/')
def index():
    return render_template('xss.html', ff=func1)


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

xss.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ff('六五')}}
    <!-- safe和Django中过滤器中的safe方法一致 -->
	{{ff('六五')|safe}}
</body>
</html>

注意:

  1. Markup等价django的mark_safe ,

  2. extends,include一模一样

七、请求与响应对象

from flask import Flask, request, jsonify, make_response

app = Flask(__name__)
app.debug = True


@app.route('/', methods=['GET', 'POST'])
def index():
    from werkzeug.datastructures import CombinedMultiDict
    # --------------------------- 请求对象 ---------------------------
    # 获取当前请求方法
    print(request.method)  # POST

    # 获取get请求提交的数据
    print(request.args)  # ImmutableMultiDict([('name', 'yang'), ('age', '18')])
    print(type(request.args))  # <class 'werkzeug.datastructures.ImmutableMultiDict'>
    print(request.args.get('name'))  # yang
    from werkzeug.datastructures import ImmutableMultiDict

    # 获取get形式提交的数据(提示: 需要自己转)
    print(request.query_string)  # b'name=yang&age=18'

    # 获取post请求提交的数据
    print(request.form)  # ImmutableMultiDict([('name', 'yang666'), ('age', '22')])

    # 获取文件
    print(
        request.files)  # ImmutableMultiDict([('avatar', <FileStorage: 'default.jpg' ('image/jpeg')>), ('sql_file', <FileStorage: 'luffyapi.sql' ('application/x-sql')>)])
    print(request.files.get('avatar'))  # FileStorage: 'default.jpg' ('image/jpeg')>

    # 获取post和get提交的数据总和
    print(
        request.values)  # CombinedMultiDict([ImmutableMultiDict([('name', 'yang'), ('age', '18')]), ImmutableMultiDict([('name', 'yang666'), ('age', '22')])])
    print(request.values.get('name'))  # yang
    print(request.values.get('age'))  # 18
    print(request.values.getlist('name'))  # ['yang', 'yang666']

    # 获取客户端所带的cookie
    print(request.cookies)  # {'key': 'woshicookies', 'user': 'yang'}

    # 获取请求头中所携带的数据
    print(request.headers)
    '''
    Yang: xiudetianhualuanzui
    Cookie: key=woshicookies; xxx=lqz
    User-Agent: PostmanRuntime/7.26.3
    Accept: */*
    Postman-Token: 40bb7ca6-ba5b-4d1a-9732-1f49cfef954f
    Host: 127.0.0.1:8080
    Accept-Encoding: gzip, deflate, br
    Connection: keep-alive
    Content-Type: multipart/form-data; boundary=--------------------------487226677414449536798986
    Content-Length: 65491
    '''

    # 获取不带域名的请求路径
    print(request.full_path)  # /?name=yang&age=18
    # 获取不带域名只带参数的请求路径
    print(request.path)  # /

    # 获取带域名带参数的请求路径
    print(request.url)  # http://127.0.0.1:8080/?name=yang&age=18
    # 获取带域名请求路径
    print(request.base_url)  # http://www.yang1333.com:8080/
    # 获取域名
    print(request.url_root)  # http://www.yang1333.com:8080/
    # 获取域名
    print(request.host_url)  # http://www.yang1333.com:8080/
    # 获取当前请求用户IP: 127.0.0.1:500
    print(request.host)  # www.yang1333.com:8080

    # --------------------------- 响应对象 ---------------------------
    # 返回三板斧: 字符串, render_template, redirect
    return "字符串"
    return render_template('html模板路径', **{})
    return redirect('/index.html')

    # 返回JSON格式数据: 类似于Django中的JsonResponse对象
    return jsonify({'k1': 'v1'})

    # 返回response对象
    string = 'hello world'
    response = make_response(string)

    # 设置cookie操作
    response.set_cookie('key', 'value')
    response.delete_cookie('key')

    # 设置响应头
    response.headers['X-Something'] = 'A value'

    # response是flask.wrappers.Response类型
    print(type(response))
    from flask.wrappers import Response

    return response


if __name__ == '__main__':
    print(app.config)
    app.run(port=8080)