http://flask.pocoo.org/Flask是一个Python编写的Web微框架,让我们可以使用Python语言快速实现一个网 站或Web服务。本文参考自http://flask.pocoo.org/docs/0.12/Flask官方文档,大部分代码引用自官 方文档。安装Flask首先我们来安装Flask。最简单的办法就是使用pip。pipinstallflask1然后打开一个Pyt hon文件,输入下面的内容并运行该文件。然后访问localhost:5000,我们应当可以看到浏览器上输出了HelloFlask !。fromflaskimportFlaskapp=Flask(__name__)@app.route(''/'')def hello_world():return''HelloFlask!''if__name__==''__main__'':ap p.run()12345678910111213快速开始调试模式我们修改代码中的输出,然后查看浏览器上是否有变化。如果你照做的话, 可以看到什么变化都没有。其实Flask内置了调试模式,可以自动重载代码并显示调试信息。这需要我们开启调试模式,方法很简单,设置FL ASK_DEBUG环境变量,并将值设置为1。然后再次运行程序,会看到有这样的输出。这时候如果再次修改代码,会发现这次Flask会自 动重启。RestartingwithstatDebuggerisactive!DebuggerPIN: 157-063-180Runningonhttp://127.0.0.1:5000/(PressCTRL+Cto quit)1234路由在上面的例子里可以看到路由的使用。如果了解SpringWebMVC的话,应该对路由很熟悉。路由通过使用 Flask的app.route装饰器来设置,这类似Java的注解。@app.route(''/'')defindex():retu rn''IndexPage''@app.route(''/hello'')defhello():return''Hello,Wo rld''1234567路径变量如果希望获取/article/1这样的路径参数,就需要使用路径变量。路径变量的语法是/path/onverter:varname>。在路径变量前还可以使用可选的转换器,有以下几种转换器。转换器作用string默认选项,接受除了 斜杠之外的字符串int接受整数float接受浮点数path和string类似,不过可以接受带斜杠的字符串any匹配任何一种转换器u uid接受UUID字符串下面是Flask官方的例子。@app.route(''/user/'')defshow_ user_profile(username):#showtheuserprofileforthatuserret urn''User%s''%username@app.route(''/post/'')defshow _post(post_id):#showthepostwiththegivenid,theidisani ntegerreturn''Post%d''%post_id123456789构造URL在Web程序中常常需要获取某个页面的 URL,在Flask中需要使用url_for(''方法名'')来构造对应方法的URL。下面是Flask官方的例子。>>>fromf laskimportFlask,url_for>>>app=Flask(__name__)>>>@app.route (''/'')...defindex():pass...>>>@app.route(''/login'')...deflogi n():pass...>>>@app.route(''/user/'')...defprofile(use rname):pass...>>>withapp.test_request_context():...printurl_ for(''index'')...printurl_for(''login'')...printurl_for(''login'', next=''/'')...printurl_for(''profile'',username=''JohnDoe'')...//lo gin/login?next=//user/John%20Doe123456789101112131415161718192021 HTTP方法如果需要处理具体的HTTP方法,在Flask中也很容易,使用route装饰器的methods参数设置即可。fromf laskimportrequest@app.route(''/login'',methods=[''GET'',''POST''])d eflogin():ifrequest.method==''POST'':do_the_login()else:sho w_the_login_form()12345678静态文件Web程序中常常需要处理静态文件,在Flask中需要使用url_for 函数并指定static端点名和文件名。在下面的例子中,实际的文件应放在static/文件夹下。url_for(''static'', filename=''style.css'')1模板生成Flask默认使用http://jinja.pocoo.org/docs/2. 9/templates/Jinja2作为模板,Flask会自动配置Jinja模板,所以我们不需要其他配置了。默认情况下,模板文件 需要放在templates文件夹下。使用Jinja模板,只需要使用render_template函数并传入模板文件名和参数名即 可。fromflaskimportrender_template@app.route(''/hello/'')@app.rout e(''/hello/'')defhello(name=None):returnrender_template(''h ello.html'',name=name)123456相应的模板文件如下。Hello fromFlask{%ifname%}Hello{{name}}!{%els e%}Hello,World!{%endif%}1234567日志输出Flask为我们预配置了一个 Logger,我们可以直接在程序中使用。这个Logger是一个标准的PythonLogger,所以我们可以向标准Logger那样 配置它,详情可以参考https://docs.python.org/library/logging.html官方文档或者我的文章h ttp://www.jianshu.com/p/9884a660050fPython日志输出。app.logger.debug( ''Avaluefordebugging'')app.logger.warning(''Awarningoccurred(% dapples)'',42)app.logger.error(''Anerroroccurred'')123处理请求在Flas k中获取请求参数需要使用request等几个全局对象,但是这几个全局对象比较特殊,它们是?ContextLocals?,其实就 是Web上下文中局部变量的代理。虽然我们在程序中使用的是全局变量,但是对于每个请求作用域,它们都是互不相同的变量。理解了这一点 ,后面就非常简单了。Request对象Request对象是一个全局对象,利用它的属性和方法,我们可以方便的获取从页面传递过来的 参数。method属性会返回HTTP方法的类似,例如post和get。form属性是一个字典,如果数据是POST类型的表单,就可以 从form属性中获取。下面是Flask官方的例子,演示了Request对象的method和form属性。fromflas kimportrequest@app.route(''/login'',methods=[''POST'',''GET''])def login():error=Noneifrequest.method==''POST'':ifvalid_login (request.form[''username''],request.form[''password'']):returnlog_ the_user_in(request.form[''username''])else:error=''Invaliduser name/password''#thecodebelowisexecutediftherequestmethod #wasGETorthecredentialswereinvalidreturnrender_template (''login.html'',error=error)1234567891011121314如果数据是由GET方法传送过来的,可以 使用args属性获取,这个属性也是一个字典。searchword=request.args.get(''key'','''')1文件 上传利用Flask也可以方便的获取表单中上传的文件,只需要利用request的files属性即可,这也是一个字典,包含了被上传 的文件。如果想获取上传的文件名,可以使用filename属性,不过需要注意这个属性可以被客户端更改,所以并不可靠。更好的办法是利用 werkzeug提供的secure_filename方法来获取安全的文件名。fromflaskimportrequestfr omwerkzeug.utilsimportsecure_filename@app.route(''/upload'',met hods=[''GET'',''POST''])defupload_file():ifrequest.method==''POS T'':f=request.files[''the_file'']f.save(''/var/www/uploads/''+se cure_filename(f.filename))12345678CookiesFlask也可以方便的处理Cookie。使用方法 很简单,直接看官方的例子就行了。下面的例子是如何获取cookie。fromflaskimportrequest@app.ro ute(''/'')defindex():username=request.cookies.get(''username'')# 使用cookies.get(key)代替cookies[key]避免#得到KeyError如果cookie不存在 1234567如果需要发送cookie给客户端,参考下面的例子。fromflaskimportmake_response@a pp.route(''/'')defindex():resp=make_response(render_template(.. .))resp.set_cookie(''username'',''theusername'')returnresp123456 7重定向和错误redirect和abort函数用于重定向和返回错误页面。fromflaskimportabort,redi rect,url_for@app.route(''/'')defindex():returnredirect(url_for( ''login''))@app.route(''/login'')deflogin():abort(401)this_is_neve r_executed()12345678910默认的错误页面是一个空页面,如果需要自定义错误页面,可以使用errorhandler 装饰器。fromflaskimportrender_template@app.errorhandler(404)defpa ge_not_found(error):returnrender_template(''page_not_found.html'' ),40412345响应处理默认情况下,Flask会根据函数的返回值自动决定如何处理响应:如果返回值是响应对象,则直接传递给客户 端;如果返回值是字符串,那么就会将字符串转换为合适的响应对象。我们也可以自己决定如何设置响应对象,方法也很简单,使用make_re sponse函数即可。@app.errorhandler(404)defnot_found(error):resp=mak e_response(render_template(''error.html''),404)resp.headers[''X-So mething'']=''Avalue''returnresp12345Sessions我们可以使用全局对象session来管 理用户会话。Sesison是建立在Cookie技术上的,不过在Flask中,我们还可以为Session指定密钥,这样 存储在Cookie中的信息就会被加密,从而更加安全。直接看Flask官方的例子吧。fromflaskimportFl ask,session,redirect,url_for,escape,requestapp=Flask(__nam e__)@app.route(''/'')defindex():if''username''insession:return ''Loggedinas%s''%escape(session[''username''])return''Youaren otloggedin''@app.route(''/login'',methods=[''GET'',''POST''])deflog in():ifrequest.method==''POST'':session[''username'']=request. form[''username'']returnredirect(url_for(''index''))return''''''rmmethod="post">pe=submitvalue=Login>''''''@app.route(''/logout'')deflogout ():#removetheusernamefromthesessionifit''stheresession. pop(''username'',None)returnredirect(url_for(''index''))#setthe secretkey.keepthisreallysecret:app.secret_key=''A0Zr98j/3y XR~XHH!jmN]LWX/,?RT''12345678910111213141516171819202122232425262 7282930模板简介这里简单的介绍一下Jinja模板的使用方法,详细资料直接看原文档吧。模板标签其实Jinja模板和其他语言 和框架的模板类似,反正都是通过某种语法将HTML文件中的特定元素替换为实际的值。如果使用过JSP、Thymeleaf等模板,应该 可以非常容易的学会使用Jinja模板。其实从上面的例子中我们应该可以看到Jinja模板的基本语法了。代码块需要包含在{%%} 块中,例如下面的代码。{%extends''layout.html''%}{%blocktitle%}主页{%endbl ock%}{%blockbody%}主页 {%endblock%}123456789双大括号中的内容不会被转义,所有内容都会原样输出,它常常和其他辅助函数一起使用。下面 是一个例子。Flask小例 子1继承模板可以继承其他模板,我们可以将布局设置为父模板,让其他模板继承,这样可以非常方便的控制整个程序的外观。例如这里有 一个layout.html模板,它是整个程序的布局文件。rset="UTF-8">">le=1">{%blocktitle%}{%endblock%}stylesheet"href="{{url_for(''static'',filename=''css/bootstrap.css '')}}"/>e=''css/bootstrap-theme.css'')}}"/>nerbody-content">{%blockbody%}{%endblock%}="containerfooter">
这是页脚 r(''static'',filename=''js/jquery.js'')}}">url_for(''static'',filename=''js/bootstrap.js'')}}"> 123456789101112131415161718192021222324252627其他模板可以这么写。对比一 下面向对象编程的继承概念,我们可以很容易的理解。{%extends''layout.html''%}{%blocktitle %}主页{%endblock%}{%blockbody%}主 页本项目演示了Flask的简单使用方法,点击导航栏上的菜单条查看具体功能。 {%endbl ock%}12345678910控制流条件判断可以这么写,类似于JSP标签中的Java代码,{%%}中也可以写Python代 码。下面是Flask官方文档的例子。{%ifnotsession.logged_i n%}login{%else%}ef="{{url_for(''logout'')}}">logout{%endif%}123456 7循环的话可以这么写,和在Python中遍历差不多。{%forkey,valueindata.items ()%}{{key}} | {{value}} | {%endfo r%}文件 | | 123456789101112需要注意 不是所有的Python代码都可以写在模板里,如果希望从模板中引用其他文件的函数,需要显式将函数注册到模板中。可以参考http:// stackoverflow.com/questions/6036082/call-a-python-function-from-jinja2这个爆栈提问。写在最后这篇文章主要参考了Flask的官方文档,但是只介绍了Flask的最基本的一部分。了解了这部分,我们可以用Python搭一个小服务器做点事情。如果希望详细了解Flask的使用用法,请关注更详细的资料。本文就是起一个抛砖引玉的效果。顺便说,通过Flask我也了解了Python语言的执行速度。我们都知道编译器编译出来的代码执行起来要比解释器解释代码要快大约几十倍到几千倍不等。以前学Java的时候,感觉Java慢,主要原因就是等待编译时间比较长。相对来说用Python写脚本就很块了,因为没有编译过程。但是从Flask的运行速度来看,我切身感受到了Python执行确实不快。举个例子,在Spring中写一个控制器,接受HTTP参数,并显示到页面上,如果程序编译完之后,这个显示过程基本是瞬时的。但是同样的需求在Flask中,我居然可以感觉到明显的延迟(大概几百毫秒的等待时间)。所以,如果你想写一个比较快的Web程序,还是用Java或者JVM语言吧,虽然看着土,性能确实杠杠的。最后,我写了一个小练习,试了试Flask的基本功能,如果有兴趣可以上https://github.com/techstay/python-study/tree/master/flask-sample我的Github查看代码。
|
|