首页 > 其他分享 >flask_04days

flask_04days

时间:2024-03-04 17:12:07浏览次数:26  
标签:04days flask app request --- session cookie view

cbv源码分析

 执行流程

# 1 app.add_url_rule('/user', 'user', UserView.as_view('user'))
    -第三个参数,放视图函数的内存地址---》UserView.as_view('user') 是函数内存地址
# 2 UserView中找类方法as_view--》返回值是一个函数内存地址
    -UserView中没有
    -MethodView---》View--》as_view()

    @classmethod
    def as_view(cls, name,*class_args, **class_kwargs):
        def view(**kwargs):
            return self.dispatch_request(**kwargs)
        return view
    
    
# 3 app.add_url_rule的第三个位置,放的是 view 内层函数

# 4 请求来了--》路由匹配成功--》执行 view(参数)---》本质在执行 --》self.dispatch_request

# 5 MethodView 上的 dispatch_request --》有具体实现
    -不要去View中找dispatch_request---》因为它直接抛了异常,没有实现
# 6 MethodView 上的 dispatch_request
    def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue:
        # request.method.lower() 请求方式变小写
        # self是视图类的对象
        # 去视图类的对象中反射跟请求方式同名的方法 假设是get方法
        meth = getattr(self, request.method.lower(), None)
        if meth is None and request.method == "HEAD":
            meth = getattr(self, "get", None)
        assert meth is not None, f"Unimplemented method {request.method!r}"
        # get(传入参数)
        return meth(**kwargs)  
    
    
    
# -----------上述跟django一模一样------

endpoint 的使用

##2  endpoint 的使用
app.add_url_rule('/item', endpoint='xxx',view_func=ItemAPI.as_view('item'))
如果写了endpoint---》别名以它为准,如果不写以as_view的参数为准

## 逻辑:
1 app.add_url_rule('/item',endpoint='xxx', view_func=ItemAPI.as_view('item'))
2 endpoint = _endpoint_from_view_func(view_func)
    如果endpoint没传,就会走这句
   
    view_func 是  ItemAPI.as_view('item')  它就是 view
    
3 _endpoint_from_view_func(view_func)---》返回了传入的函数的名字
    return view_func.__name__
    # 如果没有其他更改--->所有cbv的函数内存地址都是view

4 如果上面传入了ItemAPI.as_view('item'),它的函数名就是view---》endpoint就是view
    -view.__name__ = name
    -view的名字 是咱么  ItemAPI.as_view('名字') 传入的名字,不再是view了


## 总结:
    endpoint如果不传,会以视图函数的函数名作为endpoint
        -fbv:如果不写endpoint,会以函数名作为endpoint,但是如果多个视图函数加了同一个装饰器,又没有指定endpoint,就会出错了
        -cbv:调用as_view一定要传入一个字符串---》如果endpoint没写,endpoint就是传入的这个字符串,如果写了,这个字符串没用
        
    如果传了,直接以endpoint传入的作为endpoint

CBV加装饰器

### cbv中加装饰器
    1 使用步骤:在类中加入类属性:
        class ItemAPI(MethodView):
            decorators = [装饰器,装饰器2] # 先写的装饰器放在最内部---》最后执行
            def get(self):
                # print(url_for('xxx'))
                print(url_for('item'))
                return 'get'
    2 源码中
       if cls.decorators:
          for decorator in cls.decorators:
               # 这就是装饰器的本质原理
                view = decorator(view)   
                '''
                @装饰器
                def view()
                '''

session执行流程分析

 基本使用

# cookie 是客户端浏览器的键值对
# session是存在于服务端的键值对

# flask的session存在哪了?
    加密后放到了cookie中


from flask import Flask, request, session
from flask.views import MethodView

app = Flask(__name__)
app.secret_key = 'asdfasdf'


@app.route('/login', methods=['GET'])
def login():
    name = request.args.get('name')
    # 假设登录成功
    session['name'] = name

    return 'hello'


@app.route('/', methods=['GET'])
def index():
    print(session.get('name'))
    res = session.get('name')
    if res:
        return '欢迎你,%s' % res
    else:
        return '您没有登录'


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

执行流程

# flask中通过SecureCookieSessionInterface对象来控制整个session的使用流程
app.session_interface=SecureCookieSessionInterface()


