Dry goods coming. Flask framework to see which one is enough, is not concerned about getting lost, Jeff take you to see the source code. Development of technology up to date

First, acquaintance Flask

1.1 What is the flask?

img

This Flask is the author Armin Ronacher in an April Fool joke April 1, 2010, but later popular, and thus become a web framework written in a formal python

Flask is a Web framework written in a micro Python, Python language so that we can use to quickly implement a Web site or Web service, before the introduction Flask at first to talk about it and Django ties and differences, django a large and comprehensive web framework that many built-in module, flask is a small but excellent lightweight framework, Django features large and comprehensive, Flask contains only basic configuration, the idea of ​​one-stop solution Django, allowing developers do not develop it before selecting application It spends a lot of time on infrastructure. There Django templates, forms, routing, basic database management and so on built-in features. In contrast, Flask just a kernel, the default is dependent on two external libraries: Jinja2 template engine and WSGI toolset --Werkzeug, flask of use is an essential feature of all the tools rely on the form of import to expand, flask reservation only web development of core functionality.

img

WSGI (web server gateway interface) is used to specify how the python web server how to communicate with the standard Python Web program with python Web server, essentially a socket server. And Werkzeug WSGI module is a specific implementation

Keywords : a micro web framework written in Python and a two core libraries (Jinja2 template engine and WSGI toolset)

1.2 Why should the flask?

Substantially meet the performance requirements flask general web development, and the flexibility and extensibility superior to other web frame, fit for various databases are very high

Keywords : 1 2 performance basically meet the demand flexibility and strong scalability are high on 3. fit a variety of databases.

4. in a real production environment, the development of small projects fast, flexible design of large projects

Two, Flask quick start

'''
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()

Three, Flask four swordsman

'''
响应字符串
响应html页面
跳转页面
返回json字符串
'''

from flask import Flask, render_template, redirect, jsonify

app = Flask(__name__)


@app.route("/index")
def index():
    # 1.返回字符串
    # return "hello word  啊啊啊"

    # 2.返回html页面
    # 返回html,从flask里面导入render_template
    # return render_template("index.html")

    # 3.跳转路由
    # return redirect('/login')

    # 4.返回数据转json返回,从flask中导入jsonify
    # data = {"name": "jeff", "age": "18"}
    # return jsonify(data)
    pass


@app.route("/login")
def login():
    return "我是login页面"


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

Three, flask profile

'''
四种配置flask方法配置
1.直接给app对象赋值属性
2.以字典的形式,给flask配置文件做配置
3.以文件的形式给flask做配置(django就是这种)
4.以类的形式,给flask做配置(推荐使用)
'''


from flask import Flask

app = Flask(__name__)

# 方式1(不推荐),因为只能配置两项。debug和secret_key
# app.debug = True  # 默认false,自动重启

# 方式2 字典的形式
# app.config["DEBUG"] = True


# 方式3 以文件的形式,在from_pyfile里传递路径
# app.config.from_pyfile("settings.py")


# 方式4 以类的形式,一个文件多个套配置,减少测试与更改(推荐使用)
# app.config.from_object("setobj.settings")

@app.route("/")
def index():
    return "json 是炮王"


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

Three ways profiles:

Similarly, like Django, a special configuration file

DEBUG = True

Four ways configuration class:

Advantages: a file, multiple sets of configuration. Different classes of different configurations, the configuration reduces the item to be changed on-line test

class settings():
    DEBUG = True

You can configure properties

flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
'''
 default_config = ImmutableDict(
        {
            "ENV": None,
            "DEBUG": None,
            "TESTING": False,
            "PROPAGATE_EXCEPTIONS": None,
            "PRESERVE_CONTEXT_ON_EXCEPTION": None,
            "SECRET_KEY": None,
            "PERMANENT_SESSION_LIFETIME": timedelta(days=31),
            "USE_X_SENDFILE": False,
            "SERVER_NAME": None,
            "APPLICATION_ROOT": "/",
            "SESSION_COOKIE_NAME": "session",
            "SESSION_COOKIE_DOMAIN": None,
            "SESSION_COOKIE_PATH": None,
            "SESSION_COOKIE_HTTPONLY": True,
            "SESSION_COOKIE_SECURE": False,
            "SESSION_COOKIE_SAMESITE": None,
            "SESSION_REFRESH_EACH_REQUEST": True,
            "MAX_CONTENT_LENGTH": None,
            "SEND_FILE_MAX_AGE_DEFAULT": timedelta(hours=12),
            "TRAP_BAD_REQUEST_ERRORS": None,
            "TRAP_HTTP_EXCEPTIONS": False,
            "EXPLAIN_TEMPLATE_LOADING": False,
            "PREFERRED_URL_SCHEME": "http",
            "JSON_AS_ASCII": True,
            "JSON_SORT_KEYS": True,
            "JSONIFY_PRETTYPRINT_REGULAR": False,
            "JSONIFY_MIMETYPE": "application/json",
            "TEMPLATES_AUTO_RELOAD": None,
            "MAX_COOKIE_SIZE": 4093,
        }
    )
