微框架、简洁、只做他需要做的,给开发展提供了很大的扩展性。 Flask和相关的依赖(Jinja2、Werkzeug)设计得非常优秀,用起来很爽。 开发效率非常高,比如使用SQLAlchemy的ORM操作数据库可以节省开发者大量书写sql的时间。 社会活跃度非常高。 Flask的灵活度非常之高,他不会帮你做太多的决策,即使做已经帮你做出选择,你也能非常容易的更换成你需要的,比如: 使用Flask开发数据库的时候,具体是使用SQLAlchemy还是MongoEngine或者是不用ORM而直接基于MySQL-Python这样的底层驱动进行开发都是可以的,选择权完全掌握在你自己的手中。区别于Django,Django内置了非常完善和丰富的功能,并且如果你想替换成你自己想要的,要么不支持,要么非常麻烦。 把默认的Jinija2模板引擎替换成Mako引擎或者是其他模板引擎都是非常容易的。 第一个flask程序: 用pycharm新建一个flask项目,新建项目的截图如下: 点击create后创建一个新项目,然后在helloworld.py文件中书写代码: #coding: utf8 # 从flask框架中导入Flask类 from flask import Flask # 传入__name__初始化一个Flask实例 app = Flask(__name__) # app.route装饰器映射URL和执行的函数。这个设置将根URL映射到了hello_world函数上 @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': # 运行本项目,host=0.0.0.0可以让其他电脑也能访问到该网站,port指定访问的端口。默认的host是127.0.0.1,port为5000 app.run(host='0.0.0.0',port=9000) 然后点击运行,在浏览器中输入http://127.0.0.1:9000就能看到hello world了。需要说明一点的是,app.run这种方式只适合于开发,如果在生产环境中,应该使用Gunicorn或者uWSGI来启动。如果是在终端运行的,可以按ctrl+c来让服务停止。 设置为DEBUG模式: 默认情况下flask不会开启DEBUG模式,开启DEBUG模式后,flask会在每次保存代码的时候自动的重新载入代码,并且如果代码有错误,会在终端进行提示。 开启DEBUG模式有三种方式: 直接在应用对象上设置: app.debug = True app.run() 在执行run方法的时候,传递参数进去: app.run(debug=True) 在config属性中设置: app.config.update(DEBUG=True) 如果一切正常,会在终端打印以下信息: * Restarting with stat * Debugger is active! * Debugger pin code: 294-745-044 * Running on http://0.0.0.0:9000/ (Press CTRL+C to quit) 需要注意的是,只能在开发环境下开启DEBUG模式,因为DEBUG模式会带来非常大的安全隐患。 另外,在开启了DEBUG模式后,当程序有异常而进入错误堆栈模式,你第一次点击某个堆栈想查看变量值的时候,页面会弹出一个对话框,让你输入PIN值,这个PIN值在你启动的时候就会出现,比如在刚刚启动的项目中的PIN值为294-745-044,你输入这个值后,Werkzeug会把这个PIN值作为cookie的一部分保存起来,并在8小时候过期,8小时以内不需要再输入PIN值。这样做的目的是为了更加的安全,让调试模式下的攻击者更难攻击到本站。 项目配置: Flask项目的配置,都是通过app.config对象来进行配置的。比如要配置一个项目处于DEBUG模式下,那么可以使用app.config['DEBUG] = True来进行设置,那么Flask项目将以DEBUG模式运行。在Flask项目中,有四种方式进行项目的配置: 直接硬编码: app = Flask(__name__) app.config['DEBUG'] = True 因为app.config是flask.config.Config的实例,而Config类是继承自dict,因此可以通过update方法: app.config.update( DEBUG=True, SECRET_KEY='...' ) 如果你的配置项特别多,你可以把所有的配置项都放在一个模块中,然后通过加载模块的方式进行配置,假设有一个settings.py模块,专门用来存储配置项的,此时你可以通过app.config.from_object()方法进行加载,并且该方法既可以接收模块的的字符串名称,也可以模块对象: # 1. 通过模块字符串 app.config.from_object('settings') # 2. 通过模块对象 import settings app.config.from_object(settings) 也可以通过另外一个方法加载,该方法就是app.config.from_pyfile(),该方法传入一个文件名,通常是以.py结尾的文件,但也不限于只使用.py后缀的文件: app.config.from_pyfile('settings.py',silent=True) # silent=True表示如果配置文件不存在的时候不抛出异常,默认是为False,会抛出异常。 Flask项目内置了许多的配置项,所有的内置配置项,可以在这里查看。 URL与函数的映射: 从之前的helloworld.py文件中,我们已经看到,一个URL要与执行函数进行映射,使用的是@app.route装饰器。@app.route装饰器中,可以指定URL的规则来进行更加详细的映射,比如现在要映射一个文章详情的URL,文章详情的URL是/article/id/,id有可能为1、2、3...,那么可以通过以下方式: python @app.route('/article/ string: 默认的数据类型,接受没有任何斜杠“/”的文本。 int: 接受整形。 float: 接受浮点类型。 path: 和string的类似,但是接受斜杠。 uuid: 只接受uuid字符串。 any:可以指定多种路径,这个通过一个例子来进行说明: @app.route('/ def item(url_path): return url_path 以上例子中,item这个函数可以接受两个URL,一个是/article/,另一个是/blog/。并且,一定要传url_path参数,当然这个url_path的名称可以随便。 如果不想定制子路径来传递参数,也可以通过传统的?=的形式来传递参数,例如:/article?id=xxx,这种情况下,可以通过request.args.get('id')来获取id的值。如果是post方法,则可以通过request.form.get('id')来进行获取。 构造URL(url_for): 一般我们通过一个URL就可以执行到某一个函数。如果反过来,我们知道一个函数,怎么去获得这个URL呢?url_for函数就可以帮我们实现这个功能。url_for()函数接收两个及以上的参数,他接收函数名作为第一个参数,接收对应URL规则的命名参数,如果还出现其他的参数,则会添加到URL的后面作为查询参数。 通过构建URL的方式而选择直接在代码中拼URL的原因有两点: 将来如果修改了URL,但没有修改该URL对应的函数名,就不用到处去替换URL了。 url_for()函数会转义特殊字符和Unocode数据,这些工作都不需要我们自己处理。 下面用一个例子来进行解释: ```python from flask import Flask,url_for app = Flask(name) @app.route('/article/ def article(id): return '%s article detail' % id # 这行的代码可以在交互模式下产生请求上下文,不用`app.run()`来运行这个项目,直接可以运行下面的代码, # 也会有`flask`上下文 with app.test_request_context(): print url_for('article',id='1') print url_for('article',id='2',next='/') ``` 执行后的结果如下: > /article/1/ > /article/2/?next=%2F 自定义URL转换器: 刚刚在URL映射的时候,我们看到了Flask内置了几种数据类型的转换器,比如有int/string等。如果Flask内置的转换器不能满足你的需求,此时你可以自定义转换器。自定义转换器,需要满足以下几个条件: 转换器是一个类,且必须继承自werkzeug.routing.BaseConverter。 在转换器类中,必须实现to_python(self,value)方法,这个方法的返回值,将会传递到view函数中作为参数。 在转换器类中,必须实现to_url(self,values)方法,这个方法的返回值,将会在调用url_for函数的时候生成符合要求的URL形式。 比如,拿一个官方的例子来说,Reddit可以通过在URL中用一个加号(+)隔开社区的名字,方便同时查看来自多个社区的帖子。比如访问“www.reddit.com/r/flask+lisp/”的时候,就同时可以查看flask和lisp两个社区的帖子,现在我们自定义一个转换器来实现这个功能: #coding: utf8 from flask import Flask,url_for from werkzeug.routing import BaseConverter class ListConverter(BaseConverter): def __init__(self,url_map,separator='+'): super(ListConverter,self).__init__(url_map) self.separator = separator def to_python(self, value): return value.split(self.separator) def to_url(self, values): return self.separator.join(BaseConverter.to_url(self,value) for value in values) @app.route('/community1/ def community1(page_names): return '%s+%s' % tuple(page_names) @app.route('/community2/ def community2(page_names): return '%s|%s' % tuple(page_names) communityu1使用的是默认的+号进行连接,而第二种方式使用了|进行连接。 URL唯一: Flask的URL规则是基于Werkzeug的路由模块。这个模块的思想是基于Apache以及更早的HTTP服务器的主张,希望保证优雅且唯一的URL。 举个例子: @app.route('/projects/') def projects(): return 'project page' 上述例子中,当访问一个结尾不带斜线的URL会被重定向到带斜线的URL上去。这样有助于避免搜索引擎搜索同一个页面两次。 再看一个例子: @app.route('/about') def about(): return 'about page' 以上例子中,当访问带斜线的URL(/about/)会产生一个404('Not Found')错误。 指定HTTP方法: 在@app.route()中可以传入一个关键字参数methods来指定本方法支持的HTTP方法,默认只响应GET请求,看以下例子: python @app.route('/login/',methods=['GET','POST']) def login(): return 'login' 以上装饰器将让login的URL既能支持GET又能支持POST。 页面跳转和重定向: 重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面。 永久性重定向: http的状态码是301,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入www.jingdong.com的时候,会被重定向到www.jd.com,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向。 暂时性重定向: http的状态码是302,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。 在flask中,重定向是通过flask.redirect(location,code=302)这个函数来实现的,location表示需要重定向到的URL,应该配合之前讲的url_for()函数来使用,code表示采用哪个重定向,默认是302也即暂时性重定向,可以修改成301来实现永久性重定向。 以下来看一个例子,关于在flask中怎么使用重定向: from flask import Flask,url_for,redirect app = Flask(__name__) app.debug = True @app.route('/login/',methods=['GET','POST']) def login(): return 'login page' @app.route('/profile/',methods=['GET','POST']) def profile(): name = request.args.get('name') if not name: # 如果没有name,说明没有登录,重定向到登录页面 return redirect() else: return name 关于响应(Response): 视图函数的返回值会被自动转换为一个响应对象,Flask的转换逻辑如下: 如果返回的是一个合法的响应对象,则直接返回。 如果返回的是一个字符串,那么Flask会重新创建一个werkzeug.wrappers.Response对象,Response将该字符串作为主体,状态码为200,MIME类型为text/html,然后返回该Response对象。 如果返回的是一个元组,元祖中的数据类型是(response,status,headers),只能包含一个元素。status值会覆盖默认的200状态码,headers可以是一个列表或者字典,作为额外的消息头。 如果以上条件都不满足,Flask会假设返回值是一个合法的WSGIt应用程序,并通过Response.force_type(rv,request.environ)转换为一个请求对象。 以下将用例子来进行说明: 第一个例子:直接使用Response创建: from werkzeug.wrappers import Response @app.route('/about/') def about(): resp = Response(response='about page',status=200,content_type='text/html;charset=utf-8') return resp 第二个例子:可以使用make_response函数来创建Response对象,这个更加的方便,因为他封装了默认的Content-Type以及status等: from flask import make_response @app.route('/about/') def about(): return make_response('about page') 第三个例子:通过返回元组的形式: @app.errorhandler(404) def not_found(): return 'not found',404 第四个例子:自定义响应。自定义响应必须满足三个条件: 必须继承自Response类。 必须实现类方法force_type(cls,rv,environ=None)。 必须指定app.response_class为你自定义的Response 以下将用一个例子来进行讲解,Restful API都是通过JSON的形式进行传递,如果你的后台跟前台进行交互,所有的URL都是发送JSON数据,那么此时你可以自定义一个叫做JSONResponse的类来代替Flask自带的Response类: from flask import Flask,jsonify from werkzeug.wrappers import Response app = Flask(__name__) class JSONResponse(Response): default_mimetype = 'application/json' @classmethod def force_type(cls,response,environ=None): if isinstance(response,dict): response = jsonify(response) return super(JSONResponse,cls).force_type(response,environ) app.response_class = JSONResponse @app.route('/about/') def about(): return {'message':'about page'} if __name__ == '__main__': app.run(host='0.0.0.0',port=8000) 此时如果你访问/about/这个URL,那么在页面中将会显示: { 'message': 'about page' } |
|
来自: 石头p4g54puvpz > 《flask》