Web 控制器

控制器

控制器需要提供可扩展性,类似于 Model ,但由于先决条件(加载了模块的数据库)可能尚不可用(例如,未创建数据库或未选择数据库),因此无法使用相同的机制。

因此,控制器提供了自己的扩展机制,与模型的机制分离:

控制器通过从 Controller 继承 创建。路由通过使用 route() 装饰的方法定义::

class MyController(odoo.http.Controller):
    @route('/some_url', auth='public')
    def handler(self):
        return stuff()

要 覆盖 一个控制器,从其类 继承 并覆盖相关方法,必要时重新暴露它们::

class Extension(MyController):
    @route()
    def handler(self):
        do_before()
        return super(Extension, self).handler()
  • 使用 route() 进行装饰是必要的,以保持方法(和路由)可见:如果重新定义方法时未进行装饰,它将被“取消发布”。

  • 所有方法的装饰器会被合并,如果覆盖方法的装饰器没有参数,则保留之前的所有装饰器;任何提供的参数都会覆盖之前定义的参数,例如::

    class Restrict(MyController):
        @route(auth='user')
        def handler(self):
            return super(Restrict, self).handler()
    

    将把 /some_url 的认证方式从公开更改为用户(需要登录)。

API

路由

@odoo.http.route(route: str | Sequence[str] | None = None, **routing: typing.Unpack[RoutingOpts])[源代码]

装饰控制器方法,以便将匹配给定 URL 和选项的传入请求路由到被装饰的方法。

警告

必须重新装饰在控制器扩展中被覆盖的任何方法,但可以省略参数。详情请参见 Controller 。

参数
  • route (Union[str, Iterable[str]]) – 被装饰方法服务的路径。与该路由匹配的传入 HTTP 请求路径将被路由到此装饰方法。有关路由表达式的格式,请参阅 werkzeug 路由文档 。

  • type (str) – 请求类型,可以是 'jsonrpc' 或 'http' 。它描述了在哪里找到请求参数以及如何序列化响应。

  • auth (str) – 认证方法,以下之一: * 'user' :用户必须经过认证,当前请求将使用该用户的权限执行。 * 'bearer' :用户使用 “Authorization” 请求头进行认证,使用带有 API 令牌的 Bearer 方案。请求将使用相应用户的权限执行。如果缺少该头部,请求必须属于认证会话,就像 “user” 认证方法一样。 * 'public' :用户可能经过认证,也可能没有。如果未认证,当前请求将使用共享的公共用户执行。 * 'none' :该方法始终处于活动状态,即使没有数据库。主要由框架和认证模块使用。请求代码将没有任何访问当前用户的设施。

  • bearer_scope (str) – 用于对用户进行身份验证的 bearer 令牌的作用域。如果在某条路由上将 bearer_scope 设置为 ‘A’,那么只有以作用域 ‘A’(而非作用域 ‘B’)生成的令牌才能在该端点上对用户进行身份验证。对于 auth='bearer' 必须设置,对于其他身份验证方法则不得设置。

  • methods (Iterable[str]) – 此路由适用的 HTTP 方法(动词)列表。如果未指定,则允许所有方法。

  • cors (str) – Access-Control-Allow-Origin CORS 指令的值。

  • csrf (bool) – 是否应为该路由启用 CSRF 保护。默认对 'http' 类型请求启用,默认对 'jsonrpc' 类型请求禁用。

  • readonly (Union[bool, Callable[[registry, request], bool]]) – 此端点是否应在只读副本上打开游标,而不是(默认情况下)主读写数据库。

  • handle_params_access_error (Callable[[Exception], Response]) – 如果从 URL 参数中检索记录时发生错误(访问错误或缺失错误),实现自定义行为。

  • captcha (str) – 验证码的操作名称。设置后,请求将根据验证码实现进行验证。失败时,这些请求将返回 UserError。

  • save_session (bool) – 是否应在 http 响应上设置 session_id cookie 并将脏会话保存到磁盘。对于 auth='bearer' 默认为 False 。其他情况默认为 True 。

请求

请求对象会在请求开始时自动设置到 odoo.http.request 上。

class odoo.http.requestlib.Request(httprequest: odoo.http._facade.HTTPRequest)[源代码]

围绕传入 HTTP 请求的包装器,包含反序列化的请求参数、会话工具和请求分发逻辑。