'''

Four, flask route

4.1 source code analysis

# 源码分析:
'''
self.add_url_rule(rule, endpoint, f, **options)


def add_url_rule(
        self,  # app对象
        rule,  # url路由
        endpoint=None,  # 路由别名
        view_func=None,  # 响应的函数名
        provide_automatic_options=None,
        **options
    ):

methods :['POST','GET'] —》控制请求方法,不传默认只能GET方法
'''

# @app.route的本质就在执行add_url_rule
        # rule是路由,endpoint是路由别名,view_func是响应函数
        # 如果endpoint不传就是响应的函数名

4.2 1: surnamed

from flask import Flask , url_for, redirect

app = Flask(__name__)


def index():
    print()
    return "我是index"

# @app.route('/detail/<int:nid>',methods=['GET','POST'],endpoint='detail')  # 典型写法
@app.route('/login')
def login():
    print(url_for("index1"))   # 走的别名,如果别名没有写,默认函数名
    return redirect(url_for("index1")) # 走的别名,如果别名没有写,默认函数名

# url_for:
    # 用endpoint获取路由要用url_for 在flask中导入,也就是反向解析

# 路由
app.add_url_rule('/', endpoint='index1', view_func=index)

# endpoint 别名
# view_func 响应的函数名


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

4.3 2: famous grouping

from flask import Flask , url_for, redirect

app = Flask(__name__)

# 必须接收分组名字一样的  nid
def index(nid):
    print(nid)
    return "我是index"

# 路由:有名分组
app.add_url_rule('/index/<string:nid>', endpoint='index1', view_func=index, methods=['POST','GET'])

app.add_url_rule('/index/<int:nid>', endpoint='index', view_func=index, methods=['POST','GET'])

# 浏览器:http://127.0.0.1:5000/index/asdfas
# string、int 规定接收的类型


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

4.4 Routing small summary

 总结:
 1 @app.route("/login") 的本质app.add_url_rule("/login",view_func=login),所以我们就可以用这两个方式来添加路由
 2 路由的参数,
    2.1 endpoint,做是反向解析,如果上面添加路由的时候,没有传递endpoint就是使用响应函数的函数名,反向解析用url_for(),做解析,这个url_for必须在flask里面导入
    2.2 methods=["POST","GET"],该参数控制路由允许哪些请求方法访问,如果不传,默认只能GET方法
    2.3 路由以及路由路由转化器。"/index/<int:nid>",<参数的类型:用哪个变量来接收>,响应函数中的形参的名字必须转化器中一致。

4.5 default converter

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

4.6 custom converters

#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__)
# 1.写类
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
# 2.注册:添加到flask中
app.url_map.converters['regex'] = RegexConverter
# 正则匹配处理结果,要交给to_python,to_python函数可以对匹配处理结果做处理
# 3.使用:
@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'

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

4.7 custom converters summary

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,进行处理。处理以后,在拼接到路由。

Five, flask template rendering

py file:

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()

1. loop variable

<!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() %}
   <tr>
       <td>{{ k }}</td>
       <td>{{ v.name }}</td>
       <td>{{ v['name'] }}</td>
       <td>{{ v.get('name') }}</td>
       <td>{{url_for("index")}}</td>
   </tr>
{% endfor %}
</body>
</html>

2. Analyzing logic

<!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>

3. The execution of the function, pass parameters

django than the brackets can be performed function, transmission parameters

from flask import Flask,render_template,Markup
app = Flask(__name__)
app.debug = True



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",ht1 = func1,ht="<h1>饼哥正帅</h1>")



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

html file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{ ht|safe}}
{{ht1("jaosn","tank")}}  // 传参数
</body>
</html>

Six, flask request and response

from flask import Flask, request, make_response

app = Flask(__name__)
app.debug = True


@app.route('/', methods=['POST', 'GET'])
def index():
    # print('请求方法',request.method)  # 请求方法
    # print('get请求的参数',request.args)  # get 请求的参数
    # print('post请求的参数',request.form)  # post请求的参数
    # print('请求的cookies',request.cookies)  # 请求的cookies
    # print('post与get的所有参数',request.values)  # post与get的所有参数

    # 响应头,添加make_response
    response = make_response('ok')
    #response = make_response(render_template("login.html"))
    # 设置cookie
    response.set_cookie("key","val")
    return 'OK'


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

Request relevant information

 请求相关的信息
    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

Seven, set cookies

from flask import Flask, make_response

app = Flask(__name__)
app.debug = True


@app.route('/', methods=['POST', 'GET'])
def index():
    # 响应头,添加make_response
    response = make_response('ok')
    
    # 设置cookies
    response.set_cookie('key', 'val')  
    
    # 删除cookies
    response.delete_cookie("key")
    
    # 设置响应头
    response.headers["x-somexx"] = "A SB"
    
    return response


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

Set the cookie parameters

key, 键
value='', 值
max_age=None, 超时时间 cookie需要延续的时间(以秒为单位)如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止

expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
                   
path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
                   
domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
                   
secure=False, 浏览器将通过HTTPS来回传cookie
                   
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

Eight, flask of session

cookie: the key is stored in the client
session: stored in the client's key-value pair
token: stored in the client to check through the algorithm

8.1 Setting session (using Version)

You must now set about using the session key before

app.secret_key="asdas" # 值随便
# app.config['SECRET_KEY'] = os.urandom(24) # 配置session使用的秘钥
设置:session['username'] = 'xxx'
# 在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
# 在flask中他没有数据库,但session是怎样实现的?
    # 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
    # 我们通过app.session_interface来查看
    
删除:session.pop('username', None)

Flask session object provides storage for the cookie encryption, session data is encrypted signed by the secret key data.

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24) # 配置session使用的秘钥

@app.route('/')
def set_session_info():
    session['username'] = 'mark' # 使用用户信息配置sesion信息作为cookie,并添加到响应体中
    
    return '设置session信息'

session object like a dictionary can operate, the internal dictionary is to encrypt the information is then added to the appropriate operation of the body as a Cookie, when the response is automatically returned to the browser.

 session['username'] = 'mark'
 session['userphone'] = '123456'  # 可以指定多条session信息,统一放到响应的cookie中返回给浏览器

8.2 Setting session (analysis version)

from flask import Flask,session

app = Flask(__name__)
# 要用session,必须app配置一个密钥
app.secret_key  =  "asdasdihasdiuh"

# 设置session的名字,默认配置文件中为:session
app.config['SESSION_COOKIE_NAME']="python13session" 

# app.session_interface

#app.session_interface实现了两个方法,一个叫save_session,一个open_session,
# save_session 存session执行,加密设置cookies
# open_session 取session执行,解密大字典,拿到session
@app.route("/",)
def index():
    #如何设置sessoion
    # 1 导入session
    # 2 给sessoion设置值
    session['name'] = "egon"
    return "ok"

@app.route("/login")
def login():
    print(session["name"])
    return "login"

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

8.3 Setting the session is valid

后端Flask跟浏览器交互默认情况下,session cookie会在用户关闭浏览器时清除。通过将session.permanent属性设为True可以将session的有效期延长为31天,也可以通过操作app的配置PERMANENT_SESSION_LIFETIME来设置session过期时间。

案例 3.3.2.1:开启指定session过期时间模式

from flask import Flask, session
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)


@app.route('/')
def set_session_info():
    session['username'] = 'mark'
    session['userphone'] = '123456'
    session.permanent = True # 开启设置有效期,默认为31天后过期
    return 'Hello World!'
...

Set custom expiration

# 通过设置PERMANENT_SESSION_LIFETIME指定具体的过期时间

from datetime import timedelta
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1) # 设置为1小时候过期

8.4 acquire sessoin

Flask gets set in the session information obtained through the session object, the object inherits the session dictionary class, so when the acquisition value of the dictionary is the way. Its internal browser will pass over the session decrypt the message.

@app.route('/get_session/')
def get_session():
    username = session.get('username')
    userphone = session.get('userphone')
    if username or userphone:
        return "{},{}".format(username, userphone)
    return "session为空"

1550930691065

8.5 Delete session

sessionObject calls pop()according to specific sessionremoved the specified session information key.

session object calls clear()can clear all this browser session request information about this domain name

@app.route('/del_session/')
def del_session():
    session.pop('username')
    # session.clear()
    return '删除成功'

8.6 source code analysis

session-source implementation process

-save_seesion
    -响应的时候,把session中的值加密序列化放大到了cookie中,返回到浏览器中
-open_session
    -请求来了,从cookie中取出值,反解,生成session对象,以后再视图函数中直接用sessoin就可以了。

Source code analysis

# app.session_interface  点进去

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,
        )

Nine, flash

9.1 What is flash?

1554289488442

-设置:flash('aaa')
-取值:get_flashed_message()
-
-假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
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()

Guess you like

Origin www.cnblogs.com/guyouyin123/p/12521976.html