flask详解-app.py(2)

def update_template_context(self, context: dict[str, t.Any]) -> None:
    """Update the template context with some commonly used variables.
    This injects request, session, config and g into the template
    context as well as everything template context processors want
    to inject.  Note that the as of Flask 0.6, the original values
    in the context will not be overridden if a context processor
    decides to return a value with the same key.

    :param context: the context as a dictionary that is updated in place
                    to add extra variables.
    """
    names: t.Iterable[str | None] = (None,)

    # A template may be rendered outside a request context.
    if request:
        names = chain(names, reversed(request.blueprints))

    # The values passed to render_template take precedence. Keep a
    # copy to re-apply after all context functions.
    orig_ctx = context.copy()

    for name in names:
        if name in self.template_context_processors:
            for func in self.template_context_processors[name]:
                context.update(self.ensure_sync(func)())

    context.update(orig_ctx)

这个方法用于更新模板上下文。

1.方法定义:

def update_template_context(self, context: dict[str, t.Any]) -> None:

这是一个名为 update_template_context 的方法,它接受一个字典 context 作为参数,该字典包含模板的上下文。方法没有返回值(返回 None)。
2.  处理蓝图:

names: t.Iterable[str | None] = (None,) 
if request: 

    names = chain(names, reversed(request.blueprints))

这部分代码处理蓝图(blueprints)。蓝图是 Flask 中用于组织大型应用的一种结构,它允许你将应用拆分成多个部分(或蓝图),每个部分可以有自己的路由、模板、静态文件等。request.blueprints 是一个包含当前请求相关的所有蓝图的列表。
5. 保存原始上下文:

orig_ctx = context.copy()

在更新上下文之前,先保存原始上下文的副本。这是为了确保原始值不会被覆盖,除非一个上下文处理器决定返回具有相同键的值。
6. 应用上下文处理器:

for name in names:  
    if name in self.template_context_processors:  
        for func in self.template_context_processors[name]:  

            context.update(self.ensure_sync(func)())

这部分代码遍历 names 列表(包括蓝图和默认的 None 值),并查找每个名称对应的上下文处理器函数。这些函数会返回一个新的字典,该字典会更新到 context 中。self.ensure_sync(func)() 确保函数是同步执行的。
7. 恢复原始上下文:

context.update(orig_ctx)

最后,使用之前保存的原始上下文 orig_ctx 更新 context。这确保了传递给 render_template 的值具有优先权,即使它们与上下文处理器的返回值有相同的键。

总的来说,这个方法的目的是扩展模板的上下文,使其包含更多的有用变量,但同时又确保传递给 render_template 的原始值不会被意外覆盖。

    def make_shell_context(self) -> dict[str, t.Any]:
        rv = {"app": self, "g": g}
        for processor in self.shell_context_processors:
            rv.update(processor())
        return rv

    def run(
        self,
        host: str | None = None,
        port: int | None = None,
        debug: bool | None = None,
        load_dotenv: bool = True,
        **options: t.Any,
    ) -> None:
        if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
            if not is_running_from_reloader():
                click.secho(
                    " * Ignoring a call to 'app.run()' that would block"
                    " the current 'flask' CLI command.\n"
                    "   Only call 'app.run()' in an 'if __name__ =="
                    ' "__main__"\' guard.',
                    fg="red",
                )

            return

        if get_load_dotenv(load_dotenv):
            cli.load_dotenv()

            if "FLASK_DEBUG" in os.environ:
                self.debug = get_debug_flag()

        if debug is not None:
            self.debug = bool(debug)

        server_name = self.config.get("SERVER_NAME")
        sn_host = sn_port = None

        if server_name:
            sn_host, _, sn_port = server_name.partition(":")

        if not host:
            if sn_host:
                host = sn_host
            else:
                host = "127.0.0.1"

        if port or port == 0:
            port = int(port)
        elif sn_port:
            port = int(sn_port)
        else:
            port = 5000

        options.setdefault("use_reloader", self.debug)
        options.setdefault("use_debugger", self.debug)
        options.setdefault("threaded", True)

        cli.show_server_banner(self.debug, self.name)

        from werkzeug.serving import run_simple

        try:
            run_simple(t.cast(str, host), port, self, **options)
        finally:
            self._got_first_request = False