update_env(user: int | BaseModel | None = None, context: dict | None = None, su: bool | None = None) → None[源代码]

更新当前请求的环境。

参数
  • user (int or res.users record) – 可选的用户/用户 ID,用于更改当前用户。

  • context (dict) – 可选的上下文字典,用于更改当前上下文。

  • su (bool) – 可选的布尔值,用于更改超级用户模式。

update_context(**overrides) → None[源代码]

使用 overrides 的值覆盖当前请求的环境上下文。要替换整个上下文,请改用 update_env() 。

csrf_token(time_limit: int | None = None) → str[源代码]

生成并返回当前会话的 CSRF 令牌。

参数

time_limit – CSRF 令牌仅在指定的持续时间(以秒为单位)内有效,默认为 48 小时,None 表示令牌在当前用户的会话有效期内一直有效。

返回

ASCII 令牌字符串

validate_csrf(csrf: str) → bool[源代码]

给定的 csrf 令牌是否有效?

参数

csrf – 要验证的令牌。

返回

有效时为 True ,无效时为 False 。

default_lang() → str[源代码]

根据请求规范返回默认用户语言。

返回

如果指定了首选语言,则返回该语言,否则返回 ‘en_US’。

get_http_params() → dict[源代码]

从查询字符串和请求体中的表单(包括 application/x-www-form-urlencoded 和 multipart/form-data)提取键值对。

返回

合并后的键值对。

make_response(data: str, headers: HeaderType | None = None, cookies: Mapping | None = None, status: int = 200) → Response[源代码]

用于非 HTML 响应或带有自定义响应头或 Cookie 的 HTML 响应的辅助工具。

虽然处理器可以直接返回页面的 HTML 标记作为字符串,但如果返回的是非 HTML 数据,则需要创建一个完整的响应对象,否则客户端将无法正确解析返回的数据。

参数
  • data – 响应主体

  • status – HTTP 状态码

  • headers – 要设置在响应中的 HTTP 头

  • cookies – 要在客户端设置的 Cookie

返回

一个响应对象。

make_json_response(data: typing.Any, headers: HeaderType | None = None, cookies: Mapping | None = None, status: int = 200) → Response[源代码]

用于 JSON 响应的辅助工具,它会对 data 进行 JSON 序列化,并在未提供时相应地设置 Content-Type 头。

参数
  • data – 将被 JSON 序列化为响应主体的数据

  • status – HTTP 状态码

  • headers – 要设置在响应中的 HTTP 头

  • cookies – 要在客户端设置的 Cookie

not_found(description: str | None = None) → werkzeug.exceptions.NotFound[源代码]

HTTP 404 (未找到)响应的快捷方式

render(template: str, qcontext: dict | None = None, lazy: bool = True, **kw) → odoo.http.response.Response[源代码]

QWeb 模板的延迟渲染。

给定模板的实际渲染将在调度结束时进行。在此期间,模板和/或 qcontext 可以被修改,甚至可以被静态响应替换。

参数
  • template – 要渲染的模板

  • qcontext – 要使用的渲染上下文

  • lazy – 是否应将模板渲染推迟到最后可能的时刻

  • kw – 转发到 werkzeug 的 Response 对象

reroute(path: str | bytes, query_string=None) → None[源代码]

使用新的路径和查询字符串重写当前请求的 URL。这相当于轻量级重定向,不会向浏览器返回 3xx 响应,但会更改当前 URL。

class odoo.http.dispatcher.JsonRPCDispatcher(request)[源代码]
classmethod is_compatible_with(request)[源代码]

确定当前请求是否与此调度器兼容。

dispatch(endpoint, args)[源代码]

基于 HTTP 的 JSON-RPC 2 。

我们的实现与规范在两点上有所不同:

  1. JSON-RPC 请求负载中的 method 成员被忽略,因为 HTTP 路径已经用于将请求路由到控制器。

  2. 我们仅支持按名称传递参数结构,即 JSON-RPC 请求负载中的 params 成员必须是 JSON 对象,而不是 JSON 数组。

此外,可以通过特殊的 context 参数传递一个上下文,以替换会话上下文,该参数会在调用端点之前被移除。

成功请求示例:

--> {"jsonrpc": "2.0", "method": "call", "params": {"arg1": "val1" }, "id": null}

<-- {"jsonrpc": "2.0", "result": { "res1": "val1" }, "id": null}

产生错误的请求示例:

