Flask之旅: 快速上手

栏目: Python · 发布时间: 5年前

内容简介:Flask只有route()装饰器把视图函数绑定到url上面。另外我们也可以指定动态url。通过把 URL 的一部分标记为 <variable_name> 就可以在 URL 中添加变量。标记的 部分会作为关键字参数传递给函数。

Flask只有route()装饰器把视图函数绑定到url上面。

@app.route('/user')
def hello_user():
    return 'Hello, user!'
复制代码

另外我们也可以指定动态url。

通过把 URL 的一部分标记为 <variable_name> 就可以在 URL 中添加变量。标记的 部分会作为关键字参数传递给函数。

# 比如获取一个用户详情的url

@app.route('/user/<id>/')
def hello_user(id):
    return 'Hello, userid: {0}!'.format(id)
复制代码

<variable_name>默认是字符串, 如果我们需要指定参数类型可以通过:

<converter:variable_name>
复制代码

Flask执行的转换器类型:

Flask之旅: 快速上手

唯一Url

Flask的URL规则基于Werkzeug的路由模块, 主张保证优雅且唯一的URL。

以上述的例子为例如果你访问

http://0.0.0.0:9999/user/2
复制代码

我们定义的路由是'/user//', 如果访问一个结尾不带/的URL会被重定向到带斜杠的URL上去,这样可以保持 URL 唯一,并帮助 搜索引擎避免重复索引同一页面。

Flask之旅: 快速上手

构造URL

使用url_for()构建url, 它接受函数名字作为第一个参数, 也接受对应URL规则的变量部分的命名参数, 未知的变量部分会添加到URL末尾作为查询参数。

from flask import Flask, url_for
app = Flask(__name__)

app.config['DEBUG'] = True

@app.route('/user/<int:id>')
def user(id):
    pass

#  test_request_context() 告诉 Flask 正在处理一个请求
with app.test_request_context():
    print(url_for('user', id=2))
    print(url_for('user', id=3, type='doctor'))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port='9999')
复制代码

输出:

/user/2
/user/3?type=doctor
复制代码

为什么不在把 URL 写死在模板中,而要使用反转函数 url_for() 动态构建?

1. 反转通常比硬编码URL的描述性更好。
2. 未来更过URL, 你可以只在一个地方改变 URL,而不用到处替换。
3. URL创建会为你处理特殊字符的转义和Unicode数据,比较直观。
4. 生产的路径总是绝对路径,可以避免相对路径产生副作用。
5. 如果你的应用是放在URL根路径之外的地方(如在 /myapplication 中,不在 / 中), url_for() 会为你妥善处理。
复制代码

跳转与重定向

跳转(301)多用于旧网址在废弃之前转向新网址保证用户的访问, 有页面被永久性易走的概念。

重定向(302)表示页面只是暂时的转移, 不建议经常性使用重定向。

redirect(location) #默认是302
redirect(location, code=301) # 可以指定code
复制代码
from flask import Flask, url_for, render_template, redirect
app = Flask(__name__)

