• flask框架 如何启动flask项目, flask四剑客(返回字符串, 返回html, 跳转路由, 返回json), flask的配置文件, 路由本质以及参数, 自定义转化器, flask的模板渲染,flask的请求与响应, flask的session,闪现


    如何启动一个flask项目

    '''
    pip install flask
    
    '''
    # 1 导入flask,我们要用flask,就必须导入Flask
    from  flask import Flask
    # 2 生成一个Flask对象,__name__表示当前文件的名字
    app = Flask(__name__)
    
    
    
    # 3 添加路由,flask用的是装饰器的模式
    #注册路由,并写响应函数index
    @app.route("/")
    def index():
        return "Hello flask"
    
    if __name__ == '__main__':
        #4 启动flask
        #run里面是执行了run_simple(host,port,self=app,也就是flask对象)
        app.run()

    flask四剑客 (返回字符串,返回html,跳转路由,返回json)

        2.1 直接返回字符串
        2.2 render_template("html页面")
        2.3 redirect 页面跳转
        2.4 jsonify  返回json
    # 1 如何响应一个字符串
    # 2 如何响应一个html页面
    # 3 如何跳转页面
    # 4 如何返回一个json字符串
    
    from  flask import Flask,render_template,redirect,jsonify
    app = Flask(__name__)
    @app.route("/index")
    def index():
        #1 返回字符串
        #return "你号,我是字符串"
        # 1  返回一个html,
                # 1 从flask里面导入render_template,2 在同级目录中添加templates文件夹,将html页面这个文件夹底下
        #return render_template("index.html")
        # 3 跳转路由,1 从flask里面导入redirect
        #return  redirect("/login")
        # 4 返回数据转json返回,要从flask中导入jsonify
        data = {'name':"jason","name1":"owen"}
        return  jsonify(data)
    
    @app.route("/login")
    def login():
        return "我是login页面"
    
    
    if __name__ == '__main__':
        app.run()

    flask的配置文件

        3.1 直接给app属性赋值 只能给app.debug和app.secret_key配置
        3.2 给app.config["DEBUG"]等设置属性
        3.3 文件的形式给flask作配置,app.config.from_pyfile("settings.py"),这个和django一样
        3.4 以类的形式给flask作配置,app.config.from_object("setting.Test"),表示setting文件中Test为配置。推荐使用这样
    # 4中方法给flask做配置
    
    # 1直接给app对象赋值属性
    # 2 以字典的形式,给flask做配置
    # 3 以文件的形式,给flask做配置(django就是用这种)
    # 4 以类的形式,给flask做配置(如果用flask,推荐是使用第4中)
    
    from flask import Flask
    
    app = Flask(__name__)
    # 1方式1(不推荐),因为他只能配置两个配置项,一个是debug 一个是secret_key
    # app.debug = True
    
    # 2 方式2 字典的形式,这个里面就可以对所有的flask配置项做配置
    #app.config["DEBUG"] = True        # 必须要和配置一样,得大写
    
    #3 方式3 以文件的形式,在form_pyfile(里面传递配文件的路径)这个和django一样
    #app.config.from_pyfile("settings.py")
    
    # settings.py中代码如下
    # DEBUG = True
    
    #4 方式4 以类的形式,那为什么推荐大家使用这个呢?因为他可以实现一个文件多个配置,而且减少测试与上线更改的配置项
    app.config.from_object("setobj.settings")
    
    # setobj.py中的代码如下
    # class settings:
    #   DEBUG = True
    
    @app.route("/")
    def index():
        return "jason is dsb"
    
    if __name__ == '__main__':
        app.run()

    路由本质以及参数

        4.1 我们可以有两种方式配置路由,第一种是装饰器的形式@app.route("/"),第二种,app.add_url_rule("/",view_func=响应函数函数对象)
        4.2 路由种的参数之rule:就是路由,他作有名分组,@app.route("/<int:nid>"),响应函数的接收这个参数必须和nid一致
        4.3 路由参数之endpoint,用于反向解析的,和以不传,如果不传就是用响应的函数名,做为反向的。
        4.4 如何做反向解析,url_for(endpoint),如果用"/<int:nid>"那我们写url_for("index",nid=111)
        4.5  路由参数之view_func:表示的是响应函数的函数对象
        4.6   路由参数之methods,该路由可以允许哪些请求方法请求
    from flask import Flask,url_for,redirect
    app = Flask(__name__)
    # @app.route("/")
    def index(nid):        # 必须与有名分组<int:nid>中的nid一致
        print(nid,type(nid))
    
        return "ojbk"
    
    #@pp.route的本质就在执行add_url_rule这个中的rule是路由,endpoint是路由别名,view_func是响应函数
    #如果endpoint不传就是响应的函数名
    
    app.add_url_rule("/index/<int:nid>", endpoint="index1",view_func=index,methods=["POST","GET"])
    
    @app.route("/login",methods=["POST"])
    def login():
        #用endpoint取路由要用url_for 在flask中导入,也就是反向解析
        print(url_for("index1"))
        # return  redirect(url_for("index1"))
    
    #路由参数;methods,可以控制该方法能有哪些请求方式可以访问      默认为get方法
    #app.add_url_rule("/index", endpoint="index1",view_func=index,methods=["POST"])     等价于@app.route('/login',methods=['POST'])
    
    # 路由参数:有名分组,app.add_url_rule("/index/<int:nid>"响应函数必须用nid来接收
    # ps:经过测试,当methods=["POST"],若login跳转到index1路径,postman发post方法不被允许。但是若method方法有methods=["GET"],login可以发送get请求
    
    
    if __name__ == '__main__':
        app.run()
        
     '''
     总结:
     1 @app.route("/login") 的本质app.add_url_rule("/login",view_func=login),所以我们就可以用这两个方式来添加路由
     2 路由的参数,
         2.1 endpoint,做是反向解析,如果上面添加路由的时候,没有传递endpoint就是使用响应函数的函数名,反向解析用url_for(),做解析,这个url_for必须在flask里面导入。url_for(endpoint),如果用"/<int:nid>"那我们写url_for("index",nid=111)
         2.2 methods=["POST","GET"],该参数控制路由允许哪些请求方法访问,如果不传,默认只能GET方法
         2.3 路由以及路由路由转化器。"/index/<int:nid>",<参数的类型:用哪个变量来接收>,响应函数中的形参的名字必须转化器中一致。
     
     '''   
       

    自定义转化器

    #非重点
    #1 写类,继承BaseConverter
    #2 注册:app.url_map.converters['regex'] = RegexConverter
    # 3 使用:@app.route('/index/<regex("d+"):nid>')  正则表达式会当作第二个参数传递到类中
    
    from flask import Flask, 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):
            """
            路由匹配时,匹配成功后传递给视图函数中参数的值
            """
            print("to_python",value,type(value))
            return int(value)+1
    
        def to_url(self, value):
            """
            使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
            """
            val = super(RegexConverter, self).to_url(value)
            return val+"222"
    
    # 添加到flask中      把定义的类注册到converters
    app.url_map.converters['regex'] = RegexConverter    # regex与RegexConverter类中的构造函数regex一致
    # 正则匹配处理结果,要交给to_python,to_python函数可以对匹配处理结果做处理
    @app.route('/index/<regex("d+"):nid>')    # 名字与上面的regex保持一致
    def index(nid):
        print("index",nid,type(nid))    # index 89 <class 'int'>
        print(url_for('index', nid='888'))    # /index/888222
        return 'Index'
    
    if __name__ == '__main__':
        app.run()

    总结:

    1 导入from werkzeug.routing import BaseConverter
    2 我写个继承BaseConverter。实现3个方法,def __init__ , def to_python , def to_url
    3 将上面的类注册到app.url_map.converters['regex'] = RegexConverter中
    4 然后就可以在路由转化器中使用3中的regex("传正则"5 当路由被访问以后。regex("传正则")会匹配结果,把结果传递to_python,我们可以进行再次处理,to_python处理好的结果,会传递给响应函数的形参
    6 当用url做反向解析的时候,传递给路由转化器的参数,会经过to_url,进行处理。处理以后,在拼接到路由。

    flask的模板渲染

        渲染模板语言和django很像,都是用{{}},{%%},
        注意点:1 flask给模板传值,render_template("index.htm",user=user,name=name)
            2  flask的模板语言支持对函数的调用。for 循环的循环对象,再py中要加括号的,模板语言中也要加括号。
            3 显示原生的html 如果是管道符 html|safe,如果是后端处理,就是用Markup
    from flask import Flask,render_template,Markup
    app = Flask(__name__)
    app.debug = True
    
    
    USERS = {
        1:{'name':'张三','age':18,'gender':'','text':"道路千万条"},
        2:{'name':'李四','age':28,'gender':'','text':"安全第一条"},
        3:{'name':'王五','age':18,'gender':'','text':"行车不规范"},
    }
    
    def func1(arg,tank):
        return Markup(f"<h1>饼哥正帅,{arg} is sb {tank} is same as {arg}</h1>")
    
    @app.route("/")
    def index():
        # data = {
        #     "user" :USERS,
        #     "name": "jason"
        # }
        return render_template("index.html",user = USERS,name="jason",ht1 = func1,ht="<h1>饼哥正帅</h1>")
        #return render_template("index.html",**data)
    
    
    
    
    if __name__ == '__main__':
        app.run()

    html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1> 我是html</h1>
    <table>
    {% for k,v in user.items() %}    <!--flask允许内部加括号-->
       <tr>
           <td>{{ k }}</td>
           <td>{{ v.name }}</td>
           <td>{{ v['name'] }}</td>
           <td>{{ v.get('name') }}</td>
           <td>{{url_for("index")}}</td>
       </tr>
    {% endfor %}
    </table>
    
    <div>{{name}}</div>
    
    {% if name == "jason" %}
        <h1>is sb</h1>
    {% else %}
        <h1>水哥</h1>
    {% endif %}
    
    {{ ht|safe}}
    {{ht1("jaosn","tank")}}
    </body>
    </html>

    flask的请求与响应

        5.1 请求,所有的请求都要从flask种导入request.所有请求的东西都在request
        5.2 响应相关,把flask的四剑客传到make_response(四剑客),得到一个response对象,我们就可以对response设置请求头,设置cookie。
    from flask import Flask,request,make_response,render_template,redirect
    
    app = Flask(__name__)
    
    @app.route("/",methods=["POST","GET"])
    def index():
        # 请求相关的信息
        # print("请求方法",request.method)#请求方法
        # print("get请求的参数",request.args)# get请求的参数
        # print("post请求的参数",request.form) #post请求的参数
        # print("post,与get的所有参数",request.values)#post,与get的所有参数
        # print("请求的cookies",request.cookies)#请求的cookies
        # 请求相关信息
        # request.method  提交的方法
        # request.args  get请求提及的数据
        # 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
    
        #关于响应我们已经将了4剑客,如果添加响应头,已经cookie
        #要添加这些东西必须,导入make_response,
    
        response = make_response("ok")
        #response = make_response(render_template("login.html"))
        #response = make_response(redirect("/login"))
        #设置cookie
        #response.set_cookie("key","val")
        #如何删除cookie
        #response.delete_cookie("key")
        # 如何设置响应头
        response.headers["x-somexx"] = "A SB"
        return  response

    flask的session

    直接设置加密成cookie返回给前端

    然后前端再根据加密的cookie去后端解密后拿到session

        7.1 全局导入session,把session,当字典存值,取就当字典取值
        7.2 原理之存session
        当响应要返回给客户端时候,会调用sesssion_interface中的save_session方法。把全局session字典做加密得到val,然后将这个val设置到cookie中。cookie的键为配置文件中的session_cookie_name,值就是我们session字典加密得到的结果。
        7.3 原理之取session
        当flask接收到请求的时候,会调用sesssion_interface中的open_session方法,该方法中从cookie中取键为配置文件中session_cookie_name的cookie值,得到这个值以后呢,做解密。然后赋值给全局的session字典。这样我们就可以取到之前flask设置session。
        7.4 注意。用session必须配置app.secret_key="随便"

     

    from flask import Flask,session
    
    app = Flask(__name__)
    # 要用session,必须app配置一个密钥
    app.secret_key  =  "asdasdihasdiuh"
    app.config['SESSION_COOKIE_NAME']="python13session"
    
    # app.session_interface
    
    #app.session_interface实现了两个方法,一个叫save_session,一个open_session,
    
    @app.route("/",)
    def index():
        #如何设置sessoion
        # 1 导入session
        # 2 给sessoion设置值
        session['name'] = "egon"
        session["nam1"] ="sdsd"
        return "ok"
    
    @app.route("/login")
    def login():
        print(session["name"])
        return "login"
    
    if __name__ == '__main__':
        app.run()
        

    分析session的原理

    class SecureCookieSessionInterface(SessionInterface):
       
        salt = "cookie-session"
       
        digest_method = staticmethod(hashlib.sha1)
      
        key_derivation = "hmac"
       
        serializer = session_json_serializer
        session_class = SecureCookieSession
    
        def get_signing_serializer(self, app):
            if not app.secret_key:
                return None
            signer_kwargs = dict(
                key_derivation=self.key_derivation, digest_method=self.digest_method
            )
            return URLSafeTimedSerializer(
                app.secret_key,
                salt=self.salt,
                serializer=self.serializer,
                signer_kwargs=signer_kwargs,
            )
        # 取session的时候执行的
        def open_session(self, app, request):
            s = self.get_signing_serializer(app)
            if s is None:
                return None
            ##cookie键是SESSION_COOKIE_NAME"=session
            val = request.cookies.get(app.session_cookie_name)
    
            print("open_session.session_cookie_name,", app.session_cookie_name, )
            if not val:
                return self.session_class()
            max_age = total_seconds(app.permanent_session_lifetime)
            try:
                data = s.loads(val, max_age=max_age)
                print("self.session_class(data)", self.session_class(data) )
                return self.session_class(data)
            except BadSignature:
                return self.session_class()
    
        #存session的时候执行的
        def save_session(self, app, session, response):
            domain = self.get_cookie_domain(app)
            path = self.get_cookie_path(app)
    
            # If the session is modified to be empty, remove the cookie.
            # If the session is empty, return without setting the cookie.
            if not session:
                if session.modified:
                    response.delete_cookie(
                        app.session_cookie_name, domain=domain, path=path
                    )
    
                return
            # Add a "Vary: Cookie" header if the session was accessed at all.
            if session.accessed:
                response.vary.add("Cookie")
    
            if not self.should_set_cookie(app, session):
                return
            httponly = self.get_cookie_httponly(app)
            secure = self.get_cookie_secure(app)
            samesite = self.get_cookie_samesite(app)
            expires = self.get_expiration_time(app, session)
            # 把session做了一个加密,把整个session的key--》val,全部加密,的到一个value值,
            #session是一个大字典,
            val = self.get_signing_serializer(app).dumps(dict(session))
            # 他把session加密后得到的val存到cookie里面了
            #cookie键是SESSION_COOKIE_NAME"=session
            print("源码中的session",dict(session))
            print("app.session_cookie_name,",app.session_cookie_name,)
            response.set_cookie(
                app.session_cookie_name,
                val,
                expires=expires,
                httponly=httponly,
                domain=domain,
                path=path,
                secure=secure,
                samesite=samesite,
            )

    闪现

        8.1 要用必须导入flash,get_flashed_messages,
        8.2 flash 用于存闪现的值。他有两个参数,1 messsage,用来存储信息 2 category ,用于给信息分类,该参数可以不传,不传就是分类为”messsage“
        8.3 get_flashed_messages 用是用来取闪现的值,他也有两个参数:1 with_category,拿到的结果是否需要带上分类名称,2 category_filter 是用来过滤我要取哪个分类下的信息。当然这个两个都是可选的。
        注意点: 
        1 设置flash,必须设置app.secret_key="随便",因为flash是基于session的。
        2 闪现的值,不同的请求中只能取一次,当然再同一请求内是可以获取多次的。
    from flask import Flask,flash,get_flashed_messages
    
    app  = Flask(__name__)
    #app.session_interface
    app.secret_key ="sdasd"
    # 什么闪现:就像session一样,也是一个页面设置,另一个页面使用,我不管你在哪个页面调用的
    # 只要调用一次,就清空了,
    # 闪现的作用,一般用信息处理。假设用户,a页面做操作,产生了信息。我希望在b页面内获取。
    # 但是我不知道用户在什么时候,访问b页面,但是只要用户一旦访问页面就把信息显示出来。
    # 同一页面,同次请求是可以拿多次的
    @app.route("/")
    def index():
        #产生信息,message设置消息的,category给消息分类,如果不传默写用”message“
    
        flash("你错过了我")
        
        flash(message="你再次错过我",category="渣男")
        return "index"
    
    @app.route("/login")
    def login():
        #(with_categories=True,消息是否要带上分类信息,category_filter=["渣男"]对消息进行过滤,取指定的分类消息
        print(get_flashed_messages(with_categories=True,category_filter=["渣男"]))
        print(get_flashed_messages())
        return "login"
    
    
    @app.route("/test")
    def test():
        print(get_flashed_messages())
        return "test"
    
    if __name__ == '__main__':
        app.run()
        
    # 注意:即使filter过滤取,不取出来,其他网页也不能继续使用
  • 相关阅读:
    离奇的软件开发之路
    集群环境中的单例设计模式
    Android 如何更换屏幕上锁界面背景图片
    基于华为Java编程规范的Eclipse checkStyle.xml
    对数据库事务的总结
    [Sciter系列] MFC下的Sciter–1.创建工程框架
    Android 如何添加一种锁屏方式
    Hibernate级联操作 注解
    linux就是这个范儿之融于心而表于行(1)
    Android 如何修改默认的searchable items。
  • 原文地址:https://www.cnblogs.com/ludingchao/p/12554670.html
Copyright © 2020-2023  润新知