Django处理前端请求的流程梳理

news2024/11/14 2:47:51

初始

在前端请求到达 Django 应用时,首先到达的是 WSGI 接口(Web Server Gateway Interface)。WSGI 是 Python Web 应用和 Web 服务器之间的标准接口,Django 使用它来处理和响应 Web 请求。也就是首先会经过Django 项目中的 wsgi.py 文件

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'drf_learn.settings')

application = get_wsgi_application()

以上代码就是wsgi.py 文件, 在这里完成WSGIHandler的初始化。代码如下:

import django
from django.core.handlers.wsgi import WSGIHandler


def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Return a WSGI callable.

    Avoids making django.core.handlers.WSGIHandler a public API, in case the
    internal WSGI implementation changes or moves in the future.
    Django 的 WSGI 支持的公共接口。返回一个 WSGI 可调用对象。避免将 django.core.handlers.WSGIHandler 设为公共 API,
    以防内部 WSGI 实现在未来发生变化或移动。
    """
    django.setup(set_prefix=False)
    return WSGIHandler()

WSGIHandler类内部,实现了__call__方法,WSGI服务会调用__call__方法。方法如下:

    def __call__(self, environ, start_response):
        """

        :param environ: 一个包含所有请求信息的字典,由 WSGI 服务器传入。
        :param start_response: 一个回调函数,用于开始 HTTP 响应并设置响应状态和头信息
        :return:
        """
        #  # 设置脚本前缀
        # 设置请求的脚本前缀。get_script_name 从 environ 中获取请求的路径前缀(即当前应用的路径前缀,通常在部署在子路径下时有用)。
        # Django 使用 SCRIPT_NAME 环境变量设置脚本前缀,以正确地处理多路径部署情况。
        """
        在很多应用场景中,我们可能需要将一个 Django 应用部署到服务器的某个子路径下,而不是根路径。例如:

        假设你的主域名为 https://example.com
        你的 Django 应用部署在子路径 /myapp/ 下
        客户端访问你的 Django 应用的 URL 是 https://example.com/myapp/
        在这种情况下,Django 需要知道当前的子路径 (/myapp/),以便正确地解析和生成 URL。
        这就是 SCRIPT_NAME 的作用——它告诉 Django 请求的路径前缀是什么,以便应用在生成链接时知道要添加的子路径。
        """
        # get_script_name(environ):从 environ 中读取 SCRIPT_NAME 的值,获取当前请求的路径前缀。在上例中,这个值就是 "/myapp"。
        # set_script_prefix:设置 Django 全局的脚本前缀,使得后续请求中引用的所有 URL 都会以这个前缀开头。
        set_script_prefix(get_script_name(environ))


        # # 发送请求开始信号
        # 发送 request_started 信号,通知所有接收者一个新的请求即将开始。接收者可以是中间件或其他监听这个信号的函数。
        #         # 这在一些自定义逻辑中可能有用,例如日志记录或初始化特定的上下文变量,
        """
            signals.request_started:这是 Django 的 request_started 信号对象。
            send 方法:用于发送信号,触发所有连接到该信号的接收者。
            参数解释:
                sender=self.__class__:指定信号的发送者,这里是 WSGIHandler 类本身。这样接收者可以根据发送者来判断是否处理该信号。
                environ=environ:传递给接收者的附加信息,这里是 WSGI 的环境变量字典 environ,包含了请求的所有信息。
            常见的接收者:
                数据库连接管理:
                    Django 的数据库连接组件会监听 request_started 信号,以确保在请求开始时建立数据库连接,或者重置连接。
                缓存系统:
                    一些缓存机制可能需要在请求开始时进行清理或初始化。
                第三方应用程序:
                    一些中间件或应用程序可能需要在请求开始时执行特定的逻辑,如统计请求数量、日志记录等。
            意义:允许接收者在请求处理的早期阶段执行初始化操作,确保在请求处理过程中所需的资源和环境已准备就绪。
        """
        signals.request_started.send(sender=self.__class__, environ=environ)


        # # 创建 HttpRequest 对象 将 WSGI 的 environ 字典转换为 Django 的 HttpRequest 对象。
        #  这个 HttpRequest 对象包含了所有关于请求的信息(例如路径、请求头、请求方法等),供后续处理使用。
        request = self.request_class(environ)


        # # 获取响应 处理请求,返回 HttpResponse 对象
        """
            2.1 请求处理的核心方法
                self.get_response(request) 是 Django 中处理请求的核心方法,定义在 django.core.handlers.base.BaseHandler 类中。
                它负责从接收到的 HttpRequest 对象出发,经过一系列步骤,最终生成并返回 HttpResponse 对象。
            这个方法会调用 Django 的中间件和视图,处理请求并生成响应。具体步骤如下:
                请求预处理:调用中间件的 process_request 方法。
                URL 解析:根据请求的路径,解析出对应的视图函数或类。
                视图处理:调用视图函数或类,生成响应。
                异常处理:在视图处理过程中捕获异常,进行处理。
                请求后处理:调用中间件的 process_response 方法,对响应进行后续处理。
                返回响应:最终返回一个 HttpResponse 对象。
        """
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = "%d %s" % (response.status_code, response.reason_phrase)
        # 设置响应头
        response_headers = [
            *response.items(),
            *(("Set-Cookie", c.output(header="")) for c in response.cookies.values()),
        ]
        # 开始响应
        start_response(status, response_headers)
        if getattr(response, "file_to_stream", None) is not None and environ.get(
            "wsgi.file_wrapper"
        ):
            # If `wsgi.file_wrapper` is used the WSGI server does not call
            # .close on the response, but on the file wrapper. Patch it to use
            # response.close instead which takes care of closing all files.
            # 如果使用 'wsgi.file_wrapper',则 WSGI 服务器不会在响应上调用 .close,
            # 而是在文件包装器上调用 .close。将其修补为使用 response.close,它负责关闭所有文件。
            response.file_to_stream.close = response.close
            response = environ["wsgi.file_wrapper"](
                response.file_to_stream, response.block_size
            )
        # 返回相应内容
        return response

这个 __call__ 方法实现了 Django 的 WSGIHandler 的核心处理流程。以下是方法的详细流程分解:

__call__流程梳理

1. 设置脚本前缀

set_script_prefix(get_script_name(environ))
  • 作用:设置请求的脚本前缀,使 Django 能正确处理子路径的 URL。
  • 过程
    • get_script_name(environ)environ 中读取 SCRIPT_NAME 的值,获取当前请求的路径前缀(如 /myapp)。
    • set_script_prefix 设置 Django 的全局脚本前缀,以确保生成的 URL 都包含此路径。

2. 发送 request_started 信号

signals.request_started.send(sender=self.__class__, environ=environ)
  • 作用:发送 request_started 信号,通知所有接收者一个新的请求开始。
  • 过程:Django 的信号机制允许接收者在请求开始时执行一些初始化操作,如数据库连接管理、缓存清理、请求日志记录等。

3. 创建 HttpRequest 对象

request = self.request_class(environ)
  • 作用:将 environ 字典转换为 Django 的 HttpRequest 对象。
  • 过程request_class(通常是 HttpRequest 类)从 environ 中解析请求路径、请求头、请求方法等,创建包含所有请求信息的 HttpRequest 实例,供后续处理。

4. 获取响应

response = self.get_response(request)
  • 作用:核心请求处理步骤,调用 Django 的视图或中间件,最终生成 HttpResponse 对象。
  • 具体过程
    • 请求预处理:调用中间件的 process_request 方法。
    • URL 解析:根据请求的路径解析对应的视图函数。
    • 视图处理:执行视图函数或类,生成响应。
    • 异常处理:处理视图处理过程中的异常。
    • 请求后处理:调用中间件的 process_response 方法。
  • 返回值:生成并返回一个 HttpResponse 对象。

5. 设置响应状态码和响应头

status = "%d %s" % (response.status_code, response.reason_phrase)
response_headers = [
 *response.items(),
 *(("Set-Cookie", c.output(header="")) for c in response.cookies.values()),
]
start_response(status, response_headers)
  • 作用:构建并设置 HTTP 响应的状态和头部信息。
  • 过程
    • status:通过 response.status_coderesponse.reason_phrase 生成状态字符串(如 200 OK)。
    • response_headers:将响应头和 cookies 转换为 WSGI 标准的格式。
    • start_response:调用 start_response 回调函数,发送 HTTP 响应的状态和头部信息。

6. 文件流处理(可选)

if getattr(response, "file_to_stream", None) is not None and environ.get("wsgi.file_wrapper"):
 response.file_to_stream.close = response.close
 response = environ["wsgi.file_wrapper"](response.file_to_stream, response.block_size)
  • 作用:处理文件流响应。
  • 过程
    • 检查 file_to_stream 是否存在,若存在则调用 wsgi.file_wrapper,用它来包装文件流。
    • 修改 response.file_to_stream.closeresponse.close,确保关闭文件时调用 response.close

7. 返回响应内容

return response
  • 作用:将 HttpResponse 内容返回给 WSGI 服务器。
  • 结果:WSGI 服务器将响应传回给 Web 服务器,最终返回到前端。

总结

这个 __call__ 方法的流程如下:

  1. 设置脚本前缀:确保生成的 URL 包含子路径。
  2. 发送请求开始信号:通知监听者一个请求开始了。
  3. 创建请求对象:将 WSGI 的 environ 转为 Django 的 HttpRequest
  4. 获取响应:通过 Django 的中间件和视图生成 HttpResponse
  5. 设置响应状态码和头信息:调用 start_response 发送状态和头部信息。
  6. 文件流处理:使用 wsgi.file_wrapper 包装文件流(如有必要)。
  7. 返回响应:将最终响应返回给 WSGI 服务器。

整个过程将 WSGI 服务器的请求有效地转换成 Django 的响应,并返回给客户端。在这个过程中,response = self.get_response(request) 核心请求处理步骤,调用 Django 的视图或中间件,最终生成 HttpResponse 对象。接下来我们具体分析这个方法都做了什么。一下是该方法的代码。

def get_response(self, request):
    """Return an HttpResponse object for the given HttpRequest."""
    # Setup default url resolver for this thread
    # 配置当前线程使用的 URL 配置。Django 的函数,用于设置当前线程的 URL 配置模块。
    set_urlconf(settings.ROOT_URLCONF)
    # 将请求传递给中间件链进行处理,最终生成响应。
    response = self._middleware_chain(request)
    # 在响应对象中添加资源关闭器,以便在响应完成后关闭请求相关的资源。
    response._resource_closers.append(request.close)
    if response.status_code >= 400:
        log_response(
            "%s: %s",
            response.reason_phrase,
            request.path,
            response=response,
            request=request,
        )
        return response

在这个方法中,最最最关键的就是_middleware_chain属性,我们仅需深入的分析。这个属性实际上是一个BaseHandler类的一个属性,但是该属性在类中的load_middleware方法中,被赋值为一个hander,但是hander是一个方法。代码如下:

# Adapt the top of the stack, if needed.
handler = self.adapt_method_mode(is_async, handler, handler_is_async)
# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._middleware_chain = handler

所以,在get_response方法中,response = self._middleware_chain(request)就合理了。接下来我们详细的讲解load_middleware方法。

load_middleware 方法的主要流程是从项目设置中的 settings.MIDDLEWARE 列表中加载中间件,并将它们适配成一个链式处理流程(middleware chain),用于在请求生命周期中调用。以下是每个步骤的详细流程:

load_middleware流程梳理

1. 初始化中间件列表

self._view_middleware = []
self._template_response_middleware = []
self._exception_middleware = []
  • 解释:初始化空列表,用于存储不同类型的中间件方法:
    • self._view_middleware:存储带有 process_view 方法的中间件。
    • self._template_response_middleware:存储带有 process_template_response 方法的中间件。
    • self._exception_middleware:存储带有 process_exception 方法的中间件。
  • 作用:确保加载中间件前清空列表,避免重复添加。

2. 设置处理函数 get_responsehandler

get_response = self._get_response_async if is_async else self._get_response
handler = convert_exception_to_response(get_response)
  • 解释:根据是否异步,选择不同的响应处理方法。
    • convert_exception_to_response:装饰 get_response,捕获异常并将其转换为 HttpResponse 对象。
  • 作用:确保所有异常被捕获,并转换为标准的 HTTP 响应。

3. 逆序加载中间件

for middleware_path in reversed(settings.MIDDLEWARE):
    middleware = import_string(middleware_path)
  • 解释:通过 reversed() 方法逆序遍历 settings.MIDDLEWARE 列表。这样后添加的中间件会包裹先添加的中间件,确保请求生命周期中调用顺序正确。
  • 过程:使用 Django 的 import_string() 将字符串路径转换为中间件类。

4. 检查中间件的同步和异步支持

middleware_can_sync = getattr(middleware, "sync_capable", True)
middleware_can_async = getattr(middleware, "async_capable", False)
  • 解释:检查中间件是否支持同步或异步模式,默认值分别为 TrueFalse
  • 流程
    • 如果中间件既不支持同步也不支持异步,抛出异常。
    • 根据当前 handler 的模式(同步或异步)设置 middleware_is_async,确保中间件与当前模式兼容。

5. 适配 handler 方法

adapted_handler = self.adapt_method_mode(
    middleware_is_async, handler, handler_is_async, debug=settings.DEBUG, name="middleware %s" % middleware_path,
)
  • 解释:使用 self.adapt_method_mode 适配 handler 与中间件的模式(同步或异步),以保证兼容。
  • 作用:确保在异步环境下能够调用同步的中间件,或在同步环境下支持异步调用。

6. 创建中间件实例

mw_instance = middleware(adapted_handler)
  • 解释:创建中间件实例,并将适配后的 handler 传入。若实例创建失败或返回 None,则抛出配置错误 ImproperlyConfigured

7. 注册中间件方法

  • 检查并注册 process_view 方法

    if hasattr(mw_instance, "process_view"):
        self._view_middleware.insert(
            0,
            self.adapt_method_mode(is_async, mw_instance.process_view),
        )
    
    • 解释:若中间件实例包含 process_view 方法,将其插入 self._view_middleware 的开头。
    • 作用:确保请求处理时,按逆序调用 process_view
  • 检查并注册 process_template_response 方法

    if hasattr(mw_instance, "process_template_response"):
        self._template_response_middleware.append(
            self.adapt_method_mode(
                is_async, mw_instance.process_template_response
            ),
        )
    
    • 解释:若中间件包含 process_template_response 方法,将其添加到 self._template_response_middleware 列表。
  • 检查并注册 process_exception 方法

    if hasattr(mw_instance, "process_exception"):
        self._exception_middleware.append(
            self.adapt_method_mode(False, mw_instance.process_exception),
        )
    
    • 解释:若中间件包含 process_exception 方法,将其适配为同步模式并添加到 self._exception_middleware 列表。

8. 更新 handler 并处理异常

handler = convert_exception_to_response(mw_instance)
handler_is_async = middleware_is_async
  • 解释:将新的 mw_instance 包装为 handler,将异常捕获并转换为响应。根据中间件是否异步,更新 handler_is_async

9. 顶部适配 handler 方法

handler = self.adapt_method_mode(is_async, handler, handler_is_async)
self._middleware_chain = handler
  • 解释:最终对整个中间件链进行适配,以匹配当前模式(同步或异步)。
  • 作用:生成完整的中间件链 _middleware_chain,完成中间件的加载过程。

总结流程

  1. 初始化三个中间件列表以存储不同类型的中间件方法。
  2. 根据请求的同步或异步模式,选择合适的 get_response 处理方法。
  3. 逆序遍历 settings.MIDDLEWARE 列表并逐个加载中间件。
  4. 检查每个中间件是否支持同步或异步模式,并适配相应的 handler
  5. 将中间件中的特定方法(如 process_viewprocess_template_responseprocess_exception)添加到各自列表中。
  6. 最后生成并保存完整的中间件链 _middleware_chain

通过这些步骤,Django 可以构建一个完整的中间件链,用于处理请求的各个阶段,并捕获和处理其中的异常。在这一部分中,是有优先处理中间件,中间件处理完后才处理的请求。最最最最关键的地方在_get_response,在这个方法中解决并调用视图,然后应用 view、exception 和 template_response 中间件。此方法是 requestresponse 中间件中发生的一切。代码如下:

    def _get_response(self, request):
        """
        Resolve and call the view, then apply view, exception, and
        template_response middleware. This method is everything that happens
        inside the request/response middleware.
        解决并调用视图,然后应用 view、exception 和 template_response 中间件。此方法是 requestresponse 中间件中发生的一切。
        """
        response = None
        # 通过 resolve_request 方法,根据请求解析出对应的视图函数 callback,以及视图函数需要的参数 callback_args 和关键字参数 callback_kwargs。
        callback, callback_args, callback_kwargs = self.resolve_request(request)

        # Apply view middleware
        for middleware_method in self._view_middleware:
            response = middleware_method(
                request, callback, callback_args, callback_kwargs
            )
            if response:
                break

        if response is None:
            wrapped_callback = self.make_view_atomic(callback)
            # If it is an asynchronous view, run it in a subthread.
            # 如果它是一个异步视图,请在子线程中运行它。
            if iscoroutinefunction(wrapped_callback):
                wrapped_callback = async_to_sync(wrapped_callback)
            try:
                response = wrapped_callback(request, *callback_args, **callback_kwargs)
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise

        # Complain if the view returned None (a common error).
        self.check_response(response, callback)

        # If the response supports deferred rendering, apply template
        # response middleware and then render the response
        if hasattr(response, "render") and callable(response.render):
            for middleware_method in self._template_response_middleware:
                response = middleware_method(request, response)
                # Complain if the template response middleware returned None
                # (a common error).
                self.check_response(
                    response,
                    middleware_method,
                    name="%s.process_template_response"
                    % (middleware_method.__self__.__class__.__name__,),
                )
            try:
                response = response.render()
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise

        return response

_get_response方法流程处理

1. _get_response方法

_get_response方法中,Django开始解析请求的URL,并找到对应的视图函数(或视图类)。具体步骤如下:

def _get_response(self, request):
    response = None
    # 解析请求,获取对应的视图函数和参数
    callback, callback_args, callback_kwargs = self.resolve_request(request)

    # 应用视图中间件
    for middleware_method in self._view_middleware:
        response = middleware_method(request, callback, callback_args, callback_kwargs)
        if response:
            break

    if response is None:
        wrapped_callback = self.make_view_atomic(callback)
        # 如果视图函数是异步的,则转换为同步函数
        if iscoroutinefunction(wrapped_callback):
            wrapped_callback = async_to_sync(wrapped_callback)
        try:
            # 调用视图函数,获取响应
            response = wrapped_callback(request, *callback_args, **callback_kwargs)
        except Exception as e:
            # 处理异常
            response = self.process_exception_by_middleware(e, request)
            if response is None:
                raise
    ...
    return response

2.resolve_request方法

resolve_request方法通过请求的URL,使用URL解析器ResolverMatch找到对应的视图函数(callback)、位置参数(callback_args)和关键字参数(callback_kwargs)。

def resolve_request(self, request):
    urlconf = getattr(request, 'urlconf', None)
    set_urlconf(urlconf)
    resolver = get_resolver(urlconf)
    resolver_match = resolver.resolve(request.path_info)
    request.resolver_match = resolver_match
    return resolver_match.func, resolver_match.args, resolver_match.kwargs

在这里,resolver.resolve(request.path_info)会根据urls.py中定义的URL模式,匹配请求的路径,返回一个ResolverMatch对象,其中包含了视图函数。

3 获取视图函数

对于基于类的视图(Class-Based Views,CBV),在urls.py中,我们通常这样定义:

from django.urls import path
from .views import MyView

urlpatterns = [
    path('my-url/', MyView.as_view(), name='my_view'),
]

这里的MyView.as_view()会返回一个视图函数,这个函数就是callback

4. 调用视图函数

回到_get_response方法,当我们获取到callback后,经过视图中间件的处理(如果有的话),我们会调用wrapped_callback,也就是视图函数。

response = wrapped_callback(request, *callback_args, **callback_kwargs)

5. as_view方法的作用

现在,我们需要深入了解as_view方法是如何将请求处理到视图类的。

@classmethod
def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
        # 创建视图类的实例
        self = cls(**initkwargs)
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        # 调用dispatch方法
        return self.dispatch(request, *args, **kwargs)

    view.view_class = cls
    view.view_initkwargs = initkwargs
    # 复制一些元数据信息
    view.__doc__ = cls.__doc__
    view.__module__ = cls.__module__
    view.__annotations__ = cls.dispatch.__annotations__
    view.__dict__.update(cls.dispatch.__dict__)

    # 如果视图类是异步的,标记为协程函数
    if cls.view_is_async:
        markcoroutinefunction(view)

    return view
5.1 as_view返回视图函数

as_view方法是基于类的视图的入口。它是一个类方法,返回一个视图函数view。当Django的URL解析器解析到这个视图时,实际上获取到的就是这个view函数。

5.2 视图函数view的执行流程

view函数被调用时,会执行以下步骤:

  1. 实例化视图类self = cls(**initkwargs),这里的cls就是视图类本身。
  2. 设置请求和参数self.setup(request, *args, **kwargs),这个方法将request和其他参数绑定到视图实例上。
  3. 调用dispatch方法return self.dispatch(request, *args, **kwargs)dispatch方法根据请求的HTTP方法(如GET、POST)分发到对应的处理方法(如getpost)。

6. 视图类的dispatch方法

dispatch方法是处理请求的核心,它会根据请求的方法名,调用视图类中对应的方法。

def dispatch(self, request, *args, **kwargs):
    # 如果视图类有特定的http_method_names,例如['get', 'post']
    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

最终通过handler(request, *args, **kwargs)调用的views.py文件中的get方法,

from rest_framework.response import Response
from rest_framework.views import APIView


class HelloWorldView(APIView):
    def get(self, request):
        return Response({"message": "Hello World!"})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2238472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux网络的基本设置

1、查看网络接口信息 ip a/ip addr #简略的查看网络接口信息 ifconfig #只显示当前活跃的设备 ifconfig -a #实现当前主机的所有网络设备&#xff0c;包括未运行的设备 rootubuntu1:~# ifconfig ens33:flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 设备名…

利用AI制作《职业生涯规划PPT》,10分钟完成

职业生涯规划是大学生活中非常重要的一环。通过制定职业规划&#xff0c;你能够明确未来的职业目标、认清自身的优劣势&#xff0c;进而制定切实可行的计划&#xff0c;以便顺利踏上职业发展的道路。而制作一份精美的职业生涯规划PPT&#xff0c;能有效帮助你在面试、职业规划报…

【数据结构与算法】希尔排序(直接插入排序)

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 引言 一.直接插入排序的基本思想 二. 直接插入排序算法解析 详细版本的算法思想解析 算法思想提炼 实现代码 画图刨析 三. 直接插入排序的特性 复杂度分析 稳定性分析 四. 希尔排序的基本思想 五. 希尔排序算法解…

RK3568 Android12跳过认证 预置谷歌服务GMS

在Rom开发中需要发布海外版本时基本都需要内置google服务,而规范方式集成的话都需要设备进行认证,获取google应用签名等非常复杂的一套流程,一般大厂才有这些资质和资源,这里介绍一种非常规方式集成GMS,跳过设置认证流程,在RK3568 android12环境亲测有效。 谷歌全家桶中…

深度学习之卷积问题

1 卷积在图像中有什么直观作用 ​ 在卷积神经网络中&#xff0c;卷积常用来提取图像的特征&#xff0c;但不同层次的卷积操作提取到的特征类型是不相同的&#xff0c;特征类型粗分如表1所示。 ​ 表1 卷积提取的特征类型 卷积层次特征类型浅层卷积边缘特征中层卷积局部特征深…

Go语言的内置容器

文章目录 一、数组数组的定义数组声明数组特点数组元素修改 二、切片切片声明基于数组创建切片使用make()函数构造切片使用append()为切片动态添加元素\使用copy()复制新的切片数组与切片相互转换 三、Map映射Map定义使用make()函数创建map用切片作为map的值使用delete()函数删…

二叉树的各种操作补充

二叉树的各种操作补充 求二叉树的结点数求二叉树的叶结点数求二叉树的高度求二叉树的第k层结点数查找指定结点层序遍历判断二叉树是否是完全二叉树 我们任然沿用二叉树的基本信息&#xff1a; typedef char BTDataType; typedef struct BinaryTreeNode {BTDataType _data;struc…

Go语言的常用内置函数

文章目录 一、Strings包字符串处理包定义Strings包的基本用法Strconv包中常用函数 二、Time包三、Math包math包概述使用math包 四、随机数包&#xff08;rand&#xff09; 一、Strings包 字符串处理包定义 Strings包简介&#xff1a; 一般编程语言包含的字符串处理库功能区别…

Perfetto中如何使用SQL语句

在使用 Perfetto 分析 Android 性能时&#xff0c;可以通过 Perfetto 提供的内置 SQL 查询来提取和分析不同的性能数据。Perfetto 允许你在 UI 界面或命令行中运行 SQL 查询&#xff0c;提取出 Trace 数据中包含的各种性能信息&#xff0c;比如 CPU 使用率、线程状态、内存分配…

QML项目实战:自定义TextField

目录 一.添加模块 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.15 二.自定义TextField 1.属性设置 2.输入框设置 3.按钮开关 三.效果 1.readonly为false 2.readonly为true 四.代码 一.添加模块 import QtQuick.…

【进阶】Stable Diffusion 插件 Controlnet 安装使用教程(图像精准控制)

Stable Diffusion WebUI 的绘画插件 Controlnet 最近更新了 V1.1 版本&#xff0c;发布了 14 个优化模型&#xff0c;并新增了多个预处理器&#xff0c;让它的功能比之前更加好用了&#xff0c;最近几天又连续更新了 3 个新 Reference 预处理器&#xff0c;可以直接根据图像生产…

DAF-FM DA与NO反应后,生成的产物能够发出强烈的绿色荧光,254109-22-3

一、基本信息 产品名称&#xff1a;DAF-FM DA&#xff08;一氧化氮NO荧光探针DAF-FM&#xff09; 英文名称&#xff1a;DAF-FM DA&#xff0c;DAF-FM diacetate CAS号&#xff1a;254109-22-3 分子式&#xff1a;C25H18F2N2O7 供应商&#xff1a;陕西新研博美生物科技 分…

在 Mac 和 Windows 系统中快速部署 OceanBase

OceanBase 是一款分布式数据库&#xff0c;具备出色的性能和高扩展性&#xff0c;可以为企业用户构建稳定可靠、灵活扩展性能的数据库服务。本文以开发者们普遍熟悉的Windows 或 Mac 环境为例&#xff0c;介绍如何快速上手并体验OceanBase。 一、环境准备 1. 硬件准备 OceanB…

使用Ant Design的Layout布局不能撑满整个屏幕问题解决方法

代码示例&#xff1a; import React, { useState } from react import {LaptopOutlined,NotificationOutlined,UserOutlined, } from ant-design/icons import type { MenuProps } from antd import { Layout, Menu, theme } from antd import routes from ./routes/index imp…

【ubuntu18.04】使用U盘制作ubuntu18.04启动盘操作说明

打开show application 打开Startup Disk 选择镜像 双击选择ubuntu的iso镜像 镜像下载地址 Ubuntu 18.04.6 LTS (Bionic Beaver) 制作镜像 注意&#xff1a; 制作镜像会格式化U盘&#xff0c;记得备份资料 点击Make Startup Disk,弹出如下对话框 点击Yes 输入管理员密码&a…

22.04Ubuntu---ROS2创建python节点

创建工作空间 mkdir -p 02_ros_ws/src 然后cd到该目录 创建功能包 在这条命令里&#xff0c;tom就是你的功能包 ros2 pkg create tom --build-type ament_python --dependencies rclpy 可以看到tom功能包已经被创建成功了。 使用tree命令&#xff0c;得到如下文件结构 此时…

《手写Spring渐进式源码实践》实践笔记(第十七章 数据类型转换)

文章目录 第十七章 数据类型转换工厂设计实现背景技术背景Spring数据转换实现方式类型转换器&#xff08;Converter&#xff09;接口设计实现 业务背景 目标设计实现代码结构类图实现步骤 测试事先准备属性配置文件转换器工厂Bean测试用例测试结果&#xff1a; 总结 第十七章 数…

使用docker形式部署jumpserver

文章目录 前言一、背景二、使用步骤1.基础环境准备2.拉取镜像3.进行部署4.备份记录启动命令 前言 记录一下使用docker形式部署jumpserver服务的 一、背景 搭建一个jumpserver的堡垒机&#xff0c;但是发现之前是二进制文件部署的&#xff0c;会在物理机上部署污染环境&#x…

(62)使用RLS自适应滤波器进行系统辨识的MATLAB仿真

文章目录 前言一、基本概念二、RLS算法原理三、RLS算法的典型应用场景四、MATLAB仿真代码五、仿真结果1.滤波器的输入信号、参考信号、输出信号、误差信号2.对未知系统进行辨识得到的系数 总结与后续 前言 RLS&#xff08;递归最小二乘&#xff09;自适应滤波器是一种用于系统…

算法每日双题精讲——滑动窗口(长度最小的子数组,无重复字符的最长子串)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…