app.config['DEBUG'] = True

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login')
def login():
    return render_template('login.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port='9999')
    
复制代码

HTTP方法

Web 应用使用不同的 HTTP 方法处理 URL,默认情况下,一个路由只回应 GET 请求。可以使用 route() 装饰器的 methods 参数来处理不同的 HTTP 方法:

@app.route('/login', methods=['GET', 'POST'])
复制代码

简单介绍下常见的HTTP方法与使用场景:

- GET: 获取资源, GET操作应该是幂等的

- HEAD: 想要获取信息, 但是只关心消息头, 应该可以把它当作GET来处理, 但是不返回内容。具有幂等性

- POST: 创建一个资源, 非幂等方法

- PUT: 完整的替换资源或者创建资源, 是幂等方法

- DELETE: 删除资源, 是幂等方法

- OPTIONS:获取资源所支持的所有HTTP方法

- PATCH: 局部更新, 非幂等方法
复制代码

HTTP幂等方法,是指无论调用多少次都不会有不同结果的 HTTP 方法。不管你调用一次,还是调用一百次,一千次,结果都是相同的。

关于 如何理解 RESTful 的幂等性

在视图函数里面我们可以使用如下方式判断HTTP请求方法

from flask import Flask, request

request.method # 获取当前请求的方法
复制代码

静态文件

动态的 web 应用也需要静态文件,一般是 CSS 和 JavaScript 文件。理想情况下你的 服务器已经配置好了为你的提供静态文件的服务。但是在开发过程中, Flask 也能做好 这项工作。只要在你的包或模块旁边创建一个名为 static 的文件夹就行了。 静态文件位于应用的 /static 中。

在实例化Flask时候如果你查看源码你会发现
app = Flask(__name__)


def __init__(
        self,
        import_name,
        static_url_path=None,
        static_folder='static',
        static_host=None,
        host_matching=False,
        subdomain_matching=False,
        template_folder='templates',
        instance_path=None,
        instance_relative_config=False,
        root_path=None
    ):
复制代码

static为默认的静态文件的目录。

# 这样是可以直接访问到静态文件的

http://0.0.0.0:9999/static/app.css
复制代码

我们不建议在模板里面直接写死静态文件路径, 应该使用url_for()生成路径

url_for('static', filename='app.css')
复制代码

当然我们也可以定制静态文件的真实目录

app = Flask(__name__, static_folder='/tmp')
复制代码

渲染模板

Flask默认提供的是Jinja2 模板引擎。

使用 render_template() 方法可以渲染模板,你只要提供模板名称和需要 作为参数传递给模板的变量就行了。下面是一个简单的模板渲染例子:

templates是Flask默认的目录名字。

@app.route('/')
def index():
    return render_template('index.html', title='首页')
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
</head>
<body>
</body>
</html>
复制代码

在模板内部可以和访问 get_flashed_messages() 函数一样访问 request 、 session 和 g对象[g保存的是当前请求的全局变量,不同的请求会有不同的全局变量]。

Jinja2文档这里就不细说了, 后面有空单独写一篇, 现在前后分离, 已经比较少使用模板了。

操作request对象

在Flask 中由全局对象request来提供请求信息。如果你有一些 Python 基础,那么 可能 会奇怪:既然这个对象是全局的,怎么还能保持线程安全?

from flask import request
复制代码

某些对象在 Flask 中是全局对象,但不是通常意义下的全局对象。这些对象实际上是 特定环境下本地对象的代理。真拗口!但还是很容易理解的。

从一个 Flask App 读入配置并启动开始,就进入了 App Context,在其中我们可以访问配置文件、打开资源文件、通过路由规则反向构造 URL。当一个请求进入开始被处理时,就进入了 Request Context,在其中我们可以访问请求携带的信息,比如 HTTP Method、表单域等。

request虽然是全局变量但是只是一个代理, 想深挖细节的可以看看这个文章Flask的Context机制。

理解Flask的request上下文

- 通过使用 method 属性可以操作当前请求方法

- 通过使用 form 属性处理表单数据(在 POST 或者 PUT 请求 中传输的数据), 当 form 属性中不存在这个键时会发生什么?会引发一个 KeyError 。 
如果你不像捕捉一个标准错误一样捕捉 KeyError ,那么会显示一个 HTTP 400 Bad Request 错误页面。

- 要操作 URL (如 ?key=value )中提交的参数可以使用 args 属性:
searchword = request.args.get('key', '')
复制代码

响应

视图函数的返回值会被转为一个响应对象。

比如:

# 你会发现页面里面没有文字显示, 只有h3标签
@app.route('/')
def index():
    return '<h3></h3>'

复制代码

你查看app.route()源码会发现

# route装饰器只是一个语法糖, 实际执行的还是add_url_rule()
def decorator(f):
    endpoint = options.pop('endpoint', None)
    self.add_url_rule(rule, endpoint, f, **options)
    return f
return decorator
复制代码

转化逻辑如下:

1. 如果返回的是一个合法的响应对象, 它会从视图直接返回
2. 如果返回的是一个字符串, 会用字符串数据和默认参数来创建以字符串为主体, 状态码为200,MIME类型的text.html的werkzeug.wrappers.Response响应对象。

3. 如果返回的是一个元组, 且元组的元素可以提供额外的信息, 这样的元组格式为(response, status, headers)。它们会覆盖默认的配置。

4. 如果上述条件都不对, Flask会假设返回值是一个合法的WSGI应用程序, 并通过Response.force_type(rv, request.environ)转化为请求对象
复制代码

实例:

@app.route('/')
def index():
    return render_template('index.html'), 400
复制代码

我们也可以显示使用make_response方法

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

app.config['DEBUG'] = True

@app.route('/')
def index():
    response = make_response(render_template('index.html'), 400)
    return response

复制代码

使用make_response方法我们可以设置cookie, 头信息等。

查看make_response方法源码其实也很好理解。

def make_response(*args):
    # 根据args传参情况进行不同处理
    if not args:
        return current_app.response_class()
    if len(args) == 1:
        args = args[0]
    return current_app.make_response(args)
复制代码
def make_response(self, rv):
    status = headers = None
    # unpack tuple returns
    # 传入的是元组
    if isinstance(rv, tuple):
        len_rv = len(rv)
        # 格式(response, status, headers)
        if len_rv == 3:
            rv, status, headers = rv
        # decide if a 2-tuple has status or headers
        elif len_rv == 2:
            if isinstance(rv[1], (Headers, dict, tuple, list)):
                rv, headers = rv
            else:
                rv, status = rv
        # other sized tuples are not allowed
        else:
            raise TypeError(
                'The view function did not return a valid response tuple.'
                ' The tuple must have the form (body, status, headers),'
                ' (body, status), or (body, headers).'
            )

    # the body must not be None
    if rv is None:
        raise TypeError(
            'The view function did not return a valid response. The'
            ' function either returned None or ended without a return'
            ' statement.'
        )

    # make sure the body is an instance of the response class
    if not isinstance(rv, self.response_class):
        if isinstance(rv, (text_type, bytes, bytearray)):
            # let the response class set the status and headers instead of
            # waiting to do it manually, so that the class can handle any
            # special logic
            rv = self.response_class(rv, status=status, headers=headers)
            status = headers = None
        else:
            # evaluate a WSGI callable, or coerce a different response
            # class to the correct type
            try:
                rv = self.response_class.force_type(rv, request.environ)
            except TypeError as e:
                new_error = TypeError(
                    '{e}\nThe view function did not return a valid'
                    ' response. The return type must be a string, tuple,'
                    ' Response instance, or WSGI callable, but it was a'
                    ' {rv.__class__.__name__}.'.format(e=e, rv=rv)
                )
                reraise(TypeError, new_error, sys.exc_info()[2])

    # prefer the status if it was provided
    if status is not None:
        if isinstance(status, (text_type, bytes, bytearray)):
            rv.status = status
        else:
            rv.status_code = status

    # extend existing headers with provided headers
    if headers:
        rv.headers.extend(headers)

    return rv
复制代码

以上所述就是小编给大家介绍的《Flask之旅: 快速上手》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Algorithmic Beauty of Plants

The Algorithmic Beauty of Plants

Przemyslaw Prusinkiewicz、Aristid Lindenmayer / Springer / 1996-4-18 / USD 99.00

Now available in an affordable softcover edition, this classic in Springer's acclaimed Virtual Laboratory series is the first comprehensive account of the computer simulation of plant development. 150......一起来看看 《The Algorithmic Beauty of Plants》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具