Flask的CBV和Flask-Session

什么是CBV

CBV在Django中也是接触过的

FBV就是function   CBV就是class

FBV简单, 小巧, 当不涉及到复杂的逻辑时可以使用FBV

CBV 灵活, 类的封装, 继承, 多态。

在Flask中实现CBV

from flask import Flask, views, render_template, request

app = Flask(__name__)

class Login(views.MethodView):

    def get(self):
        return render_template('login.html')

    def post(self):
        return request.form.get('username')


app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"))

if __name__ == '__main__':
    app.run("0.0.0.0",9999)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>登录</h1>
<form action="" method="post">
    <input type="text" name="username">
    <input type="submit">
</form>

</body>
</html>
login.html

CBV有了, 路由在哪里, 之前FBV都是使用装饰器来声明一个路由的,那么CBV是怎么实现的呢。

其实只要看一看@app.route()的源码就会知道该怎么做了。

@app.route()源码浅解

class Flask(_PackageBoundObject):

    def route(self, rule, **options):
        def decorator(f):
            """
            :param f: 视图函数
            :return:  内部函数 decorator
            """
            endpoint = options.pop('endpoint', None)  # 从参数中弹出endpoint, 没有的话就是None
            self.add_url_rule(rule, endpoint, f, **options)  # 调用这个函数, 将路由规则, endpoint, 视图函数传了进去, 其实这里就是去添加路由和视图的对应关系了
            return f

        return decorator

点进去add_url_rule,查看是怎么添加路由和视图的对应关系的

 @setupmethod
    def add_url_rule(self, rule, endpoint=None, view_func=None,
                     provide_automatic_options=None, **options):
        """

        :param rule: 视图函数的route装饰器中定义的路由规则
        :param endpoint: 从option中取出的endpoint
        :param view_func: 视图函数
        :param provide_automatic_options:
        :param options:
        :return:
        """
       
        if endpoint is None:  # endpoint如果为None
            endpoint = _endpoint_from_view_func(view_func)  # 将试图视图函数传了进去, 返回视图函数的__name__
        options['endpoint'] = endpoint  # 重新赋值endpoint, 这时endpoint有可能等于视图函数的__name__, 或还是之前的值
        methods = options.pop('methods', None)  # 将请求方式弹出

      
        if methods is None:
            methods = getattr(view_func, 'methods', None) or ('GET',)
        if isinstance(methods, string_types):
            raise TypeError('Allowed methods have to be iterables of strings, '
                            'for example: @app.route(..., methods=["POST"])')
        methods = set(item.upper() for item in methods)
        required_methods = set(getattr(view_func, 'required_methods', ()))

     
        if provide_automatic_options is None:
            provide_automatic_options = getattr(view_func,
                                                'provide_automatic_options', None)

        if provide_automatic_options is None:
            if 'OPTIONS' not in methods:
                provide_automatic_options = True
                required_methods.add('OPTIONS')
            else:
                provide_automatic_options = False

        methods |= required_methods

        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError('View function mapping is overwriting an '
                                     'existing endpoint function: %s' % endpoint)
            self.view_functions[endpoint] = view_func  # 重要的一句, 看样是是字典增加键值对的操作, key: endpoint: value: func

打印下view_function

from flask import Flask, views, render_template, request

app = Flask(__name__)

print(app.view_functions)


class Login(views.MethodView):

    def get(self):
        return render_template('login.html')

    def post(self):
        return request.form.get('username')


app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"))
print(app.view_functions)
if __name__ == '__main__':
    app.run("0.0.0.0", 9999)

# 结果:
{'static': <bound method _PackageBoundObject.send_static_file of <Flask 's1'>>}
{'static': <bound method _PackageBoundObject.send_static_file of <Flask 's1'>>, 'login': <function View.as_view.<locals>.view at 0x00000188DEA61E18>}

上面代码中也写出了正确的CBV写法,就是通过这一行代码:

app.add_url_rule("/login", endpoint=None, view_func=Login.as_view(name="login"))

@app.route()调用add_url_rule()来添加对应关系,我们也可以自己调用add_url_rule()。

