Python Flask 快速入门

1. 基本

  1. 一个不叫flask.py的文件,因为这会与Flask冲突,然后使用python运行
    # flaskr.py
    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'Hello World'
    
    @app.route('/user/<username>')
    def show_user_profile(username):
        return 'User %s' % username
    
    @app.route('/post/<int:post_id>')
    def show_post(post_id):
        return 'Post %d' % post_id
    
    if __name__ == '__main__':
        # app.run()  调试模式,该文件只能从你自己的计算机上访问,网络中其它任何的地方都不能访问。只有加了host='0.0.0.0'才可以
        # app.run(debug=True) 或者 app.debug=True  可以让应用在你修改了代码后自动的重启服务器。并且如果发生错误,它会提供一个有用的调试器。
        # 其他调试器 http://www.pythondoc.com/flask/errorhandling.html#working-with-debuggers
        app.run(host='0.0.0.0', port=5000, debug=True)
    
  2. 现在浏览 http://127.0.0.1:5000/,你会看到你的 Hello World 问候。
  3. app.route指定接受的url,里面可以有int/float/string类型的转换器,形式是type:variable\。
  4. app.route(’/a/’)可以表示app.route(’/a’),但反过来不行,会404 not found

2. url_for使用

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index(): pass

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        show_the_log_form()
    else:
        do_the_login()

@app.route('/user/<username>/')
def profile(username): pass

with app.test_request_context():
    print(url_for('index'), url_for('login'), url_for('login', next='next'), url_for('profile', username='John Doe'), sep='\n')
# 使用url_for的好处在于
    # 反向构建通常比硬编码更具备描述性。更重要的是,它允许你一次性修改 URL, 而不是到处找 URL 修改。
    # 构建 URL 能够显式地处理特殊字符和 Unicode 转义,因此你不必去处理这些。
    # 如果你的应用不在 URL 根目录下(比如,在 /myapplication 而不在 /), url_for() 将会适当地替你处理好。

3. 静态文件

动态的 web 应用同样需要静态文件。CSS 和 JavaScript 文件通常来源于此。理想情况下, 你的 web 服务器已经配置好为它们服务,然而在开发过程中 Flask 能够做到。 只要在你的包中或模块旁边创建一个名为 static 的文件夹,在应用中使用 /static 即可访问。给静态文件生成 URL ,使用特殊的 ‘static’ 端点名: url_for(‘static’, filename=‘style.css’)