# 1 登录成功---》放到session中数据----》把session中数据取出来,加密(dump)---》放到cookie-----》返回给前端--》save_session

# 2 请求来了---》请求中携带了cookie ---》取出cookie-->解密(load)得到数据--》把数据放到session中---》进入视图函数--》后续视图函数中直接使用session.get 就能取到当时放入的值--》open_session

# 不同浏览器,放的不一样,取出来也不一样


###  SecureCookieSessionInterface 俩方法来支撑上面的流程
# open_session: 请求来的时候--》解析出cookie,放到session中
def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None:
    # 拿到解密或加密的对象
    s = self.get_signing_serializer(app)
    if s is None:
        return None
    
    # request.cookie 取出客户端携带的cookie
    #self.get_cookie_name(app) ---》 app.config["SESSION_COOKIE_NAME"]--》session
    # eyJuYW1lIjoieHh4In0.ZeVMAw.2iCEYHAW7rDaH6Z5ntmKonErTbw
    val = request.cookies.get(self.get_cookie_name(app))
    if not val:
        # 如果是空,走它---》做成空session--》返回
        return self.session_class()
    # cookie在过期时间内
    max_age = int(app.permanent_session_lifetime.total_seconds())
    try:
        # 解密--》把eyJuYW1lIjoieHh4In0.ZeVMAw.2iCEYHAW7rDaH6Z5ntmKonErTbw解成字典
        data = s.loads(val, max_age=max_age)
        # 组装成有 数据的session
        return self.session_class(data)
    except BadSignature:
        return self.session_class()
    
    
    
# save_session:请求走的时候---》放到cookie中
    def save_session(self, app: Flask, session: SessionMixin, response: Response) -> None:
        # 拿到  session 字符串  拿到配置文件中对应的配置
        name = self.get_cookie_name(app)
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)
        secure = self.get_cookie_secure(app)
        samesite = self.get_cookie_samesite(app)
        httponly = self.get_cookie_httponly(app)
        if session.accessed:
            response.vary.add("Cookie")
            
        # 如果不为空---》往下走---》视图函数中放入了值  session[name]=lqz
        if not session:
            # 判断session是否被修改过
            if session.modified:
                # 删除cookie
                response.delete_cookie(
                    name,
                    domain=domain,
                    path=path,
                    secure=secure,
                    samesite=samesite,
                    httponly=httponly,
                )
                response.vary.add("Cookie")

            return

        if not self.should_set_cookie(app, session):
            return

           # 获取过期时间
        expires = self.get_expiration_time(app, session)
        # 获得加密对象 ---》 dumps 对 session  加密---》asdfas.asdfas.asdfasd
        val = self.get_signing_serializer(app).dumps(dict(session))  # type: ignore
        # 放到cookie中
        response.set_cookie(
            name,
            val,  # type: ignore
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )
        response.vary.add("Cookie")
        
        
        
        
# django 在中间件中做的
    session不是直接加密放在cookie 中得, 加密放在 django-session表中--》有个随机字符串对应

django中session的流程

# 1 app中要注册 session ---》生成django-session表
    'django.contrib.sessions',
    
# 2 中间件要注册--》真正支撑session流程的
'django.contrib.sessions.middleware.SessionMiddleware',

# 3 支撑session流程的
请求走了---》把session--》写入到cookie中
    -process_response(self, request, response):---》等价于---》save_session
请求来了---》从cookie中取出来--》查数据库--》放到session中
    -def process_request(self, request)---》等价于---》open_session



def process_request(self, request):
    # 取出 前端在cookie中携带的  随机字符串
    session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
    # SessionStore 实例化得到对象---》session_key是随机字符串
    # 内部 根据随机字符串去django-session表中--》查出 session_data--》解密--》包装成对象
    # 赋值给request.session -->后续所有视图函数中,都能使用request.session 放值或取值
    request.session = self.SessionStore(session_key)