--> {"jsonrpc": "2.0", "method": "call", "params": {"arg1": "val1" }, "id": null}

<-- {"jsonrpc": "2.0", "error": {"code": 1, "message": "End user error message.", "data": {"code": "codestring", "debug": "traceback" } }, "id": null}
handle_error(exc)[源代码]

处理在将请求分派到 type='jsonrpc' 路由时发生的任何异常。还处理当没有路由匹配请求路径、无法提供回退页面且请求 Content-Type 为 json 时发生的异常。

参数

exc – 发生的异常。

返回

一个 WSGI 应用程序

class odoo.http.dispatcher.HttpDispatcher(request: Request)[源代码]
classmethod is_compatible_with(request)[源代码]

确定当前请求是否与此调度器兼容。

dispatch(endpoint, args)[源代码]

执行与 HTTP 相关的操作,例如反序列化请求体和查询字符串,并在将请求分发到 type='http' 路由时检查 CORS 和 CSRF。

有关兼容的端点返回类型的详细信息,请参阅 load() 方法。

handle_error(exc)[源代码]

处理在将请求分发到 type='http' 路由时发生的任何异常。还处理以下情况下的异常:没有匹配的路由路径、无法提供备用页面以及请求的 Content-Type 不是 JSON。

参数

exc (Exception) – 发生的异常。

返回

一个 WSGI 响应

响应

class odoo.http.Response(*args, **kwargs)[源代码]

带有正文、状态、头部和 QWeb 支持的传出 HTTP 响应。除了 werkzeug.wrappers.Response 的参数之外,此类的构造函数还可以接受以下用于 QWeb 延迟渲染的附加参数。

参数
  • template – 要渲染的模板

  • qcontext – 要使用的渲染上下文

  • uid – 用于 ir.ui.view 渲染调用的用户 id,None 表示使用请求的用户(默认值)

这些属性可作为 Response 对象的参数使用,并且可以在渲染之前的任何时候修改

同时公开 werkzeug.wrappers.Response 的所有属性和方法。

classmethod load(fname: str = '<function>') → odoo.http.response.Response[源代码]

将端点的返回值转换为 Response。

参数
  • result – 用于加载 Response 的端点返回值。

  • fname – 结果来源的端点函数名称,用于日志记录。

返回

创建的 Response。

引发

TypeError – 当 result 的类型不属于上述任何一种类型时。

render() → Any[源代码]

渲染 Response 的模板,并返回结果。

flatten() → None[源代码]

强制渲染响应的模板,将结果设置为响应正文,并取消设置 template

Werkzeug 中 expires 的默认值为 None,表示会话 cookie。我们希望继续支持会话 cookie,但不将其作为默认行为。现在的默认值是任意设定的 1 年。因此,如果您想要一个会话 cookie,必须显式传递 expires=None。

add_etag(overwrite: bool = False, weak: bool = False) → None[源代码]

如果当前响应还没有 etag,则为其添加一个。

在 2.0 版更改: 使用 SHA-1 生成该值。在某些环境中可能无法使用 MD5。

call_on_close(func: Callable[[], Any]) → Callable[[], Any][源代码]

将一个函数添加到内部函数列表中,这些函数会在关闭响应时被调用。自 0.7 起,该函数还会返回传入的函数,因此可以将其用作装饰器。

0.6 新版功能.

删除 cookie。如果键不存在,则静默失败。

参数
  • key – 要删除的 cookie 的键(名称)。

  • path – 如果要删除的 cookie 仅限于某个路径,则必须在此处定义该路径。

  • domain – 如果要删除的 cookie 仅限于某个域,则必须在此处定义该域。

  • secure – 如果为 True,则该 cookie 只能通过 HTTPS 使用。

  • httponly – 禁止 JavaScript 访问该 cookie。

  • samesite – 将 cookie 的作用域限制为仅附加到 “same-site” 的请求。

  • partitioned – 如果为 True,则该 cookie 将被分区存储。

classmethod force_type(environ: WSGIEnvironment | None = None) → Response[源代码]

强制要求 WSGI 响应是当前类型的响应对象。在许多情况下(例如异常),Werkzeug 会在内部使用 Response。如果在异常上调用 get_response(),即使您使用的是自定义子类,返回的也会是一个常规的 Response 对象。

此方法可以强制使用给定的响应类型;并且在提供 environ 时,还会将任意 WSGI 可调用对象转换为响应对象:

