Flask

Flask是一个基于python依赖jinjia2模板和Werkzeug WSGI 服务的一个微型框架.  werkzeug和Django中的wsgiref模块一样其本质就是一个socket服务端,,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

Werkzeug 并不是 一个框架,它是一个 WSGI 工具集的库,你可以通过它来创建你自己的框架或 Web 应用

Flask 的特点: 短小精悍,易于扩展第三方组件丰富.

Flask是一个微框架,

微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。

默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。

flask和djano的区别?

djano大而全,无socket,借助第三方模块wsgiref模块,内部提供: ORM admin 中间件,Form,ModelForm,session,缓存,信号CSRF
Flask ,短小精悍,易于扩展,无socket,借助第三方库Werkzeug.第三方组件丰富

Flask的简单应用

#一个基于werkzeug库的Wsgi应用应该是这样的
from werkzeug.wrappers import Request,Response
from werkzeug.serving import run_simple

@Request.application
def hello(request):
    return Response('Hello,werkzeug')

if __name__ == '__main__':
    run_simple('localhost',4000,hello)

 Flask就是基于werkzeug来开发应用程序的

#简单的Flask应用 hello
from flask import Flask#导入Flask类
app=Flask(__name__)#实例化一个对象,这个对象就是我们的W基于WSGI的应用程序,括号里的参数是给对象起的名字,随便一个字符串就可以,__name__表示的是模块名字的字符串
@app.route('/index') #router函数把url和视图函数捆绑起来
def index():
    return 'Hello Flask'

if __name__ == '__main__':
    print(type(__name__))
    app.run(debug=True)#相当于run_simple('localhost',5000,index),

调式模式

虽然 run() 方法适用于启动本地的开发服务器,但是你每次修改代码后都要手动重启它。这样并不够优雅,

有两种方法来改变这个弊端

方法一: 直接在应用对象上设置

if __name__ == '__main__':
    app.debug=True
    app.run()#相当于run_simple('localhost',5000,index),

方法二: 在run函数中设置

app.run(debug=True)

配置文件

 flask中的配置文件是一个flask.config.Config对象(继承字典)

 flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
 2     {
 3         'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
 4         'TESTING':                              False,                          是否开启测试模式
 5         'PROPAGATE_EXCEPTIONS':                 None,                          
 6         'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
 7         'SECRET_KEY':                           None,
 8         'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
 9         'USE_X_SENDFILE':                       False,
10         'LOGGER_NAME':                          None,
11         'LOGGER_HANDLER_POLICY':               'always',
12         'SERVER_NAME':                          None,
13         'APPLICATION_ROOT':                     None,
14         'SESSION_COOKIE_NAME':                  'session',
15         'SESSION_COOKIE_DOMAIN':                None,
16         'SESSION_COOKIE_PATH':                  None,
17         'SESSION_COOKIE_HTTPONLY':              True,
18         'SESSION_COOKIE_SECURE':                False,
19         'SESSION_REFRESH_EACH_REQUEST':         True,
20         'MAX_CONTENT_LENGTH':                   None,
21         'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
22         'TRAP_BAD_REQUEST_ERRORS':              False,
23         'TRAP_HTTP_EXCEPTIONS':                 False,
24         'EXPLAIN_TEMPLATE_LOADING':             False,
25         'PREFERRED_URL_SCHEME':                 'http',
26         'JSON_AS_ASCII':                        True,
27         'JSON_SORT_KEYS':                       True,
28         'JSONIFY_PRETTYPRINT_REGULAR':          True,
29         'JSONIFY_MIMETYPE':                     'application/json',
30         'TEMPLATES_AUTO_RELOAD':                None,
31     }
View Code

如果我们要更改配置文件的话用这种方法

settings.py

class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'

class ProductionConfig(Config):
    """
    生产环境
    """
    DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
    """
    开发环境
    """
    DEBUG = True