以上是Flask框架的两个方法:make_shell_context 和 run。
1. make_shell_context 方法
创建一个用于 Flask shell 环境的上下文字典rv,其中包含两个键值对:app 指向当前 Flask 应用实例,g 指向 Flask 的全局对象 g。遍历 self.shell_context_processors 中的每一个上下文处理器函数,并调用它们。这些函数通常返回一个字典,该字典包含想要在 Flask shell 中可用的额外变量。使用 rv.update(processor()) 更新 rv 字典,以包含来自上下文处理器的所有变量,返回最终的 rv 字典,这个字典可以在 Flask shell 中作为上下文使用。

2. run 方法
启动 Flask 应用的内建开发服务器。
首先,该方法检查环境变量FLASK_RUN_FROM_CLI是否为true,以及是否从重加载器(reloader)中运行。如果是,并且不是从重加载器调用,则显示一个警告,并返回,以避免阻塞当前的 Flask CLI 命令。
如果 load_dotenv 为 True,则加载 .env 文件中的环境变量。如果 FLASK_DEBUG 环境变量存在,则设置应用的 debug 属性。
如果 debug 参数被明确传递,则设置应用的 debug 属性为传递的值。
接下来,该方法确定应用运行的 host 和 port。如果它们没有被显式传递,则使用 SERVER_NAME 配置或默认值。
使用 options.setdefault为一些默认选项设置值,如是否使用重加载器、是否使用调试器以及是否使用多线程。
调用 Werkzeug 的 run_simple 函数来启动开发服务器。
在 try-finally 块中运行服务器,确保在服务器停止时重置 _got_first_request 属性。
g 是 Flask 提供的一个全局对象,可以在请求处理过程中存储和访问数据。
Werkzeug 是 Flask 底层使用的 WSGI 工具包,run_simple 是 Werkzeug 提供的一个简单的 WSGI 服务器实现。
Flask CLI 是 Flask 的命令行界面,它提供了许多有用的命令,如运行应用、生成脚手架代码等。
这两个方法共同为 Flask 应用提供了运行和扩展功能的能力,使其更加灵活和易用。

def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient:
        cls = self.test_client_class
        if cls is None:
            from .testing import FlaskClient as cls
        return cls(  # type: ignore
            self, self.response_class, use_cookies=use_cookies, **kwargs
        )

def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner:
    cls = self.test_cli_runner_class

    if cls is None:
        from .testing import FlaskCliRunner as cls

    return cls(self, **kwargs)  # type: ignore

这两个方法用于创建测试客户端和 CLI 运行器,它们为开发者提供了在测试中模拟 HTTP 请求和运行 CLI 命令的能力,从而帮助开发者验证应用的功能和正确性。
1. test_client 方法
创建一个 Flask 测试客户端实例。self 指的是 Flask 应用实例。use_cookies 参数决定是否使用 cookies(默认为 True)。**kwargs 允许传递其他关键字参数到测试客户端的构造函数中。self.test_client_class 是 Flask 应用实例的一个属性,用于指定用于创建测试客户端的类。如果此属性为 None,则默认使用 Flask 框架提供的 FlaskClient 类。该方法返回一个新的 FlaskClient 实例,用于模拟发送 HTTP 请求到 Flask 应用。测试客户端在 Flask 应用开发中非常有用,因为它允许开发者模拟客户端发送的请求并测试应用的响应,而无需启动一个完整的 web 服务器。
2. test_cli_runner 方法
创建一个 Flask CLI 运行器实例。self 同样是 Flask 应用实例。**kwargs 允许传递其他关键字参数到 CLI 运行器的构造函数中。self.test_cli_runner_class 是 Flask 应用实例的一个属性,用于指定用于创建 CLI 运行器的类。如果此属性为 None,则默认使用 Flask 框架提供的 FlaskCliRunner 类。该方法返回一个新的 FlaskCliRunner 实例,用于在测试中运行 Flask CLI 命令。CLI 运行器使得开发者能够在测试中运行 Flask 的命令行接口命令,从而验证命令的功能和输出。这在编写 CLI 相关功能的测试时非常有用。

    def handle_http_exception(
        self, e: HTTPException
    ) -> HTTPException | ft.ResponseReturnValue:
        if e.code is None:
            return e

        if isinstance(e, RoutingException):
            return e

        handler = self._find_error_handler(e, request.blueprints)
        if handler is None:
            return e
        return self.ensure_sync(handler)(e)  # type: ignore[no-any-return]

    def handle_user_exception(
        self, e: Exception
    ) -> HTTPException | ft.ResponseReturnValue:
        if isinstance(e, BadRequestKeyError) and (
            self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]
        ):
            e.show_exception = True

        if isinstance(e, HTTPException) and not self.trap_http_exception(e):
            return self.handle_http_exception(e)

        handler = self._find_error_handler(e, request.blueprints)

        if handler is None:
            raise

        return self.ensure_sync(handler)(e)  # type: ignore[no-any-return]

