第十二篇 Flask 基础篇

Flask

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

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

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

 1 pip install flask 

from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

werkzeug
werkzeug

一 .基本使用

from flask import Flask
app = Flask(__name__)
 
@app.route('/')
def hello_world():
    return 'Hello World!'
 
if __name__ == '__main__':
    app.run()

二 .配置文件

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

# 配置文件
app.config.from_object("settings.DevelopmentConfig")


@app.route('/index',methods=['GET','POST'])
def index():

    return "index"

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

 setting.py(项目根目录下)

class BaseConfig(object):
    DEBUG = True
    SECRET_KEY = "asudflkjdfadjfakdf"


class ProductionConfig(BaseConfig):
    DEBUG = False


class DevelopmentConfig(BaseConfig):
    pass


class TestingConfig(BaseConfig):
    pass
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
    {
        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
        'TESTING':                              False,                          是否开启测试模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }
 
方式一:
    app.config['DEBUG'] = True
 
    PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
 
方式二:
    app.config.from_pyfile("python文件名称")
        如:
            settings.py
                DEBUG = True
 
            app.config.from_pyfile("settings.py")
 
    app.config.from_envvar("环境变量名称")
        环境变量的值为python文件名称名称,内部调用from_pyfile方法
 
 
    app.config.from_json("json文件名称")
        JSON文件名称,必须是json格式,因为内部会执行json.loads
 
    app.config.from_mapping({'DEBUG':True})
        字典格式
 
    app.config.from_object("python类或类的路径")
 
        app.config.from_object('pro_flask.settings.TestingConfig')
 
        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目录
配置文件-详解版

三 .路由系统

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

"""
1. 执行decorator=app.route('/index',methods=['GET','POST'])
2falsk基础知识与示例. @decorator
     - decorator(index)
"""
# 路由方式一(*):
@app.route('/index',methods=['GET','POST'])
def index():
    return "Index"

# 路由方式二:
def order():
    return 'Order'

app.add_url_rule('/order',view_func=order)


if __name__ == '__main__':
    app.run()
生成路由2种方式
from flask import Flask,render_template,redirect,url_for
app = Flask(__name__)


# endpoint 起别名,用于反向生成url
@app.route('/index',methods=['GET','POST'],endpoint='n1')
def index():
    v1 = url_for('n1')
    v2 = url_for('login')
    v3 = url_for('logout')
    print(v1,v2,v3)
    return "Index"

@app.route('/login',methods=['GET','POST'])
def login():
    return "login"

@app.route('/logout',methods=['GET','POST'])
def logout():
    return "logout"

if __name__ == '__main__':
    app.run()
endpoint(别名)
from flask import Flask,render_template,redirect,url_for
app = Flask(__name__)

@app.route('/index/<int:nid>',methods=['GET','POST'])
def index(nid):
    print(nid,type(nid))
    return "Index2"

if __name__ == '__main__':
    app.run()
路由匹配
from flask import Flask,render_template,redirect,url_for
from werkzeug.routing import 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

app.url_map.converters['xxx'] = RegexConverter

@app.route('/index/<xxx("d+"):nid>',methods=['GET','POST'])
def index(nid):
    print(nid,type(nid))
    v = url_for('index',nid=999) # /index/999
    print(v)
    return "Index"

if __name__ == '__main__':
    app.run()
自定义url正则匹配路由
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()
重定向
from flask import Flask,render_template,redirect

from gevent import pywsgi
app = Flask(__name__)
app.config['SERVER_NAME'] = 'hw.com:5000'


@app.route("/dynamic", subdomain="<username>")
def xxxxxxx(username):
    # 域名为:'www.oldboy.com:5000'
    print(username) # 获取子域名  输出:www
    return 'xxxxx'

@app.route('/index')
def x():
    print('x')
    return 'xxx'

if __name__ == '__main__':

    app.run('127.0.0.1',5000)
获取子域名
from flask import Flask,render_template,redirect
app = Flask(__name__)
import functools