class TestingConfig(Config):
    """
    测试环境
    """
    TESTING = True

#PS: 从sys.path中已经存在路径开始写


#PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
seetings.py

flask_demo.py

from flask import Flask
app=Flask(__name__)
app.config.from_object('seetings.DevelopmentConfig') #直接导入配置文件中的类就可以了
@app.route('/index')
def index():
    return 'Hello Flask'

if __name__ == '__main__':
    print(type(__name__))
    app.run()
flask_demo

路由

route() 装饰器把一个函数绑定到对应的 URL 上。

添加路由的两种方式:

# 路由方式一(*):装饰器
            @app.route('/index',methods=['GET','POST']) #当有post提交时
            def index():
                return "Index"
#路由方式二 路由方式一种的装饰器也是用的这种方法
    def order():
    return 'Order'
app.add_url_rule('/order',view_func=order)#view_func绑定那个函数

给url传参数:

要给 URL 传参数,你可以把这些特殊的字段标记为 <variable_name> , 这个部分将会作为命名参数传递到你的函数。

格式为: <转换器:参数名称>  转换器(其实就是要求参数的格式类型)。

from flask import Flask
app=Flask(__name__)
@app.route('/index/<int:id>/') #参数id要求为int类型
def index(id):#别忘记传参
    return 'Hello Flask%s'%(id)

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

转换器有下面几种:

@app.route('/user/<username>')   #常用的   不加参数的时候默认是字符串形式的
@app.route('/post/<int:post_id>')  #常用的   #指定int,说明是整型的
@app.route('/post/<float:post_id>') #浮点
                                                                       @app.route(
'/post/<path:path>') #路径,可以拼接路径 @app.route('/login', methods=['GET', 'POST'])

常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:

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

 

router中的url一个/和两个/的区别?

唯一 URL / 重定向行为
Flask 的 URL 规则基于 Werkzeug 的路由模块。这个模块背后的思想是基于 Apache 以及更早的 HTTP 服务器主张的先例,保证优雅且唯一的 URL。

以这两个规则为例:

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'
虽然它们看起来着实相似,但它们结尾斜线的使用在 URL 定义 中不同。 第一种情况中,指向 projects 的规范 URL 尾端有一个斜线。这种感觉很像在文件系统中的文件夹。
访问一个结尾不带斜线的 URL 会被 Flask 重定向到带斜线的规范 URL 去。 然而,第二种情况的 URL 结尾不带斜线,类似 UNIX
-like 系统下的文件的路径名。访问结尾带斜线的 URL 会产生一个 404 “Not Found” 错误。 这个行为使得在遗忘尾斜线时,允许关联的 URL 接任工作,与 Apache 和其它的服务器的行为并无二异。此外,也保证了 URL 的唯一,有助于避免搜索引擎索引同一个页面两次。

 构造url(反向解析)

 当视图函数中用到了url,不管url怎么变化,视图中的url都会反向解析到正确的url

注意:endpoint不写,别名默认视图函数名字

from flask import Flask,url_for#反向解析需要导入url_for 相当于Django中的reverse
app=Flask(__name__)
@app.route('/aa/',endpoint='index') #endpoint相当于django中的name,主要是起别名的作用
def index():
    v=url_for('login')#反向解析
    print(v)#打印
    return '这是index页面'

@app.route('/login/',endpoint='login')
def login():
    return '这是登录页面'


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

结果:

/login/

自定义正则转换器

当工作中遇到url中传递正则表达式的情况,我们可以自定义正则表达式转换器

from flask import Flask ,render_template,redirect,url_for
from werkzeug.routing import BaseConverter #自定义正则表达式就要继承BaseConverter这个类