这两个方法是 Flask 框架中处理异常的部分,它们负责找到适当的错误处理器来处理发生的异常,或者在没有找到处理器的情况下采取默认行为(返回异常对象或重新抛出异常)。这样做可以让开发者更加灵活地处理应用中可能发生的各种错误情况。
1. handle_http_exception 方法
这个方法处理的是 HTTPException 类型的异常。HTTPException 通常表示一个与 HTTP 请求相关的错误,比如 404 Not Found 或 500 Internal Server Error。如果异常 e 的 code 属性为 None,则直接返回异常对象 e。如果异常 e 是 RoutingException 类型,则也直接返回异常对象e。接下来,它尝试找到一个错误处理器(error handler)来处理这个异常。错误处理器是在 Flask应用中定义的用于处理特定类型的错误的函数。如果找到了这样的处理器,就使用它来处理异常,并返回处理结果。如果没有找到错误处理器,就返回原始的异常对象 e。

2. handle_user_exception 方法

这个方法处理的是用户自定义的异常,即非 HTTPException 类型的异常。首先,它检查异常 e 是否是 BadRequestKeyError 类型,并且应用是在调试模式或配置中设置了 TRAP_BAD_REQUEST_ERRORS。如果是,就将 show_exception 设置为 True,意味着将显示详细的异常信息。接着,如果异常 e 实际上是 HTTPException 类型,并且不应该被捕获(由 trap_http_exception(e) 判断),那么就调用 handle_http_exception(e) 来处理它。然后,和 handle_http_exception 方法类似,它尝试找到一个错误处理器来处理这个异常。如果找到了,就使用错误处理器来处理异常,并返回处理结果。如果没有找到错误处理器,就重新抛出该异常。

    def handle_exception(self, e: Exception) -> Response:
        exc_info = sys.exc_info()
        got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e)
        propagate = self.config["PROPAGATE_EXCEPTIONS"]

        if propagate is None:
            propagate = self.testing or self.debug

        if propagate:
            # Re-raise if called with an active exception, otherwise
            # raise the passed in exception.
            if exc_info[1] is e:
                raise

            raise e

        self.log_exception(exc_info)
        server_error: InternalServerError | ft.ResponseReturnValue
        server_error = InternalServerError(original_exception=e)
        handler = self._find_error_handler(server_error, request.blueprints)

        if handler is not None:
            server_error = self.ensure_sync(handler)(server_error)

        return self.finalize_request(server_error, from_error_handler=True)

    def log_exception(
        self,
        exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]),
    ) -> None:
        """Logs an exception.  This is called by :meth:`handle_exception`
        if debugging is disabled and right before the handler is called.
        The default implementation logs the exception as error on the
        :attr:`logger`.

        .. versionadded:: 0.8
        """
        self.logger.error(
            f"Exception on {request.path} [{request.method}]", exc_info=exc_info
        )