def wapper(func):
    @functools.wraps(func) # 保留原函数信息
    def inner(*args,**kwargs):
        print('before')
        return func(*args,**kwargs)
    return inner



@app.route('/xxxx',methods=['GET','POST'])
@wapper
def index():
    return "Index"


@app.route('/order',methods=['GET','POST'])
@wapper
def order():
    return "order"

if __name__ == '__main__':
    app.run()
装饰器(functool使用)

四 .视图(cbv-fbv)

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

def wapper(func):
    @functools.wraps(func)
    def inner(*args,**kwargs):
        print('before')
        return func(*args,**kwargs)
    return inner

@app.route('/xxxx',methods=['GET','POST'])
@wapper
def index():
    return "Index"

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

    def dispatch_request(self):
        print('Index')
        return 'Index!'

app.add_url_rule('/index', view_func=IndexView.as_view(name='index1'))  # name=endpoint
"""

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

五 .请求与相应

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

@app.route('/index',methods=['GET','POST'])
def index():
    # 请求相关
    # request.method
    # request.args
    # request.form
    # request.cookies
    # request.headers
    # request.path
    # request.files
    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(obj.filename))

    # request.values
    # request.full_path
    # request.script_root
    # request.url
    # request.base_url
    # request.url_root
    # request.host_url
    # request.host



    # 响应相关
    return ""
    return json.dumps({}) # return jsonify({})
    return render_template('index.html',n1=123)
    return redirect('/index')


    # response = make_response(render_template('index.html'))
    # response = make_response("xxxx")
    # response.set_cookie('key', 'value')
    # response.headers['X-Something'] = 'A value'
    # response.delete_cookie('key')
    # return response




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

六 .模板

from flask import Flask,render_template,redirect,request,jsonify,make_response,Markup
app = Flask(__name__)

@app.template_global()
def sbbbbbbb(a1, a2):
    """
    每个模板中可以调用的函数
    :param a1:
    :param a2:
    :return:
    """
    return a1 + a2


def gen_input(value):
    # return "<input value='%s'/>" %value
    return Markup("<input value='%s'/>" %value)

@app.route('/x1',methods=['GET','POST'])
def index():
    context = {
        'k1':123,
        'k2': [11,22,33],
        'k3':{'name':'oldboy','age':84},
        'k4': lambda x: x+1,
        'k5': gen_input, # 当前模板才能调用的函数
    }

    return render_template('index.html',**context)


@app.route('/x2',methods=['GET','POST'])
def order():
    context = {
        'k1':123,
        'k2': [11,22,33],
    }

    return render_template('order.html',**context)




if __name__ == '__main__':
    app.run()
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
    <div >头部</div>
    <div>
        {% block content %} {% endblock %}
    </div>
    <div >底部</div>
</body>
</html>
layout.html
{% extends 'layout.html'%}

{% block content %}
    <h1>{{k1}}</h1>
    <h1>{{k2.0}}  {{k2[0]}} </h1>
    <h1>{{k3.name}}  {{k3['name']}}  {{k3.get('name',888)}}</h1>
    <h1>{{k4(66)}}</h1>
    <h1>{{k5(99)}}</h1>
    <h1>{{sbbbbbbb(1,2)}}</h1>
{% endblock%}
index.html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
    <h1>{{sbbbbbbb(1,2)}}</h1>
</body>
</html>
order.html

七 .session

"""
1. 请求刚刚达到
    ctx = RequestContext(...)
          - request
          - session=None
    ctx.push()
        ctx.session = SecureCookieSessionInterface.open_session

2falsk基础知识与示例. 视图函数

3flsak源码分析上下文管理. 请求结束
    SecureCookieSessionInterface.save_session()