app=Flask(__name__)
class RegexConverter(BaseConverter):
    '''
    自定义url匹配正则表达式转换器
    '''
    def __init__(self,map,regex):
        super(RegexConverter,self).__init__(map)
        self.regex=regex
    def to_python(self, value):
        '''
        路由匹配时,匹配成功后传递给视图函数中的参数值
        :param value:
        :return:
        '''
        return int(value)
    def to_url(self, value):
        '''
        使用url_for反向生成url时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        :param value:
        :return:
        '''
        val=super(RegexConverter, self).to_url(value)
        return val

#先要把你写的正则转换器添加到Flask的转换器中 app.url_map.converters['regs']=RegexConverter
@app.route(
'/index/<regs("\d+"):nid>',methods=['GET','POST']) #使用自定义的转换器 def index(nid): print(nid,type(nid)) v=url_for("index",nid=555)#相当于/index/555 print(v) return "这是Index页面" if __name__ == '__main__':

重定向

当需要重定向时.可以用rediret_to参数

from flask import Flask,render_template,redirect
                app = Flask(__name__)

                @app.route('/index',methods=['GET','POST'],redirect_to='/new')
                def index():
                    return "老功能"

                @app.route('/new',methods=['GET','POST'])
                def new():
                    return '新功能'


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

 获取子域名

首先我们要知道:域名是由子域名和顶级域名构成的.

一级域名:又叫顶级域名,一串字符串中间一个点隔开,例如baidu.com,这里说明一下,www.baidu.com不是一级域名!!而是二级域名!

二级域名:实际上就是一个一级域名以下的主机名,一串字符串中间两个“.”隔开,例如pan.baidu.com("pan"就是主机名)。

三级域名:二级域名的子域名,特征是包含三个“.”,一般来说三级域名都是免费的。

#这是顶级域名
https://baidu.com/
#这是顶级域名的子域名
https://www.baidu.com/
https://pan.baidu.com
from flask import Flask,url_for#反向解析需要导入url_for 相当于Django中的reverse
app=Flask(__name__)
@app.route('/aa/',subdomain="admin")
def index():
    v=url_for('login')#反向解析
    print(v)
    return '这是index页面'

@app.router中的参数

 

@app.route和app.add_url_rule参数:
            rule,                       URL规则
            view_func,                  视图函数名称
            defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
            endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
            methods=None,               允许的请求方式,如:["GET","POST"]
            

            strict_slashes=None,        对URL最后的 / 符号是否严格要求,
                                        如:
                                            @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>')
                                            或
                                            def func(adapter, nid):
                                                return "/home/888"
                                            @app.route('/index/<int:nid>', redirect_to=func)

            subdomain=None,             子域名访问
                                                from flask import Flask, views, url_for

                                                app = Flask(import_name=__name__)
                                                app.config['SERVER_NAME'] = 'haiyan.com:5000'


                                                @app.route("/", subdomain="admin")
                                                def static_index():
                                                    """Flask supports static subdomains
                                                    This is available at static.your-domain.tld"""
                                                    return "admin.xxx.com"

                            #动态生成
                                                @app.route("/dynamic", subdomain="<username>")
                                                def username_index(username):
                                                    """Dynamic subdomains are also supported
                                                    Try going to user1.your-domain.tld/dynamic"""
                                                    return username + ".your-domain.tld"


                                                if __name__ == '__main__':
                                                    app.run()
@app.route和app.add_url_rule参数

视图函数中添加装饰器

其实Flask我们用的最多的就是FBV,CBV用的很少,

这里简单介绍下CBV

from flask import Flask, url_for,views

app = Flask(__name__)


def wapper(func):

    def inner(*args,**kwargs):
        print('before')
        return func(*args,**kwargs)
    return inner


class IndexView(views.MethodView):
    methods = ['GET']
    decorators = [wapper, ]

    def get(self):
        return 'Index.GET'

    def post(self):
        return 'Index.POST'

app.add_url_rule('/index', view_func=IndexView.as_view(name='index2'))  # name=endpoint
if __name__ == '__main__':
    app.run(debug=True)

我们介绍FBV模式