handle_exception和log_exception是Flask框架中处理应用异常的重要部分。通过这两个方法,Flask 框架为开发者提供了一个灵活且强大的异常处理机制。开发者可以定义自己的错误处理器来处理特定的异常类型,同时 Flask 框架也会确保异常的日志记录,以便后续分析和调试.
1. handle_exception 方法
这个方法是 Flask 应用用来处理所有非 HTTP 异常的主要方法。当 Flask 应用中发生异常时,这个方法会被调用。exc_info:获取当前的异常信息。got_request_exception.send(...):发送一个信号,通知其他监听者有一个请求异常发生。
propagate:是否应该传播异常。它首先从配置中获取,如果没有配置,则默认为在测试模式或调试模式下传播异常。如果 propagate 为 True,则重新抛出异常,除非当前的异常是传入的 e。如果不传播异常,则记录异常(通过调用 log_exception 方法)并创建一个 InternalServerError 对象。
接下来,查找是否有为这个异常定义的错误处理器。如果有,使用处理器处理异常。最后,返回处理后的响应,或者如果没有处理器,返回原始的 InternalServerError 响应。
2. log_exception 方法
这个方法用于记录异常信息。当 Flask 应用中发生异常且 handle_exception 方法决定不传播异常时,这个方法会被调用。 exc_info:包含异常类型、异常实例和跟踪回溯信息的元组。使用 Flask应用的日志记录器(logger)来记录异常信息。日志的级别是错误(error),并包含请求的路径和方法,以及 exc_info 以提供详细的异常跟踪信息。

    def dispatch_request(self) -> ft.ResponseReturnValue:
        req = request_ctx.request
        if req.routing_exception is not None:
            self.raise_routing_exception(req)
        rule: Rule = req.url_rule  # type: ignore[assignment]
        if (
            getattr(rule, "provide_automatic_options", False)
            and req.method == "OPTIONS"
        ):
            return self.make_default_options_response()
        view_args: dict[str, t.Any] = req.view_args  # type: ignore[assignment]
        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]

    def full_dispatch_request(self) -> Response:
        self._got_first_request = True

        try:
            request_started.send(self, _async_wrapper=self.ensure_sync)
            rv = self.preprocess_request()
            if rv is None:
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        return self.finalize_request(rv)

    def finalize_request(
        self,
        rv: ft.ResponseReturnValue | HTTPException,
        from_error_handler: bool = False,
    ) -> Response:
        response = self.make_response(rv)
        try:
            response = self.process_response(response)
            request_finished.send(
                self, _async_wrapper=self.ensure_sync, response=response
            )
        except Exception:
            if not from_error_handler:
                raise
            self.logger.exception(
                "Request finalizing failed with an error while handling an error"
            )
        return response

    def make_default_options_response(self) -> Response:
        adapter = request_ctx.url_adapter
        methods = adapter.allowed_methods()  # type: ignore[union-attr]
        rv = self.response_class()
        rv.allow.update(methods)
        return rv

这段代码是Flask 框架中处理请求的核心部分,是 Flask 框架处理 HTTP 请求的核心组件,它们共同工作以确保请求被正确路由、处理,并最终返回适当的响应。
1. dispatch_request 方法
这个方法根据请求的 URL规则(url_rule)找到对应的视图函数(view_function),并调用该函数来处理请求。如果请求有路由异常(routing_exception),则抛出该异常。如果规则支持自动提供 OPTIONS 方法(例如,为了 CORS),并且请求方法是OPTIONS,则返回一个默认的 OPTIONS 响应。否则,根据 URL 规则的端点(endpoint)查找视图函数,并使用请求中的视图参数(view_args)调用该函数。

2. full_dispatch_request 方法
这个方法是对请求进行完整处理的入口点。设置 _got_first_request 标志为 True,表示已经收到了第一个请求。发送 request_started 信号,通知其他监听者请求已经开始。调用 preprocess_request 方法进行请求预处理。如果预处理没有返回任何值,则调用 dispatch_request 来实际处理请求。如果在处理过程中发生异常,则调用 handle_user_exception 来处理该异常。最后,调用 finalize_request 来准备并返回最终的响应。

3. finalize_request 方法
这个方法用于准备最终的响应。调用 make_response 将视图函数返回的结果转换为响应对象。调用 process_response 对响应对象进行后处理。发送 request_finished 信号,通知其他监听者请求已经完成。如果在处理响应时发生异常,并且不是从错误处理器中抛出的,则重新抛出该异常;否则,记录异常信息。返回处理后的响应对象。

4. make_default_options_response 方法
这个方法用于生成一个默认的 OPTIONS 响应,通常用于处理 CORS(跨源资源共享)预检请求。获取请求的 URL 适配器。   使用适配器获取允许的方法列表。创建一个响应对象,并更新其 Allow 头部,包含允许的方法,返回该响应对象。

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值