"""
from flask import Flask,session
app = Flask(__name__)
app.secret_key = 'sadfasdfasdf'

@app.route('/x1')
def index():
    # 去ctx中获取session
    session['k1'] = 123
    session['k2'] = 123
    del session['k2']
    return "Index"


@app.route('/x2')
def order():
    print(session['k1'])
    return "Order"

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

    # 1. 请求一旦到来显
    app.__call__
    app.wsgi_app
    app.open_session

八 .特殊装饰器

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

"""
before_reuqest = [xxxxxxxxxx1,xxxxxxxxxx2]
"""
@app.before_request
def xxxxxxxxxx1():
    print('前1')

@app.before_request
def xxxxxxxxxx2():
    print('前2')
"""
after_request = [oooooooo1,oooooooo2]
[oooooooo2,oooooooo1,] reversed(after_request)
"""
@app.after_request
def oooooooo1(response):
    print('后1')
    return response

@app.after_request
def oooooooo2(response):
    print('后2')
    return response



@app.route('/x1',methods=['GET','POST'])
def x1():
    print('视图函数x1')
    return "视图函数x1"

@app.route('/x2',methods=['GET','POST'])
def x2():
    print('视图函数x2')
    return "视图函数x2"

if __name__ == '__main__':
    app.__call__
    app.run()
from flask import Flask,render_template,redirect
app = Flask(__name__)

@app.before_request
def xxxxxxxxxx1():
    print('前1')
    return "不要再来烦我了"

@app.before_request
def xxxxxxxxxx2():
    print('前2')

@app.after_request
def oooooooo1(response):
    print('后1')
    return response

@app.after_request
def oooooooo2(response):
    print('后2')
    return response



@app.route('/x1',methods=['GET','POST'])
def x1():
    print('视图函数x1')
    return "视图函数x1"

@app.route('/x2',methods=['GET','POST'])
def x2():
    print('视图函数x2')
    return "视图函数x2"

if __name__ == '__main__':
    app.__call__
    app.run()
s2.py
from flask import Flask,render_template,redirect,request,session
app = Flask(__name__)
app.secret_key = 'asdfasdfasdf'
@app.before_request
def check_login():
    if request.path == '/login':
        return None
    user = session.get('user_info')
    if not user:
        return redirect('/login')

@app.route('/login',methods=['GET','POST'])
def login():
    return "视图函数x1"

@app.route('/index',methods=['GET','POST'])
def index():
    print('视图函数x2')
    return "视图函数x2"

if __name__ == '__main__':
    app.run()
实践-登录验证

九 .闪现

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

@app.route('/x1',methods=['GET','POST'])
def login():
    flash('我要上向龙1',category='x1')
    flash('我要上向龙2',category='x2')
    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()

十.中间件

from flask import Flask
app = Flask(__name__)
app.secret_key = 'asdfasdfasdf'
Debug =True

@app.before_request
def xxxxxxxxxx1():
    print('前1')
@app.route('/x2',methods=['GET','POST'])
def 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')
        from flask import session,request
        obj = self.old_wsgi_app(environ, start_response)
        print('after')
        return obj

if __name__ == '__main__':
    app.wsgi_app = Middleware(app.wsgi_app)
    app.run()
    """
    1.执行app.__call__
    2falsk基础知识与示例.在调用app.wsgi_app方法
    """
View Code
from types import MethodType,FunctionType

class Foo(object):
    def fetch(self):
        pass

print(isinstance(Foo.fetch,MethodType))
print(isinstance(Foo.fetch,FunctionType)) # True

obj = Foo()
print(isinstance(obj.fetch,MethodType)) # True
print(isinstance(obj.fetch,FunctionType))
函数与方法判断

十一 .蓝图

蓝图示例
s8pro/s8pro
    _init_.py
        from flask import Flask
        from .views import account
        from .views import admin
        from .views import user

        app = Flask(__name__)

        app.register_blueprint(account.ac)
        app.register_blueprint(admin.ad)
        app.register_blueprint(user.us)

    .views
        -account.py
        -admin.py
        -user.py
mamage.py
    from s8pro import app
    if __name__ == '__main__':
        app.run()

附件:项目模板示例

1小型项目示例 (点击下载)(提取码:huaw)

1大型项目示例 (点击下载)

作者:华王 博客:https://www.cnblogs.com/huahuawang/
原文地址:https://www.cnblogs.com/huahuawang/p/14807641.html