当我们在Flask中的视图中添加装饰器时.我们要添加的装饰器和路由装饰器会出现冲突,这时候应该办

首先我们要确定的路由装饰器一定要先放到我们的装饰器的上边,因为它要先执行,才能再执行我们的装饰器,

当我们有多个视图函数需要装饰时候,比如这样

from flask import Flask#导入Flask类
app=Flask(__name__)
def wrapper(f):
    def inner(*args,**kwargs):
        print('before')
        return f()
    return inner
@app.route('/index1') 
@wrapper
def index():
    return 'Hello Flask'

@app.route('/login') 
@wrapper
def login():
    return 'Hello Flask'
if __name__ == '__main__':
    print(type(__name__))
    app.run(debug=True)

 

这时候就会出现错误

ssertionError: View function mapping is overwriting an existing endpoint function: inner

因为 endpoint默认反向生成函数名,然而,被装饰的函数的真正的函数名都是inner,所以endpoint这时候就出错了,这时候我们就需要真正的函数名,于是就用到了wraps装饰器修复

from flask import Flask
from functools import wraps  #导入wraps
app=Flask(__name__)
def wrapper(f):
    @wraps(f)
    def inner(*args,**kwargs):
        print('before')
        return f()
    return inner
@app.route('/index1')
@wrapper
def index():
    return 'Hello Flask'

@app.route('/login')
@wrapper
def login():
    return 'Hello Flask'
if __name__ == '__main__':
    print(type(__name__))
    app.run(debug=True)
加wraps后

HTTP方法

HTTP有许多访问url的方法,在默认情况下,只支持GET方法,但是,可以定义router中的参数来实现多种HTTP方法

比如当时post请求的时候

@app.route('/login',methods=['GET','POST']) #这里的括号里就要有method参数了

请求对象(request)和响应对象

首先我们应该知道,djano中的请求数据是通过参数request传递给视图函数的,但是在Flask不是通过参数传递进来的,而是通过上下文管理

首先从 flask 模块里导入它:

from flask import request

当前请求的 HTTP 方法可通过 method 属性来访问。通过:attr:~flask.request.form 属性来访问表单数据( POST 或 PUT 请求提交的数据)。

当访问form表单数据(POST提交)时

request.form.get()

注意:不存在时会报错,要捕获keyvalue异常

当访问url参数(get提交时)

request.args.get()

注意:不存在时会报错,要捕获keyvalue异常

请求相关的方法

 

 请求相关信息
        # request.method    请求方法
        # request.args      当get请求
        # request.form      当post请求时
        # request.values
        # request.cookies
        # request.headers
        # request.path
        # request.full_path
        # request.script_root
        # request.url
        # request.base_url
        # request.url_root
        # request.host_url
        # request.host
        # 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 json.dumps() #返回json数据,和他一样的就是jsonify()
    

设置响应头和cookie

  #####如何设置响应头和cookie*******
        response = make_response(render_template('index.html') ) #生成对象
        #response是flask.wrappers.Response类型
        response.set_cookie('key', 'value')  #设置cookie
        response.delete_cookie('key')   #删除cookie
         
        response.headers['X-Something'] = 'A value'  #设置响应头
        return response   #返回respon对象

补充

from urllib.parse import urlencode,quote,unquote

val = "%E6%8A%8A%E5%87%A0%E4%B8%AA"
print(unquote(val))   #ba上面这样的数据转换成中文
vall='我是中国人'
print(quote(vall))
vdd={"name":'小红'}
print(urlencode(vdd))

模板引擎

大多数和djano的模板渲染差不多

首先要建立一个名为templates的文件在根目录下,文件夹中放html

from flask import Flask,template_rendered
app=Flask(__name__)
@app.route('/xxx') 
def xxx():
    return template_rendered('/index.html',msg='fdsfd')

if __name__ == '__main__':
    print(type(__name__))
    app.run(debug=True)#相当于run_simple('localhost',5000,index),

