博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flask框架
阅读量:6655 次
发布时间:2019-06-25

本文共 18667 字,大约阅读时间需要 62 分钟。

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

 

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

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

pip3 install flask
from werkzeug.wrappers import Request, Response@Request.applicationdef hello(request):    return Response('Hello World!')if __name__ == '__main__':    from werkzeug.serving import run_simple    run_simple('localhost', 4000, hello)
werkzeug

一. 基本使用

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

二、配置文件

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目录

三、路由系统

  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @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,}
def auth(func):            def inner(*args, **kwargs):                print('before')                result = func(*args, **kwargs)                print('after')                return result        return inner        @app.route('/index.html',methods=['GET','POST'],endpoint='index')        @auth        def index():            return 'Index'        或                def index():            return "Index"        self.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])        or        app.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])        app.view_functions['index'] = index        或        def auth(func):            def inner(*args, **kwargs):                print('before')                result = func(*args, **kwargs)                print('after')                return result        return inner        class IndexView(views.View):            methods = ['GET']            decorators = [auth, ]            def dispatch_request(self):                print('Index')                return 'Index!'        app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint        或        class IndexView(views.MethodView):            methods = ['GET']            decorators = [auth, ]            def get(self):                return 'Index.GET'            def post(self):                return 'Index.POST'        app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint        @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/
', redirect_to='/home/
') 或 def func(adapter, nid): return "/home/888" @app.route('/index/
', redirect_to=func) subdomain=None, 子域名访问 from flask import Flask, views, url_for app = Flask(import_name=__name__) app.config['SERVER_NAME'] = 'wupeiqi.com:5000' @app.route("/", subdomain="admin") def static_index(): """Flask supports static subdomains This is available at static.your-domain.tld""" return "static.your-domain.tld" @app.route("/dynamic", subdomain="
") 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()
a.注册路由原理
from flask import Flask, views, 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):                    """                    路由匹配时,匹配成功后传递给视图函数中参数的值                    :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['regex'] = RegexConverter            @app.route('/index/
') def index(nid): print(url_for('index', nid='888')) return 'Index' if __name__ == '__main__': app.run()
b. 自定制正则路由匹配

四、模板

1、模板的使用

Flask使用的是Jinja2模板,所以其语法和Django无差别

2、自定义模板方法

Flask中自定义模板方法的方式和Bottle相似,创建一个函数并通过参数的形式传入render_template,如:

    

自定义函数

{
{ww()|safe}}
html
#!/usr/bin/env python# -*- coding:utf-8 -*-from flask import Flask,render_templateapp = Flask(__name__)  def wupeiqi():    return '

Wupeiqi

' @app.route('/login', methods=['GET', 'POST'])def login(): return render_template('login.html', ww=wupeiqi) app.run()
run.py

五、请求和响应

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        # request.args        # request.form        # 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')        # 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        return "内容"    if __name__ == '__main__':        app.run()
View Code

六、Session

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。

  • 设置:session['username'] = 'xxx'

  • 删除:session.pop('username', None)
from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) @app.route('/')def index():    if 'username' in session:        return 'Logged in as %s' % escape(session['username'])    return 'You are not logged in' @app.route('/login', methods=['GET', 'POST'])def login():    if request.method == 'POST':        session['username'] = request.form['username']        return redirect(url_for('index'))    return '''        

''' @app.route('/logout')def logout(): # remove the username from the session if it's there session.pop('username', None) return redirect(url_for('index')) # set the secret key. keep this really secret:app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

基本使用
pip3 install Flask-Session                run.py            from flask import Flask            from flask import session            from pro_flask.utils.session import MySessionInterface            app = Flask(__name__)            app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'            app.session_interface = MySessionInterface()            @app.route('/login.html', methods=['GET', "POST"])            def login():                print(session)                session['user1'] = 'alex'                session['user2'] = 'alex'                del session['user2']                return "内容"            if __name__ == '__main__':                app.run()        session.py            #!/usr/bin/env python            # -*- coding:utf-8 -*-            import uuid            import json            from flask.sessions import SessionInterface            from flask.sessions import SessionMixin            from itsdangerous import Signer, BadSignature, want_bytes            class MySession(dict, SessionMixin):                def __init__(self, initial=None, sid=None):                    self.sid = sid                    self.initial = initial                    super(MySession, self).__init__(initial or ())                def __setitem__(self, key, value):                    super(MySession, self).__setitem__(key, value)                def __getitem__(self, item):                    return super(MySession, self).__getitem__(item)                def __delitem__(self, key):                    super(MySession, self).__delitem__(key)            class MySessionInterface(SessionInterface):                session_class = MySession                container = {}                def __init__(self):                    import redis                    self.redis = redis.Redis()                def _generate_sid(self):                    return str(uuid.uuid4())                def _get_signer(self, app):                    if not app.secret_key:                        return None                    return Signer(app.secret_key, salt='flask-session',                                  key_derivation='hmac')                def open_session(self, app, request):                    """                    程序刚启动时执行,需要返回一个session对象                    """                    sid = request.cookies.get(app.session_cookie_name)                    if not sid:                        sid = self._generate_sid()                        return self.session_class(sid=sid)                    signer = self._get_signer(app)                    try:                        sid_as_bytes = signer.unsign(sid)                        sid = sid_as_bytes.decode()                    except BadSignature:                        sid = self._generate_sid()                        return self.session_class(sid=sid)                    # session保存在redis中                    # val = self.redis.get(sid)                    # session保存在内存中                    val = self.container.get(sid)                    if val is not None:                        try:                            data = json.loads(val)                            return self.session_class(data, sid=sid)                        except:                            return self.session_class(sid=sid)                    return self.session_class(sid=sid)                def save_session(self, app, session, response):                    """                    程序结束前执行,可以保存session中所有的值                    如:                        保存到resit                        写入到用户cookie                    """                    domain = self.get_cookie_domain(app)                    path = self.get_cookie_path(app)                    httponly = self.get_cookie_httponly(app)                    secure = self.get_cookie_secure(app)                    expires = self.get_expiration_time(app, session)                    val = json.dumps(dict(session))                    # session保存在redis中                    # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)                    # session保存在内存中                    self.container.setdefault(session.sid, val)                    session_id = self._get_signer(app).sign(want_bytes(session.sid))                    response.set_cookie(app.session_cookie_name, session_id,                                        expires=expires, httponly=httponly,                                        domain=domain, path=path, secure=secure)
自定义Session

七、蓝图

蓝图用于为应用提供目录划分:

小型应用程序:

大型应用程序:

其他:

  • 蓝图URL前缀:xxx = Blueprint('account', __name__,url_prefix='/xxx')
  • 蓝图子域名:xxx = Blueprint('account', __name__,subdomain='admin')
    # 前提需要给配置SERVER_NAME: app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
    # 访问时:admin.wupeiqi.com:5000/login.html

八、message

message是一个基于Session实现的用于保存数据的集合,其特点是:使用一次就删除。

from flask import Flask, flash, redirect, render_template, request, get_flashed_messages        app = Flask(__name__)        app.secret_key = 'some_secret'        @app.route('/')        def index1():            messages = get_flashed_messages()            print(messages)            return "Index1"        @app.route('/set')        def index2():            v = request.args.get('p')            flash(v)            return 'ok'        if __name__ == "__main__":            app.run()
View Code

九、中间件

from flask import Flask, flash, redirect, render_template, request app = Flask(__name__)app.secret_key = 'some_secret' @app.route('/')def index1():    return render_template('index.html') @app.route('/set')def index2():    v = request.args.get('p')    flash(v)    return 'ok' class MiddleWare:    def __init__(self,wsgi_app):        self.wsgi_app = wsgi_app     def __call__(self, *args, **kwargs):         return self.wsgi_app(*args, **kwargs) if __name__ == "__main__":    app.wsgi_app = MiddleWare(app.wsgi_app)    app.run(port=9999)
View Code

十、Flask插件

  • WTForms    
  • SQLAchemy
  • 等...    http://flask.pocoo.org/extensions/

 

 
 
 

转载于:https://www.cnblogs.com/bingabcd/p/7554524.html

你可能感兴趣的文章
shell脚本
查看>>
python 模块
查看>>
Flash Builder生成asdoc格式的帮助文档
查看>>
分享实录 | 第四范式程晓澄:机器学习在推荐系统中的应用
查看>>
测试服务器响应时间
查看>>
xm console无法联接guest问题的解决
查看>>
一步一步SharePoint 2007之一:安装SharePoint
查看>>
Server Develop (七) Linux 守护进程
查看>>
Android requires compiler compliance level 5.0. Please fix project properties.错误
查看>>
如何从两个List中筛选出相同的值
查看>>
android112 c代码打印日志,c反编译调用java
查看>>
C# 正则表达式学习
查看>>
py excel 文本化
查看>>
[LeetCode] Predict the Winner 预测赢家
查看>>
何恺明大神的「Focal Loss」,如何更好地理解?
查看>>
人工智能是好?是坏?还是高深莫测?
查看>>
11月9日云栖精选夜读:阿里90后工程师,如何用AI程序写出双11打call歌?
查看>>
Google X 的热气球终于派上用场了,为波多黎各提供 LTE 网络
查看>>
新华网与阿里合资创立云计算公司
查看>>
浅谈互联网医疗面临的挑战
查看>>