def process_response(self, request, response):
    try:
        accessed = request.session.accessed
        modified = request.session.modified
        empty = request.session.is_empty()
    except AttributeError:
        return response
    if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
        response.delete_cookie(
            settings.SESSION_COOKIE_NAME,
            path=settings.SESSION_COOKIE_PATH,
            domain=settings.SESSION_COOKIE_DOMAIN,
            samesite=settings.SESSION_COOKIE_SAMESITE,
        )
        patch_vary_headers(response, ('Cookie',))
    else:
        if accessed:
            patch_vary_headers(response, ('Cookie',))
        if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
            if request.session.get_expire_at_browser_close():
                max_age = None
                expires = None
            else:
                max_age = request.session.get_expiry_age()
                expires_time = time.time() + max_age
                expires = http_date(expires_time)
            # Save the session data and refresh the client cookie.
            # Skip session save for 500 responses, refs #3881.
            if response.status_code != 500:
                try:
                    request.session.save()
                except UpdateError:
                    raise SessionInterrupted(
                        "The request's session was deleted before the "
                        "request completed. The user may have logged "
                        "out in a concurrent request, for example."
                    )
                # 往cookie中放入 key是:session  value值是随机字符串: request.session.session_key
                response.set_cookie(
                    settings.SESSION_COOKIE_NAME,
                    request.session.session_key, max_age=max_age,
                    expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None,
                    httponly=settings.SESSION_COOKIE_HTTPONLY or None,
                    samesite=settings.SESSION_COOKIE_SAMESITE,
                )
    return response

闪现

#1  它是:flash 翻译过来的
#2  闪现的作用
在某次请求中,有些数据,可以放在闪现中----》下次请求,从闪现中取出来使用
取一次就没了,下次再取就是空的
谁(浏览器)放的 ,谁(浏览器)才能取到
实际上放了session中了---》cookie
# 3 如何设置,如何取值
###基本使用
# 设置
flash('用户名或密码错误,%s' % username)
# 取值
res = get_flashed_messages()[0]

## 高级使用---》设置flash时,给它设置category 分类
# 设置
flash('用户名或密码错误,%s' % username, category='login')
#取值(注意取出来的格式,列表套元组)
res=get_flashed_messages(True,category_filter=['login'])



# django中有没有这种东西?  消息框架
    django.contrib.messages
    
    
    
# 1 注册app
  'django.contrib.messages',

    
    
# 2 注册中间件
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
    
    
# 3 配置 templates
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                                ...
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
# 3 以后再视图函数中 放入
from django.contrib import messages
messages.debug
messages.info
messages.success
messages.warning
messages.error
messages.warning(request,'登陆失败,用户名或密码无效')

# 4 在 视图函数中取
get_messages(request)
# 4 在模板中
{% if messages %}
    {% for message in messages %}
        <div class="alert alert-{{ message.tags }} fade in">
            {{ message }}
        </div>
    {% endfor %}
{% endif %}

请求扩展

# 是几个装饰器--》功能是完成类似于django 的中间件--》在请求来和请求走的某些位置执行它

1 before_request:任意一次请求来了,都会执行这个装饰器装饰的函数  process_request

2 after_request:任意一次请求走了,就会执行这个装饰器装饰的函数  process_response

3 before_first_request  # 新版本去掉了 第一次请求时,跟浏览器无关

4 teardown_request :每一个请求之后绑定一个函数,即使遇到了异常

5 errorhandler:监听http响应码:只要响应码对应,就会执行对应的函数
    路径不存在时404,服务器内部错误500

6 template_global :标签

7 template_filter:过滤器
#1 before_request
@app.before_request
def before_request():
    # 1 判断如果没有登录,重定向到登录
    if session.get("name") or 'login' in request.path:
        print('请求来了1')
    # 2 做频率限制
    # 3 登录认证,认证通过,在request.user 当前登录用户   jwt认证

    else:
        return redirect('/login')


@app.before_request
def before_request():
    print('请求来了2')


#2 after_request
@app.after_request
def after_request(response):
    # 1 在响应头中加入一些数据  --》跨域处理
    response.headers['ee'] = 'xx'
    print('请求走了1')
    return response


@app.after_request
def after_request(response):
    print('请求走了2')
    return response


#3 记录日志
@app.teardown_request
def teardown_request(error):
    print(error)


# 4 errorhandler
@app.errorhandler(404)
def error_404(error):
    print('----',error)
    return render_template('404.html')

@app.errorhandler(500)
def error_500(error):
    print('----',error)
    return render_template('500.html')