1、为了防止xss攻击,加了验证,所以页面上显示字符串的形式,解决办法,有两种方式

  - 方法一在后端Markup

 v5 = Markup("<input type='text' />")

  -方法二 在前端

  {{ v4|safe }}

2、自定义方法

复制代码
def test(a,b):
    return a+b

@app.route('/index')
def index():
    return render_template("index2.html",test=test)


index2.html
<h1>{{ test(1,2) }}</h1>
复制代码

3、写一个函数在所有的页面都使用

template_global和template_filter

复制代码
@app.template_global()
def sb(a1, a2):
    return a1 + a2


@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3
复制代码
调用方式:{{sb(1,2)}}  {{ 1|db(2,3)}}

4、模板继承:和django的一样。extents

5.后端传函数,前端使用模板语言的时候需要加括号然而djano不需要

def sb(a1, a2):
    content={
        'k1':lambda x:5
    }

    return render_template('index.html',**content)
#前端
{{k1()}}

 

模板其他问题参考django 

session

它允许你在不同请求间存储特定用户的信息。

Flask中的session和djano中的session是不同的,Flask中的session放到cookie中,它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名。这意味着用户可以查看你 Cookie 的内容,但却不能修改它,除非用户知道签名的密钥。

一个完整的范例

要求 登陆后把信息添加session中

flask.py

from flask import Flask,render_template,request,redirect,session
app=Flask(__name__)
app.secret_key='wefjldsaj' #先要进行密钥签名
USER_DICT={
    '1':{'name':'小明'},
    '2':{'name':'小红'},
    '3':{'name':'36'}
}#模拟一个数据库
@app.route('/login',methods=['GET','POST'])
def login():
    print('请求来了')
    if request.method=="POST":
        username=request.form.get('username')#从form表单中取数据
        password=request.form.get('password')
        #request.args #对应get从url中取数据
        if username=='alex' and password=="123":
            #登录成功后把用户信息放入session中
            session['user_info']=username
            return redirect('/index')
        else:
            return render_template('/login.html',msg="用户名和密码错误") #还可以这样传值return render_template('/login.html',**{'msg':"用户名和密码错误"})
    return render_template('/login.html')
@app.route('/index')
def index():
    """
    主页
    :return:
    """
    username=session.get('user_info')
    if not username:
        return redirect('/login')
    print(USER_DICT)
    return render_template('/index.html',user_dict=USER_DICT)
@app.route('/logout')
def logout():
    session.pop('user_info',None)
    return '已经退出'
if __name__ == '__main__':
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">  <!--IE浏览器最高渲染-->
    <meta name="viewport" content="width=device-width, initial-scale=1"> <!--为了确保适当的绘制和缩放-->
    <title>主页</title>
    <link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<ul>
    {% for k,v in user_dict.items() %}
    <li>{{v.name}}</li>
    {% endfor%}
</ul>
<script src="../jquery-3.2.1.min.js"></script>

</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">  <!--IE浏览器最高渲染-->
    <meta name="viewport" content="width=device-width, initial-scale=1"> <!--为了确保适当的绘制和缩放-->
    <title>用户登录</title>
    <link rel="stylesheet" href="../bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<h1>请登录</h1>
<form method="post">
    用户名:<input type="text" name="username">
    密码: <input type="password" name="password">{{msg}}
    <input type="submit" value="提交">
</form>
<script src="../jquery-3.2.1.min.js"></script>

</body>
</html>

 

 

from flask import Flask,url_for,session

app = Flask(__name__)
app.secret_key = "sdsfdgdgdgd"
app.config['SESSION_COOKIE_NAME'] = 'session_lvning'  #设置session的名字