继承关系,写的Login继承的是 views.MethodView,MethodView又继承 MethodViewType, View ,在class View中有个as_view方法

view_func就等于Login.as_view(name='login')的执行结果

as_view()中的name参数是必须要传的, name是用来填充endpoint的,如果endpoint有值的话,name就没用,没有值的话name就是endpoint。

CBV后面也要执行as_view()这和django一样, 甚至连内部的逻辑都是大致相同, 执行完as_view()后return出一个函数, 这个函数会获取对应请求方式的函数, 也就是执行和请求方式对应的函数

简单看下as_view()

@classmethod
    def as_view(cls, name, *class_args, **class_kwargs):

        def view(*args, **kwargs):
            self = view.view_class(*class_args, **class_kwargs)
            return self.dispatch_request(*args, **kwargs)

        if cls.decorators:
            view.__name__ = name
            view.__module__ = cls.__module__
            for decorator in cls.decorators:
                view = decorator(view)

        # view进行赋值,view就是上面的函数,cls就是类Login,name就是login
        view.view_class = cls
        view.__name__ = name
        view.__doc__ = cls.__doc__
        view.__module__ = cls.__module__
        view.methods = cls.methods
        view.provide_automatic_options = cls.provide_automatic_options
        return view  # 将内部函数view返回

再来看看class MethodViewType

class MethodViewType(type):
    def __init__(cls, name, bases, d):
        super(MethodViewType, cls).__init__(name, bases, d)
        
        # d是一个字典,如果自己没有定义methods
        if "methods" not in d:
            methods = set()

            for base in bases:
                if getattr(base, "methods", None):
                    methods.update(base.methods)

            for key in http_method_funcs:
                if hasattr(cls, key):
                    methods.add(key.upper())

            if methods:
                cls.methods = methods
    

 然后走视图函数:

    def dispatch_request(self, *args, **kwargs):
        meth = getattr(self, request.method.lower(), None)
        # 拿到request.method.lower(),比如有get之类的。
        # self就是实例化的login对象

        # If the request method is HEAD and we don't have a handler for it
        # retry with GET.
        if meth is None and request.method == "HEAD":
            meth = getattr(self, "get", None)

        assert meth is not None, "Unimplemented method %r" % request.method
        return meth(*args, **kwargs)
        # 给meth加括号返回了

HTTP 请求方法

根据 HTTP 标准,HTTP 请求可以使用多种请求方法。

HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法。

HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

常用的8中,在源码中也有:

具体的解释:

序号 方法 描述
1 GET 请求指定的页面信息,并返回实体主体。
2 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
3 HEAD 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
4 OPTIONS 允许客户端查看服务器的性能。
5 DELETE 请求服务器删除指定的页面。
6 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
7 TRACE 回显服务器收到的请求,主要用于测试或诊断。
8 PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新 。

Flask-Session

官方认可的第三方组件

需要安装:pip3 install flask-session

from flask import Flask, session
from flask_session import Session

app = Flask(__name__)
Session(app)

@app.route('/login')
def login():
    session["username"] = 200
    return '200 ok'


if __name__ == '__main__':
    app.run('0.0.0.0', 9999)

 redis和python

Windows下载redis

https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100

正常安装后配置好环境变量

redis-server

redis-cli

set  k  设置

get  k  取值

select 0-15 默认是0,最多到15,用于数据隔离,避免重复

python中的用法:

from redis import Redis

r = Redis(host='127.0.0.1', port=6379, db=6)
r.set("name", '456')
print(r.get('name'))

 Flask中redis和session

from flask import Flask, session
from flask_session import Session
from redis import Redis

app = Flask(__name__)
app.config['SESSION_TYPE'] = "redis"
app.config['SESSION_REDIS'] = Redis(host="127.0.0.1", port=6379, db=6)
Session(app)


@app.route('/login')
def login():
    session["username"] = 200
    return '200 ok'


if __name__ == '__main__':
    app.run('0.0.0.0', 9999)

 

posted @ 2019-07-12 15:20  blog_wu  阅读(231)  评论(0编辑  收藏  举报