# convert a Werkzeug response object into an instance of the
# MyResponseClass subclass.
response = MyResponseClass.force_type(response)

# convert any WSGI application into a response object
response = MyResponseClass.force_type(response, environ)

如果您想在主调度器中对响应进行后处理,并使用子类提供的功能,这将特别有用。

请记住,如果可能,这将就地修改响应对象!

参数
  • response – 一个响应对象或 WSGI 应用程序。

  • environ – 一个 WSGI 环境对象。

返回

一个响应对象。

freeze() → None[源代码]

使响应对象准备好进行 pickle。执行以下操作:

  • 将响应缓冲到列表中,忽略 implicity_sequence_conversion 和 direct_passthrough。

  • 设置 Content-Length 头部。

  • 如果尚未设置 ETag 头部,则生成一个。

在 2.1 版更改: 移除了 no_etag 参数。

在 2.0 版更改: 始终会添加 ETag 头部。

在 0.6 版更改: Content-Length 头部会被设置。

get_data(as_text: bool = False) → bytes | str[源代码]

响应正文的字符串表示。每次访问此属性时,响应的可迭代对象都会被编码并展平。如果您流式传输大量数据,这可能会导致不期望的行为。

可以通过将 implicit_sequence_conversion 设置为 False 来禁用此行为。

如果 as_text 设置为 True,返回值将为解码后的字符串。

0.9 新版功能.

get_etag() → tuple[str, bool] | tuple[None, None][源代码]

返回形如 (etag, is_weak) 的元组。如果没有 ETag,返回值为 (None, None)。

get_json(force: bool = False, silent: bool = False) → Any | None[源代码]

将 data 解析为 JSON。在测试时很有用。

如果 mimetype 未指示 JSON(application/json,请参阅 is_json),则返回 None。

与 Request.get_json() 不同,结果不会被缓存。

参数
  • force – 忽略 mimetype,始终尝试解析 JSON。

  • silent – 忽略解析错误,改为返回 None。

iter_encoded() → Iterator[bytes][源代码]

以响应的编码对响应进行迭代。如果将响应对象作为 WSGI 应用程序调用,则此方法的返回值将用作应用程序迭代器,除非 direct_passthrough 已启用。

make_conditional(request_or_environ: WSGIEnvironment | Request, accept_ranges: bool | str = False, complete_length: int | None = None) → Response[源代码]

使响应相对于请求具有条件性。如果已为响应定义了 etag,此方法效果最佳。可以使用 add_etag 方法来完成此操作。如果在没有 etag 的情况下调用,则仅设置日期头部。

如果请求或 environ 中的请求方法不是 GET 或 HEAD,则此方法不执行任何操作。

为在处理范围请求时获得最佳性能,建议响应数据对象实现 seekable、seek 和 tell 方法,如 io.IOBase 所述。由 wrap_file() 返回的对象会自动实现这些方法。

它不会移除响应的正文,因为这是 __call__() 函数自动为我们完成的。

返回 self,以便您可以写 return resp.make_conditional(req),但会就地修改该对象。

参数
  • request_or_environ – 用于使响应有条件化的请求对象或 WSGI 环境。

  • accept_ranges – 此参数决定 Accept-Ranges 标头的值。如果为 False (默认),则不设置该标头。如果为 True,则将其设置为 "bytes"。如果它是字符串,则使用该值。

  • complete_length – 仅在有效的范围请求中使用。它将设置 Content-Range 的完整长度值,并计算 Content-Length 的实际值。此参数是成功完成范围请求的必备条件。

Raises

如果 Range 标头无法解析或无法满足,则抛出 RequestedRangeNotSatisfiable。

在 2.0 版更改: 如果长度为 0,则跳过范围处理,而不是抛出 416 Range Not Satisfiable 错误。

make_sequence() → None[源代码]

将响应迭代器转换为列表。默认情况下,如有需要会自动进行此转换。如果禁用了 implicit_sequence_conversion,则不会自动调用此方法,某些属性可能会抛出异常。这也会对所有项进行编码。

0.6 新版功能.

set_data(value: bytes | str) → None[源代码]

将新字符串设置为响应。该值必须是字符串或字节。如果设置的是字符串,会将其编码为响应的字符集(默认为 utf-8)。

0.9 新版功能.

set_etag(etag: str, weak: bool = False) → None[源代码]

设置 etag,如果已存在旧的 etag 则将其覆盖。