@app.route('/index/')
def index(nid):
    #session本质上操作的是字典, session是否还有其他方法?与字典方法相同
    #session的原理:如果下一次访问的时候带着随机字符串,会把session里面对应的
    # 值拿到内存,假设session保存在数据库,每执行一次链接一次数据库,每次都要时时更新的话
    # 会非常损耗内存
    session["xxx"] = 123
    session["xxx2"] = 123
    session["xxx3"] = 123
    session["xxx4"] = 123
    del session["xxx2"]  #在这删除了,真正存储的时候是没有xxx2的
    return "ddsf"

if __name__ == '__main__':

 

消息闪现

一般一个用户操作完成后,我们要告诉用户操作的结果,用户看完后这个消息就没必要存在了,我们就可以删除它.

Flask的消息闪现系统就是提供了这个功能.也就是反馈

flask()它可以将要闪现的内容存储起来.

get_flashed_messages():它可以把储存的内容取出来显示,然后自动删掉.

本质:闪现是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。不仅把值取走,而且吧session里的东西去掉,可以用session直接写

from flask import Flask,flash,get_flashed_messages
app = Flask(__name__)
app.secret_key = 'asdfasdfasdf'
@app.route('/x1',methods=['GET','POST'])
def login():
    flash('我要上向龙',category='x1') #把内容放入flash中,category就是一个别名 
    return '视图函数x1'
@app.route('/x2',methods=['GET','POST'])
def index():
    data = get_flashed_messages(category_filter=['x1']) #取数据
    print(data)
    return "视图函数x2"

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

先执行一次/x1

执行两次/X2

结果

['我要上向龙']
[] #第二次就取不出值来了

用的场景: 阅后即焚

登录场景:

flash.py

rom flask import render_template, request, session, url_for, redirect, flash
 
@app.route('/')
def index():
    if 'user' in session:
        return render_template('hello.html', name=session['user'])
    else:
        return redirect(url_for('login'), 302)
 