4. 渲染模板

  1. 基本使用
    from flask import render_template
    @app.route('/hello/')
    @app.route('/hello/<name>')
    def hello(name=None):
        return render_template('hello.html', name=name)
    
  2. Flask 将会在 templates 文件夹中寻找模版。因此如果你的应用是个模块,这个文件夹在模块的旁边,如果它是一个包,那么这个文件夹在你的包里面:
    1. 一个模块:
        /application.py
        /templates
            /hello.html
    2. 一个包
        /application
        /__init__.py
        /templates
            /hello.html
    
  3. 对于模板,你可以使用 Jinja2 模板的全部功能。详细信息查看官方的 Jinja2 Template Documentation http://jinja.pocoo.org/2/documentation/templates 。在模版中你也可以使用 request, session 和 g 对象,也能使用函数 get_flashed_messages() 。
    1. 模板继承 http://www.pythondoc.com/flask/patterns/templateinheritance.html#template-inheritance
    2. 例子
      <!doctype html>
      <title>Hello from Flask</title>
      {% if name %}
          <h1>Hello {{ name }}!</h1>
      {% else %}
          <h1>Hello World!</h1>
      {% endif %}
      
    3. 自动转义默认开启,因此如果 name 包含 HTML,它将会自动转义。如果你信任一个变量,并且你知道它是安全的 (例如一个模块把 wiki 标记转换到 HTML ),你可以用 Markup 类或 |safe 过滤器在模板中标记它是安全的。下面是Markup 类如何工作的基本介绍:
      from flask import Markup
      print(Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>')  # Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
      print(Markup.escape('<blink>hacker</blink>'))  # Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
      print(Markup('<em>Marked up</em> &raquo; HTML').striptags())  # u'Marked up \xbb HTML'
      
    4. 在版本0.5后,自动转义不再在所有模版中启用。模板中下列后缀的文件会触发自动转义:.html, .htm, .xml, .xhtml。从字符串加载的模板会禁用自动转义。

5. requset

  1. test_request_context 与 requst_context
    from flask import request
    with app.test_request_context('/hello', method='POST'):
        # now you can do something with the request until the
        # end of the with block, such as basic assertions:
        assert request.path == '/hello'
        assert request.method == 'POST'
    with app.request_context(environ):
        assert request.method == 'POST'
    
  2. request.method/path/form/args/files/cookies
    @app.route('/login', methods=['POST', 'GET'])
    def login():
        error = None
        if request.method == 'POST':
            if valid_login(request.form['username'], request.form['password']):
                return log_the_user_in(request.form['username'])
            else:
                error = 'Invalid username/password'
        return render_template('login.html', error=error)
    # 如果在 form 属性中不存在上述键值会发生些什么?在这种情况下会触发一个特别的 KeyError。 你可以像捕获标准的 KeyError 来捕获它,如果你不这样去做,
    # 会显示一个 HTTP 400 Bad Request 错误页面。 所以很多情况下你不需要处理这个问题。
    
    # 可以用 args 属性来接收在 URL ( ?key=value ) 中提交的参数:
    search_word = request.args.get('key', 'default')
    # 我们推荐使用 get 来访问 URL 参数或捕获 KeyError ,因为用户可能会修改 URL, 向他们显示一个 400 bad request 页面不是用户友好的。
    
  3. 文件上传: 你能够很容易地用 Flask 处理文件上传。只要确保在你的 HTML 表单中不要忘记设置属性 enctype=“multipart/form-data”, 否则浏览器将不传送文件。
    1. 基本使用
      # 上传的文件是存储在内存或者文件系统上一个临时位置。你可以通过请求对象中 files 属性访问这些文件。 每个上传的文件都会存储在这个属性字典里。
      # 它表现得像一个标准的 Python file 对象,但是它同样具有 save() 方法,该方法允许你存储文件在服务器的文件系统上。 
      @app.route('/upload', methods=['GET', 'POST'])
      def upload_file():
          if request.method == 'POST':
              f = request.files['the_file']
              f.save('/var/www/uploads/uploaded_file.txt')
      
    2. 文件名
      # 如果你想要知道在上传到你的应用之前在客户端的文件名称,你可以访问 filename 属性。但请记住永远不要信任这个值,因为这个值可以伪造。
      # 如果你想要使用客户端的文件名来在服务器上存储文件, 把它传递到 Werkzeug 提供给你的 secure_filename() 函数:
      from werkzeug import secure_filename
      @app.route('/upload', methods=['GET', 'POST'])
      def upload_file():
          if request.method == 'POST':
              f = request.files['the_file']
              f.save('/var/www/uploads/' + secure_filename(f.filename))
      
  4. cookies:
    from flask import request
    from flask import make_response
    @app.route('/')
    def index():
        username = request.cookies.get('username')
        # use cookies.get(key) instead of cookies[key] to not get a KeyError if the cookie is missing.
        resp = make_response(render_template(...))
        resp.set_cookie('username', 'the username')
        return resp
    

6. 重定向和错误

  1. 用 redirect() 函数重定向用户到其它地方。能够用 abort() 函数提前中断一个请求并带有一个错误代码。
    from flask import abort, redirect, url_for
    @app.route('/')
    def index():
        return redirect(url_for('login'))
    @app.route('/login')
    def login():
        abort(401)  # 只是为了测试而已,实际写代码的时候不会这样
        this_is_never_executed()
    
  2. 默认情况下,每个错误代码会显示一个黑白错误页面。如果你想定制错误页面,可以使用 errorhandler() 装饰器:
    @app.errorhandler(404)
    def page_not_found(error):
        return render_template('page_not_found.html'), 404
    

7. response

  1. 一个视图函数(带有app.route/errorhandler等等的函数)的返回值会被自动转换为一个响应对象。如果返回值是一个字符串,它被转换成一个响应主体是该字符串,响应码为 200 OK ,媒体类型为 text/html 的响应对象。Flask 把返回值转换成响应对象的逻辑如下:
    1. 如果返回的是一个合法的响应对象,它会被从视图直接返回。
    2. 如果返回的是一个字符串,响应对象会用字符串数据和默认参数创建。
    3. 如果返回的是一个元组而且元组中元素能够提供额外的信息。这样的元组必须是 (response, status, headers) 形式且至少含有一个元素。 status 值将会覆盖状态代码,headers 可以是一个列表或额外的消息头值字典。
    4. 如果上述条件均不满足,Flask 会假设返回值是一个合法的 WSGI 应用程序,并转换为一个请求对象。
  2. 如果你想要获取在视图中得到的响应对象,你可以用函数 make_response() 。
    @app.errorhandler(404)
    def not_found(error):
        resp = make_response(render_template('error.html'), 404)
        resp.headers['X-Something'] = 'A value'
        return resp
    

8. session

  1. 除了请求对象,还有第二个称为 session 对象允许你在不同请求间存储特定用户的信息。 这是在 cookies 的基础上实现的,并且在 cookies 中使用加密的签名。这意味着用户可以查看 cookie 的内容, 但是不能修改它,除非它知道签名的密钥。要使用会话,你需要设置一个密钥。这里介绍会话如何工作:
    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 '''<form action="" method="post">
                <p><input type=text name=username>
                <p><input type=submit value=Login>
            </form>'''
    @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'
    # 这里提到的 escape() 可以在你不使用模板引擎的时候做转义(如同本例)。
    
  2. 怎样产生一个好的密钥
    import os
    os.urandom(24)  # '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8' 目标值
    
  3. 使用基于 cookie 的会话需注意: Flask 会将你放进会话对象的值序列化到 cookie。如果你试图寻找一个跨请求不能存留的值, cookies 确实是启用的,并且你不会获得明确的错误信息,检查你页面请求中 cookie 的大小,并与 web 浏览器所支持的大小对比。

9. 消息闪烁

  1. 好的应用和用户界面全部是关于反馈。如果用户得不到足够的反馈,他们可能会变得讨厌这个应用。Flask 提供了一个真正的简单的方式来通过消息闪现系统给用户反馈。消息闪现系统基本上使得在请求结束时记录信息并在下一个(且仅在下一个)请求中可以被访问。通常结合模板布局来显示消息。使用 flash() 方法来闪现一个消息,使用 get_flashed_messages() 能够获取消息, get_flashed_messages() 也能用于模版中。
  2. 消息闪现

10. 日志

  1. 版本0.3后出现,日志调用的例子:
    app.logger.debug('A value for debugging')
    app.logger.warning('A warning occurred (%d apples)', 42)
    app.logger.error('An error occurred')
    
  2. 附带的 logger 是一个标准的日志类 Logger ,因此更多的信息请 查阅官方文档logging documentation

11. 整合WSGI中间件

  1. 如果你想给你的应用添加 WSGI 中间件,你可以封装内部 WSGI 应用。例如如果你想使用 Werkzeug 包中的某个中间件来应付 lighttpd 中的 bugs,你可以这样做:
    from werkzeug.contrib.fixers import LighttpdCGIRootFix
    app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
    

12. 部署到Web服务器

  1. 准备好部署你的新 Flask 应用?你可以立即部署到托管平台来完成快速入门,以下是向小项目提供免费的方案:
    1. Deploying Flask on Heroku
    2. Deploying WSGI on dotCloud with Flask-specific notes
  2. 你可以托管 Flask 应用的其它选择:
    1. Deploying Flask on Webfaction
    2. Deploying Flask on Google App Engine
    3. Sharing your Localhost Server with Localtunnel
  3. 如果你管理你自己的主机并且想要自己运行,请参看 部署方式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值