##5  标签
@app.template_global()
def sb(a1, a2):
    return a1 + a2


# 6 过滤器
@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3

g对象

from flask import Flask, g

# g 对象 global 全局的意思---》每次请求---》这个g一直存在--》可以设置值和取值
# g本质是为了避免request对象 放值导致的数据污染问题,以后都用g放入值和使用
app = Flask(__name__)
app.secret_key = 'asdfasdf'


@app.before_request
def before():
    # jwt认证---》认证通过--》request.user=当前登录用户
    # g.user=当前登录用户
    request.methods='lqz'
    g.name = 'lqz'  # 放入了


@app.after_request
def after(response):
    print('----', g.name)
    return response


def showName():
    print('showName', g.name)


@app.route('/', methods=['GET'])
def index():
    # 取出g中得值
    print(g.name)
    showName()
    return '欢迎你'


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

 

标签:04days,flask,app,request,---,session,cookie,view
From: https://www.cnblogs.com/wzh366/p/18052160

相关文章

  • Flask的CBV用法
    FBV写法fromflaskimportFlask,jsonifyapp=Flask(__name__)[email protected]('/')defindex():return'hello'CBV写法#导入模块fromflask.viewsimportMethodView#固定写法fromflaskimportFlaskapp=Flask(__name__)ap......
  • Flask转换器
    配置文件预览DEFAULT_CONVERTERS={'default':UnicodeConverter,'string':UnicodeConverter,'any':AnyConverter,'path':PathConverter,'int':......
  • Flask路由系统
    前置代码fromflaskimportFlask,jsonifyapp=Flask(__name__)1flask路由系统是基于装饰器的,但是它的本质是:add_url_rule2装饰器的参数及作用'''1rule:路径2methods:可以允许的请求方式3endpoint:路由别名'''3如果不用装饰器注册路由,需要使......
  • Flask使用装饰器注意点
    一装饰器,需要放在路由装饰器下面'''在执行视图函数之前,做判断--》路由的装饰器是控制路由匹配的--》需要先执行,所以登录认证装饰器,需要放在下面'''二需要直接指定路由别名原因'''直接添加会报错————每个路由,都会有个别名,如果不写,默认以函数名作为别名如果视图......
  • Flask新手四件套、session、转换器、取数据与模板语法
    新手四件套(返回格式)#导入fromflaskimportFlask,request,render_template,redirect,session#返回字符串return'字符串'#返回模板returnrender_template('模板名字')#传参returnrender_template('模板名字',key=value)#返回重定向returnredirect('/......
  • flask_02
    #1flask介绍 web框架---》小而精--》第三方插件--》完成更丰富的功能--》自由选择第三方插件#2wsgi协议:werkzeug:工具包uwsgi,wsgiref djagno,flask要遵循wsgi协议#3click定制命令 -定制命令--》把excel中得数据---》导入到mysql的某个表中......
  • Flask项目运行方式
    方式一(pycharm配置)首先新建一个flask-server目标文件选择需要运行的文件地址即可方式二:命令运行(推荐这种)flask--app文件名字.pyrun#或者python3-mflask--app文件名字.pyrun方式三:右键运行#必要代码if__name__=='__main__':app.run()方式四:命......
  • Flask_01
    #1下载中间件和爬虫中间件 -爬虫中间件---》控制输入输出---》一般不用#2下载中间件 -process_request:request对象,请求头,请求地址。。-process_response:response#3修改请求头,加入cookie,加入referer,加入请求头,加代理:request.meta['proxy']#4集成selenium---》性能低 ......
  • Python flask
    {{变量}}_init_.py这个文件的执行时间package,moduledebug模式、host、portdebug模式:热更新可以在浏览器上面显示错误信息host让别人可以访问自己的电脑url与试图映射urlRESTful风格传参@app.route('/user/<user_id>')#可以指定参数的类......
  • flask+gunicorn的小型缓存实现
    为了提高flask的查询速度,构想先把数据放在一个字典中,然后将这个字典作为缓存使用,后来遇到gunicorn多进程不能共享变量的问题(广义上多进程共享变量都是困难的),后来想过采用redis作为缓存数据,但配合我的场景使用起来太麻烦,后来又继续研究共享变量的问题,起初搜索到multiprocessing模......