@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        session['user'] = request.form['user']
        flash('Login successfully!')
        return redirect(url_for('index'))
    else:
        return '''
        <form name="login" action="/login" method="post">
            Username: <input type="text" name="user" />
        </form>

login.html

!doctype html>
<title>Hello Sample</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class="flash">
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
<div class="page">
    {% block body %}
    {% endblock %}
</div>

 全局装饰器

@app.before_request和@app.after_request

app.before_request和app.after_request相当于djano中的中间件函数process_request和process_response,服务于全局,

不同点:当before_request有返回值时.它会直接执行所有的after_request,而不是像djano中执行对应的after_request函数

from flask import Flask,session

app=Flask(__name__)
app.secret_key="dfsadsfds"
@app.route('/login')
def login():
    session['login_info']=123
    return '123'

@app.route('/index3')
def index():
    ret=session.pop('login_info')
    print('ret',ret)
    return '这是主页'

@app.before_request
def before():
    print('brefore')

@app.after_request
def after(response): #注意这里的参数和返回值
    print('after')
    return response

if __name__ == '__main__':
    app.run(debug=True)
    app.__call__
View Code

结果:

brefore
after

还有其他的一些全局装饰器

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, Request, render_template

app = Flask(__name__, template_folder='templates')
app.debug = True


@app.before_first_request
def before_first_request1():
    print('before_first_request1')


@app.before_first_request
def before_first_request2():
    print('before_first_request2')


@app.before_request
def before_request1():
    Request.nnn = 123
    print('before_request1')


@app.before_request
def before_request2():
    print('before_request2')


@app.after_request
def after_request1(response):
    print('before_request1', response)
    return response


@app.after_request
def after_request2(response):
    print('before_request2', response)
    return response


@app.errorhandler(404)
def page_not_found(error):
    return 'This page does not exist', 404


@app.template_global()
def sb(a1, a2):
    return a1 + a2


@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3


@app.route('/')
def hello_world():
    return render_template('hello.html')


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

中间件

这个中间件是发生在request形成之前,也就是在执行app.wsgi_app()之前添加一些操作,通过对象的__call__方法

没多大用处,一般我们用@app.before_request

from flask import Flask
from flask import session, request
app = Flask(__name__)
app.secret_key = 'asdfasdfasdf'

@app.route('/x2',methods=['GET','POST'])
def index():
    print('我是index')
    return "我是x2"


class Middleware(object):
    def __init__(self,old_wsgi_app):
        """
        服务端启动时,自动执行
        :param old_wsgi_app:
        """
        self.old_wsgi_app =old_wsgi_app

    def __call__(self, environ, start_response):
        """
        每次有用户请求道来时
        :param args:
        :param kwargs:
        :return:
        """
        print('before')#添加在形成request之前的操作

        obj = self.old_wsgi_app(environ, start_response)
        print('after') #添加在形成request之后的操作
        return obj

if __name__ == '__main__':
    app.wsgi_app = Middleware(app.wsgi_app)
    app.run()
    """
    执行app.run()时候
    1.先执行app.__call__,
    2.再调用app.wsgi_app(),因为我自己有wsgi_app属性,加括号执行我的__call__方法,然后就把老的app.wsgi_app传进来,这样我们就可以在老的app.wsgi_app执行前,和执行后做一些操作
"""
middleware

结果:

before
我是index
after

 蓝图blueprint

详情见flask组件中的数据库连接池

蓝图是什么?

第一个功能:如果代码很多要进行归类,blueprint就是对flask的目录结构进行划分(应用于小中型程序),使目录结构更清晰,

第二个功能:当一个py文件中有多个函数时,为了使url容易区分可以给url添加前缀.

第三个功能: 我们知道@app.before_rerequest对全局生效,然而蓝图可以让它只对某一个蓝图实例生效

我们为什么要用蓝图?

我们的应用经常会区分用户站点和管理员后台
两者虽然都在同一个应用中,但是风格迥异。把它们分成两个应用吧,总有些代码我们想重用;放在一起嘛,耦合度太高,代码不便于管理。所以Flask提供了蓝图(Blueprint)功能。
蓝图使用起来就像应用当中的子应用一样,可以有自己的模板,静态目录,有自己的视图函数和URL规则,蓝图之间互相不影响。但是它们又属于应用中,可以共享应用的配置。
对于大型应用来说,
我们可以通过添加蓝图来扩展应用功能,而不至于影响原来的程序。不过有一点要注意,目前Flask蓝图的注册是静态的,不支持可插拔。 转载于http:
//www.bjhee.com/flask-ad6.html

例子

首先这样创建目录

首先,manage.py文件是我们的启动文件

from blue_flask import app

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

admin.py文件中创建一个蓝图实例

from flask import Blueprint

ad=Blueprint('ad',__name__,url_prefix='/admin') #实例化一个蓝图对象,给url添加前缀

@ad.route('/ad1')
def ad1():
    return '这是ad1页面'
@ad.route('/ad2')
def ad2():
    return '这是ad2页面'

acount.py文件中我们再创建一个蓝图实例,并添加一个before_request装饰器

from flask import Blueprint

act=Blueprint('act',__name__) #实例化一个蓝图对象,里边的名字随便起,但是不要和url相同

@act.route('/acount')
def login():
    return '这是acount'
@act.before_request
def f ():
    print('我只对act蓝图实例有效')

__init__.py文件是我们的初始化文件,在这里我们导入蓝图,并注册蓝图

from flask import Flask
#创建一个app对象
app=Flask(__name__)

from blue_flask.views.admin import ad
from blue_flask.views.acount import act

#给新蓝图注册
app.register_blueprint(ad)
app.register_blueprint(act)

这样我们就可可以执行manage.py文件了,

在url中输入/acount,我们可以在前端看到"这是account",在后台打印出"我只对act蓝图实例有效"

当我们在url这样输入/admin/ad1,在前端会显示这是ad1页面,在后台不会打印出f装饰器的内容

 

转载于:https://www.cnblogs.com/sticker0726/p/8921794.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值