• Flask框架基础2


    路由系统

    有名分组

    from flask import Flask
    app=Flask(__name__)
    
    @app.route('/<int:nid>',strict_slashes=False)
    def index(nid):
    	print(nid)
        return 'ok'
    
    #对URL最后的 / 符号是否严格要求
    strict_slashes = None
        '''
            @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>')
        '''
    

    CBV

    from flask import Flask,views
    app=Flask(__name__)
    
    class IndexView(views.View):
        methods=['GET']
        def dispatch_request(self):
            print('index')
            return 'index123'
        
    app.add_url_rule('/index1,view_func=IndexView.as_view(name='index')') # 优先找endpoint=''名字,没有找as_view中name
    
    if __name__='__main__':
        app.run()
    

    重写dispatch分发

      class IndexView(views.MethodView):
                methods = ['GET']
                #cbv添加装饰,用这个,我们看as_view中就知道了
                decorators = [auth, ]
    
                def get(self):
                    return 'Index.GET'
    
                def post(self):
                    return 'Index.POST'
    #如果我们继承了MethodView,他帮我们重写了,dispatch_request方法,他给我们做了一个分发,通过请求,来执行不同的函数
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    

    正则

    # 1.写类:继承BaseConverter
    # 2.注册:app.url_map.converters['regex'] = RegexConverter
    # 3.使用:@app.route('/index/<regex('d+'):nid>') 正则表达式会当作第二个参数传递到类中
    from flask import Flask, views, url_for
    from werzeug.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()
    

    模板

    前端页面渲染变量

    '''
    模板里面
    渲染变量
    {{}}-->和django一样
    {% for k,v in dict.item()%}
        {{v.name}}
        {{v.get("name")}}
        {{v['name']}}
    {% endfor %}
    '''
    # <a>{{url_for("l1")}}</a> --> '/login',前端页面反向解析视图函数
    
    <!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>
    

    后端

    '''
    methods=["GET","POST]
    /detail/<int:nid> 
    nid会当做参数传给我们的视图函数
    我们给模板传值的必须是关键字传值
    url_for()做反向解析,填的是endpoint的值,如果要跳转的视图没有指定endpoint,就用函数名
    
    '''
    
    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):
    
        info = USERS.get(nid)
        return render_template('detail.html',info=info)
    
    
    @app.route('/index',methods=['GET'])
    def index():
        # 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 == 'cxw' and pwd == '123':
    
                return redirect('http://www.baidu.com')
            return render_template('login.html',error='用户名或密码错误')
    
    # flask中Markup(<h1>哇!</h1>)等价django中的mark_safe('<h1>哇!</h1>'),防止前端页面xss攻击{{  | safe}}
    def func1(a,b):
        # return (f"<h1>蔡徐坤{a},{b}</h1>")
        return Markup(f"<h1>蔡徐坤{a},{b}</h1>")
    
    
    
    @app.route("/test")
    def py_test():
        return render_template('test.html', error=func1)
    
    if __name__ == '__main__':
        app.run()
    

    请求响应

    '''
    获取当前请求的内容
    1 先要导入request
    2 直接用request.方法,属性
    返回的时候,如果需要设置额外的响应参数,比如cookie,heard
    1 response=make_response(四剑客)
    2 response.设置属性=“属性值”
    3 return response
    '''
    
    from flask import Flask
    from flask import request
    from flask import render_template
    from flask import redirect
    from flask import make_response
    
    app = Flask(__name__)
    
    @app.route('/login.html', methods=['GET', "POST"])
    def login():
    
        # 请求相关信息
        # request.method  提交的方法
        print("request.method",request.method)
        # request.args  get请求提及的数据
        print("request.args", request.args)
        # request.form   post请求提交的数据
        # request.values  post和get提交的数据总和
        # request.cookies  客户端所带的cookie
        # request.headers  请求头
        # request.path     不带域名,请求路径
        # request.full_path  不带域名,带参数的请求路径
        # request.script_root
        # request.url           带域名带参数的请求路径
        # request.base_url		带域名请求路径
        # request.url_root      域名
        # request.host_url		域名
        # request.host			127.0.0.1:500
        # request.files
        # obj = request.files['the_file_name']
        # obj.save('/var/www/uploads/' + secure_filename(f.filename))
    
        # 响应相关信息
        # return "字符串"
        # return render_template('html模板路径',**{})
        # return redirect('/index.html')
        #return jsonify({'k1':'v1'})
    
        # response = make_response(render_template('index.html'))
        # response是flask.wrappers.Response类型
        # response.delete_cookie('key')
        # response.set_cookie('key', 'value')
        # response.headers['X-Something'] = 'A value'
        # return response
        response1=make_response(render_template('test.html'))
        #response1.set_cookie('key_sss', 'valuessbbsd')
        # response1.delete_cookie('key_sss')
        response1.headers['sb'] = 'asdas'
        return response1
    
    if __name__ == '__main__':
        app.run()
    

    session

    # 设置:session['username'] = 'xxx'
    # 在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
    # 在flask中他没有数据库,但session是怎样实现的?
    	# 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
        #我们通过app.session_interface来查看
      
    # 删除:session.pop('username', None)
    
    
    # session源码的执行流程
    """
    -save_seesion
    	-响应的时候,把session中的值加密序列化放到了cookie中,返回到浏览器中
    -open_session
    	-请求来了,从cookie中取出值,反解,生成session对象,以后在视图函数中直接用sessoin就可以了。
    """
    
    from flask import Flask,session
    
    app = Flask(__name__)
    app.debug=True
    app.secret_key="ajsdklas" # 设置密钥
    app.config['SESSION_COOKIE_NAME']="session_key"
    # app.session_interface
    @app.route("/")
    def index():
        session['name']="sb"
        return "ok"
    
    @app.route("/test")
    def test():
        print(session['name'])
        return "ok1"
    
    if __name__ == '__main__':
        app.run()
    

    闪现flash

    '''
    1 设置flash
        1.1 flash("要传递的值",category="分类的名称"),如果不传默认是message
        本质:session['_flash']
    2取flash设置的值我们用get_flashed_messages
     2.1 get_flashed_messages(with_categories=False, category_filter=()),
        2.1.1如果不传递 category_filter,取出上面存储的所有分类传递的值
        2.1.2如果不传with_categories就只取值,不取分类的名字,如果传值,就获取 分类名和分类值
        
    3 这个flash只能一个视图函数中取,只要有一个视图函数取过了,那其他视图函数就不能获取
        本质:session.pop("_flash")
        3.1 但是在同一个视图函数里面可以无限的取值
    '''
    
    from flask import Flask,flash,get_flashed_messages,request,redirect
    
    app = Flask(__name__)
    app.debug=True
    app.secret_key = 'asdfasdf'
    
    @app.route('/index')
    def index():
        # 从某个地方获取设置过的所有值,并清除。
        #flash('超时错误',category="x1")
        flash("它过来了,你要小心")
        flash("我是第二个",category="ss")
        return "ssdsdsdfsd"
        # return redirect('/error')
    
    
    @app.route('/error')
    def error():
        """
        展示错误信息
        :return:
        如果get_flashed_messages(with_category=True)
        """
        #data = get_flashed_messages(category_filter=['x1'])
        data=get_flashed_messages(with_categories=True,category_filter=['ss'])
        data1 = get_flashed_messages(with_categories=True, category_filter=['ss'])
        print(type(data))
        print(data1)
        return "错误信息:%s" %(data,)
    
    
    if __name__ == '__main__':
        app.run()
    

    请求扩展

    """
    1 before_request 请求之前
        1.1可写多个befor_request函数
        1.2而且是从上往下执行的
        1.3 一旦有返回值,请求的视图函数不会执行,已经剩下的befor_request不会执行
        
    2 after_request 请求之后
        2.1可以写多个after_request函数
        2.2 所有的after_request是从下往上执行,和befor_request相反
        2.3 无论 befor_request有没有返回值,我的after_request都会执行
        2.4 必须接收response,而且必须返回response
        
    3 before_first_request 是我项目启动后,接受到的第一个请求,会执行该函数,后面就不会在执行
    
    4 teardown_request(e)
        4.1 这是e 是接收我服务器抛出的异常
        4.2 无论我服务器有没有错误,都会执行该函数
        4.3 虽然能接收异常,但是没有办法处理异常
        
    5 errorhandler(500) 
        5.1 参数的中值为错误码
        5.2 当服务器抛出对应状态码的异常,就会执行该函数
        5.3 并且该函数可以处理异常,让用户无法感知,服务器错误
        5.4 每一个错误码,都需要一个对应的函数进行处理
    """
    
    # 第一次请求时,跟浏览器无关
    @app.before_first_request
    def first():
        pass
    
    # 基于它做用户登录认证
    # 类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情 
    @app.before_request
    def process_request(*args,**kwargs):
        if request.path == '/login':
            return None
        user = session.get('user_info')
        if user:
            return None
        return redirect('/login')
    
    # 类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常 
    @app.after_request
    def process_response1(response):
        print('process_response1 走了')
        return response
    
    # 每一个请求之后绑定一个函数,即使遇到了异常 
    @app.teardown_request 
    def ter(e):
        pass
    
    # 全局前端页面都可以获取数据
    @app.template_global()
    def sb(a1, a2):
        return a1 + a2
    #{{sb(1,2)}}
    
    # 过滤器
    @app.template_filter()
    def db(a1, a2, a3):
        return a1 + a2 + a3
    #{{ 1|db(2,3)}}
    

    中间件

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return 'Hello World!'
    # 模拟中间件
    class Md(object):
        def __init__(self,old_wsgi_app):
            self.old_wsgi_app = old_wsgi_app
    
        def __call__(self,  environ, start_response):
            print('开始之前')
            ret = self.old_wsgi_app(environ, start_response)
            print('结束之后')
            return ret
    
    if __name__ == '__main__':
        #1我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法	
        #2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
        #3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
        #4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
        #把原来的wsgi_app替换为自定义的,
        
        app.wsgi_app = Md(app.wsgi_app)
        app.run()
    
  • 相关阅读:
    linux查找日志技巧
    路径选择算法|Floyd算法|Dijkstras算法(带GUI界面带实验报告)
    待整理
    ClassLoader类加载解惑
    SAX解析xml
    DOM 表单应用
    网站前端优化14条
    用wordpress制作网站的总结
    海豚浏览器前端面试总结
    程序员的美妙生活
  • 原文地址:https://www.cnblogs.com/gaohuayan/p/11600507.html
Copyright © 2020-2023  润新知