DRF从入门到精通五(路由组件、认证组件、权限组件、频率组件及认证、权限源码分析)

文章目录

  • 一、路由组件
    • REST framework提供了两个router
    • action装饰器
  • 二、认证组件(Authentication)
  • 三、权限组件(Permissions)
    • 内置权限类
  • 四、频率组件(Throttling)
  • 五、权限组件源码分析
  • 六、认证组件源码分析

一、路由组件

对于视图集ViewSetMixin,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

也就是通过路由组件帮助我们自动生成路由,它会根据URL及请求匹配对应的视图方法,而这些方法则是来自视图集,如果我们需要自定义方法来处理请求的话,后续可以搭配action装饰器实现。

SimpleRouter为每个URL添加一个斜杠后缀,可以在初始化的时候提供trailing_slash参数,并设置为False

创建router对象,并注册视图集

	'导入'from rest_framework.routers import SimpleRouter,DefaultRouter'导入的模块不是继承就是实例化'router = SimpleRouter() 或者DefaultRouter()  # 创建对象'''DefaultRouter会生成一个根路径/的配置项DefaultRouter生成的每个配置项后都可以跟上.json,直接返回json数据还可以显示注册过的路由以及美化的页面SimpleRouter和DefaultRouter用法一致,功能几乎一样''''注册路径,可以注册多个'router.register('publish',views.PublishView)  # 注册路由,并选择视图函数'注册:第一个参数是路径,第二个参数为视图类,第三个参数起别名用得少所有这里没用'urlpatterns = []'把生成的路由添加到urlpatterns路由列表中,有两种方式:'# 将生成的路由加入到Django需要调用的路由列表内'方式一:直接添加+='urlpatterns += router.urls'方式二:直接添加到urlpatterns里面使用include'from django.urls import path,includeurlpatterns = [path('',include(router.urls))]

def register(self, prefix, viewset, basename=None):

注册参数说明:

  • prefix:路由的前缀
  • viewset:视图集(内部必须继承了ViewSetMixin类)
  • basename:路由的别名

上序代码会生成如下路由:

	path('publish/',views.PublishView.as_view()),path('publish/<int:pk>',views.PublishView.as_view()),''''^publish/$' [name='publish-list^publish/(?P<pk>[^/.]+)/$' [name='publish-detail']'''

每个路由对应的接口功能

	publish/:get请求的话则会执行视图集里面的list方法publish/:post请求的话则会执行视图集里面的create方法publish/<int:pk>/:get请求执行视图集里面的retrieve方法publish/<int:pk>/:put请求执行视图集里面的update方法publish/<int:pk>/:delete请求执行视图集里面的destroy方法

实际展示
视图类

	from rest_framework.viewsets import ModelViewSet'必须是继承了ViewSetMixin类的视图类才能使用这种自动生成路由的方法'class PublishView(ModelViewSet):queryset = models.Publish.objects.all()serializer_class = PublishSerializer

路由

	from rest_framework.routers import SimpleRouterrouter = SimpleRouter()router.register('publish',views.PublishView)urlpatterns = []urlpatterns += router.urls

此时上面代码就可以自动生成路由了,完成了增、删、改、查(一条或多条数据)的接口了,但是不包括在视图集里面自定义的方法。

如果要给我们自定义的方法也加上路由,那么则需要使用action装饰器来声明。


SimpleRouter生成URL的方式
在这里插入图片描述


DefaultRouter生成URL的方式
在这里插入图片描述


action装饰器

在视图集中,如果想要让Router自动帮助我们为自定义的方法生成路由信息,需要使用rest_framework.decorators.action装饰器。

使用action装饰器的方法名会作为路由的后缀,例如:

	/publish/使用action装饰器的方法名/

并且action装饰器会接收两个参数:

  • methods:声明该action对应的请求方式,列表传递:['get','post']表示该路由get请求与post请求。
  • detail:声明该action的路由是否与单一资源(就是单条数据)对应,如果需要的话设置True。
	/publish/<int:pk>/使用action装饰器的方法名/True:表示路径格式是:/publish/pk/action方法名/False:表示路径格式是:/publish/action方法名/
  • url_path:控制生成的/使用action装饰器的方法名/后面的路径是什么,如果不写默认以方法名
  • url_name:别名,用于反向解析

实际案例
视图类

	from rest_framework.viewsets import ModelViewSetfrom rest_framework.response import Responsefrom rest_framework.decorators import actionclass PublishView(ModelViewSet):queryset = models.Publish.objects.all()serializer_class = PublishSerializer@action(methods=['post'], detail=False)def login(self,request):return Response({'message':'登录成功'})@action(methods=['get'],detail=True)def test(self,request,pk):return Response({'message':'测试成功'})

效果展示
在这里插入图片描述
在这里插入图片描述
此时可以从浏览器上看到自动生成的路由

	api/v1/ ^publish/$ [name='publish-list']api/v1/ ^publish/login/$ [name='publish-login']api/v1/ ^publish/(?P<pk>[^/.]+)/$ [name='publish-detail']api/v1/ ^publish/(?P<pk>[^/.]+)/test/$ [name='publish-test']

它使用的是正则来匹配,中间使用了有名分组,以关键字:pk=xx的形式传给视图。


二、认证组件(Authentication)

在DRF中,我们要进行登录认证的话需要使用DRF内部的认证组件,为什么不用auth组件?因为DRF重新封装了request方法,而当我们使用原来reqeust.user时,则会调用_authenticate方法,然后在调用我们编写的认证类里面的authenticate方法进行认证。

开启认证有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth"]# value值是我们认证组件类在当前项目的路径}

局部开启:在视图类里面指定认证类

	'导入登录认证类'from .auth import LoginAuthauthentication_classes = [test.LoginAuth, ]# 认证可以有多个,在调用_authenticate方法时会将列表里面类实例成对象,然后执行对象里面的authenticate方法。# 执行顺序从前至后,如果某个对象返回了正确结果则后面对象不会执行。'如果全局认证了但是又不想让某一个不认证,需要再视图类里面写入authenticate_classes = []清空即可'

登录认证类

	from rest_framework.authentication import BaseAuthenticationfrom . import modelsfrom rest_framework.exceptions import AuthenticationFailed'''通过认证类完成,使用步骤1 写一个认证类,继承BaseAuthentication2 重写authenticate方法,在内部做认证3 如果认证通过,返回2个值4 认证不通过抛AuthenticationFailed异常5 只要返回了两个值,在后续的request.user 就是当前登录用户'''class LoginAuth(BaseAuthentication):def authenticate(self, request):  重写authenticate方法,做内部认证# 完成对用户的校验# 当次请求的requesttoken = request.query_params.get('token')  获取tokenuser_token = models.UserToken.objects.filter(token=token).first()if user_token:user = user_token.user  # 如果通过认证返回两个值,不通过则抛异常'return后,在后续的视图类的方法中,就可以通过reqeust.user取到当前登录的用户''如果不按照这个规则来写,后续视图类的request.user是取不到当前登录用户'return user,user_token'质押返回了两个值,在后续的request.user就是当前登录用户'else:raise AuthenticationFailed('您没有登录!')

三、权限组件(Permissions)

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

开启权限有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['app01.permission.CommonPermission',],}'注意,不要再配置文件乱导入不使用的东西,否则没有加载过就使用会直接报错。'

局部开启:在视图类里面指定权限类

	'导入权限类'from .permission import CommonPermissionpermission_classes = [CommonPermission]'如果全局设置权限了但是又不想让某一个不设置权限,需要再视图类里面写入permission_classes = []清空即可'

补充

	如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部-'.has_permission(self,request,view)'是否可以访问视图,view表示当前视图对象-'.has_object_permission(self,request,view,obj)'是否可以访问数据对象,view表示当前视图,obj为数据对象

权限类的定义

	'models.py定义的用户表'class User(models.Model):username = models.CharField(max_length=64)password = models.CharField(max_length=64)user_type = models.IntegerField(default=1, choices=((1, '普通用户'), (2, '管理员'), (3, '超级管理员')))from rest_framework.permissions import BasePermission'''权限类其实跟认证类一样只需要继承类修改方法使用步骤1 写一个类,继承BasePermission2 重写has_permission方法(也可以不继承BasePermission,但是重写这个方法,一样有用,因为python是鸭子类型)3 在方法中校验用户是否有权限(request.user就是当前登录用户)4 如果有权限,就返回True,没有权限,返回False5 self.message 是显示给前端的中文提示信息''''我这里创建是一个只有超级管理员才能访问其他人都不能访问的例子'class CommonPermission(BasePermission):   # 随意定义一个类继承BasePermissiondef has_permission(self, request, view):  # 重写has_permission方法'''到了这里,正常步骤应该登录完了,可以使用reqeust.user来查看当前登录用户然后拿到用户后判断用户是否有权限,去用户表中查看用户类型字段user_type,然后根据类型判断是否有权限-ACL:访问控制列表-rbac:公司内部系统,基于角色的访问控制-abac:rbac升级版,加了属性认证'''try:  # 这里进行异常捕捉,因为有可能有匿名用户所以需要进行捕捉user_type = request.user.user_type  print(f"用户:{request.user.get_user_type_display()}")print(f"编号:{user_type}")if user_type == 3: # 获取用户的管理员信息,如果有权限返回True,否则Falsereturn Trueelse:'报错信息渲染,这里的reqeust.user.get_user_type_display()是返回这个字段的choice对应的文字'self.message = f"你是{request.user.get_user_type_display()}。没有权限进行操作!"return Falseexcept Exception as e:  # 当是匿名用户或者说是没有登录的用户,走这里# print(request.path) '这里的判断是为了给登录和注册页进行解除设限'if 'login' in request.path: # 获取return Trueelif 'register' in request.path:return True'渲染报错信息渲染'self.message = "您没有登录,没有权限进行操作!"return False

内置权限类

当我们通过create_user或者createsuperuser也可以具备权限,DRF提供了以下权限类。

	from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly- AllowAny	允许所有用户- IsAuthenticated	仅通过认证的用户- IsAdminUser	仅管理员用户- IsAuthenticatedOrReadOnly	以及登录认证的用户可以对数据进行增删改查操作,没有登录认证的只能查看数据

我们可以根据哪个视图的需要来进行引入。
全局使用:这就表示所有视图都只能通过认证的用户访问

	REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated',],}

如果需要某几个视图不想使用这种效果的话,则可以进行局部禁用

	permission_classes = [] # 设置空即可,或者指定别的权限类

如果未指定的话,则使用DRF默认的

	REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny',]}

四、频率组件(Throttling)

我们也可以称其为:限流。其主要作用:

  • 可以对接口访问的次数进行限制,以减轻服务器压力
  • 一般用于付费购买次数,投票等场景使用。

开启频率有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],}'注意,不要再配置文件乱导入不使用的东西,否则没有加载过就使用会直接报错。'

局部开启:在视图类里面指定权限类

	'导入权限类'from .throttling import CommonThrottlethrottle_classes = [CommonThrottle]'如果全局设置权限了但是又不想让某一个不设置权限,需要再视图类里面写入permission_classes = []清空即可'

频率类的定义

	from rest_framework.throttling import BaseThrottle,SimpleRateThrottlefrom . import models'''使用步骤:1.写一个类继承SimleRateThrottle2.重写get_cache_key方法,返回一个唯一的字符串,会以这个字符串做频率限制3.有两种写法3.1 写一个类属性 scope='随意命名',使用这个方法的必须要与配置文件中定义使用配置文件中写REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'key要跟类中的scop定义的名字对应': '5/m',},# 表示该接口一分钟只能被访问5次,key值就是我们频率类里面的scope属性值这个字典后面value值里面的/前面的是访问次数,后面是超过次数后等待的时间,可以根据下面参数来进行选择即可。{'s':1,'m':60,'h':3600,'d':86400}  # 都是使用秒来计算我们也可以直接使用英文单词来:秒:second,分:minute,时:hour,天:day}3.2 写一个类属性 rate = '5/minute' 这种写法就无需配合配置文件中写了,相当于直接整合了''''这里我以一个登录用户id进行限制一分钟访问三次'class CommonThrottle(SimpleRateThrottle):rate = '3/minute'  # second minute hour daydef get_cache_key(self, request, view):user = request.userobj = models.User.objects.filter(username=user.username).first()'''返回什么,频率就可以做什么限制比如也可以通过IP地址进行限制,ip = request.META.get('REMOTE_ADDR')'''return obj.pk  # ip

在settings中使用匿名用户、普通用户的限制

	REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ('rest_framework.throttling.AnonRateThrottle', # 匿名用户限流'rest_framework.throttling.UserRateThrottle', # 普通用户限流),'DEFAULT_THROTTLE_RATES': {'anon': '3/m', # 设置匿名用户每分钟只能访问3次'user': '5/m', # 设置普通用户每分钟只能访问5次}}

五、权限组件源码分析

	'''我们知道在DRF的APIView中有三大认证是在执行视图类的方法之前就执行了三大认证,也就是APIView中的dispatch方法中的self.initial。在之前几篇DRF博客中,以及介绍解读过APIView的源码了所以这里我就不重头开始解读了,直接从dispatch里面开始了'''def dispatch(self, request, *args, **kwargs):try:'就是在这里执行了三大认证:认证、权限、频率'self.initial(request, *args, **kwargs)'执行视图类的方法开始'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_allowedresponse = handler(request, *args, **kwargs)'执行视图类的方法结束'except Exception as exc:  全局异常捕捉response = self.handle_exception(exc)self.response = self.finalize_response(request, response, *args, **kwargs)return self.response'''我们找到了这个dispatch里面执行三大认证的地方后,我们知道,这个self是视图类的对象,而视图类是继承了APIView这个类所以我们先去APIView这个类中找一下有没有这个initial的方法,结果是有的'''找到了APIView里的initialdef initial(self, request, *args, **kwargs):self.perform_authentication(request) # 认证组件self.check_permissions(request) # 权限组件self.check_throttles(request) # 频率组件'因为我们这里是分析权限组件的,所以在这里只看一下权限的,跟上面一样,这个self还是视图类的对象'在APIView里面找到了check_permissions方法# 检查请求是否具有所需的权限def check_permissions(self, request):# 遍历视图或视图集的权限类列表'这里的self还是视图类的对象,然后我们又得去APIView里面找看有没有get_permissions方法''''def get_permissions(self):return [permission() for permission in self.permission_classes]在这个get_permissions里面直接返回了一个列表生成式,我们得去看看这个self.permission_class是什么permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES从上面点击查看到的可以得知,self.permission_class就是咱们配置在视图类中的列表,里面是一个个权限类,并且没加括号执行。然后我们可以知道它每次从我们自己的视图类的permission_class列表中拿出一个值出来所以这里的返回值就是每次拿到一个值然后加括号执行,其实就是我们配置的一个个权限类的对象'''所以这里self.get_permissions()就是拿到一个个我们配置的权限类的对象的列表,然后在这里又进行循环一个个拿出for permission in self.get_permissions(): 所以这里的permission就是我们写的一个个的权限类的对象# 调用每个权限类的 has_permission 方法进行权限检查'''这里看到has_permission,这个就是为什么我们需要再权限类中重写这个方法,因为在这里它在调用它并且传入了两个参数,这个request就是APIView包装后的新的request,而这个self它还是我们视图类的对象因为还是在APIView中。这就是为什么我们在权限类中重写has_permission方法括号中加入了一个view参数,就是接收了这个的self也就是视图类对象。所以我们这个权限类中的view其实就可以直接拿到view.request,也可以直接拿到view.action等参数'''if not permission.has_permission(request, self):'而这里在权限类中has_permission方法如果返回值是True就不会执行这里的代码,反之就会走这里'# 如果权限检查失败,调用 permission_denied 方法,拒绝访问self.permission_denied('这里的self还是视图类的对象,当执行了这个permission_denied就是说明没有权限''''这里注意一个点,如果配置了多个权限类,如果第一个权限类就没过,就不会执行后面的权限类,所以得把想要过的放最前面'''request,# 获取权限类中可能定义的消息和代码message=getattr(permission, 'message', None),'这里的message和code都是从我们权限类的对象中反射过来的'code=getattr(permission, 'code', None))'在这里我们还可以看看,这个permission_denied,它还是在APIView中'def permission_denied(self, request, message=None, code=None):if request.authenticators and not request.successful_authenticator:raise exceptions.NotAuthenticated()raise exceptions.PermissionDenied(detail=message, code=code)'''可以看到它执行抛了异常,因为抛了异常,最后会被APIView中的全局异常捕捉到并且把上面的message和code都传入过去message会放在响应体中,code会放在响应状态码中'''

总结:

	权限类源码的执行流程:1.先去视图类继承的APIView中的dispatch方法中执行self.initial方法2.然后又执行APIView的initial方法中的self.check_permissions(request)3.然后从里面取出配置在视图类中的权限类,实例化得到对象。4.然后for循环一个个执行对象的has_permission方法(重写的方法),如果返回False就直接结束,不再往下执行权限就认证通过'小细节'1.为什么写一个类继承BasePermission,重写has_permission方法-也可以不继承这个类,只重写这个方法也可以(因为python是鸭子类型)2.权限类中 self.message  会返回给前端3.局部配置:放在视图类中:permission_classes = [权限类名]4.全局配置,配置在配置文件中也可以,那么视图类中就没有-如果视图类上不配做权限类,permission_classes = [],会默认使用配置文件的api_settings.DEFAULT_PERMISSION_CLASSES-执行的顺序:优先使用项目配置文件----->其次使用drf内配置文件

六、认证组件源码分析

	'因为也是继承了APIView,从上面权限组件源码分析中我们知道在它的dispatch方法中有一个initial方法''里面也有一个认证组件的'def initial(self, request, *args, **kwargs):self.perform_authentication(request) # 认证组件self.check_permissions(request) # 权限组件self.check_throttles(request) # 频率组件'因为我们这里是分析只分析认证组件的,然后self还是视图类的对象'在APIView里面找到了perform_authentication方法def perform_authentication(self, request):'''可以看到里面只写了一句代码,因为这里还是APIView所以这里的self还是视图类的,这里的reqeust就是APIView包装的新的request。'''request.user'这里可以看到request.user,可以会觉得它是一个属性,但是其实它是一个方法,是伪装成数据属性的''这样我们就得回到APIView源码中找了,因为我们这个新的reqeust是在Request中,所以我们得去看它了'我们直接在视图中导入这个然后找到这个user位置:from rest_framework.request import Request@propertydef user(self):  这里的self就是Request的对象,因为它并没有继承任何一个类。所以就是它自己的对象if not hasattr(self, '_user'):'然后这里是看有没有这个_user,但是我们确实是没有,所以是False,但是又if了not所以变成True'with wrap_attributeerrors():  # 上下文管理器self._authenticate()  所以会执行这一句return self._user'sel_authenticate()这里的self就是Resquest对象,所以我们找找Resquest中有没有这个方法'def _authenticate(self):'''这里循环跟权限组件那块差不多self.authenticators,就是我们配置在视图类中认证类的一个个对象,放在列表中所以这里循环出来的authenticator就是一个个我们配置的认证类对象'''for authenticator in self.authenticators:此处对上面几句的解释'''这个self还是Resquest对象,我们在Resquest中找authenticators,而它不是一个方法,而是一个属性,所以我们直接按住Ctrl+鼠标左键点击跳转即可def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):self.authenticators = authenticators or ()从我们点击跳转找到的我们可以看到这个是Resquest类实例化后得到的对象的初始化方法,会把对象的authenticators传入给了,self.authenticators对象,所以我们在类实例化调用这个初始化方法是什么时候实例化类的,我们得去APIView中找找,在我们之前博客中有写过APIView的源码分析中知道,在它的dispatch中request = self.initialize_request(request, *args, **kwargs)这里实例化得到对象了,所以我们去看看def initialize_request(self, request, *args, **kwargs):return Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)从上面代码中可以看到返回了authenticators=self.get_authenticators(),这里的self又是谁?现在是在APIView中,所以这里的self是视图类的对象然后直接跳转到这个self.get_authenticators()def get_authenticators(self):return [auth() for auth in self.authentication_classes]self.self.authentication_classes,self就是视图类的对象,而authentication_classes就是在视图类中配置的认证类中的一个个对象,它是一个列表'''try:'''因为上面我们知道了authenticator就是我们配置的一个个认证类,而这里的authenticate就是我们在认证类中重写的方法,因为在这里调用它了。而这里的self就还是APIView包装的新的Resquest对象,所以在认证类中重写这个方法后面接收了它然后执行认证类的这个方法,后返回值就赋值给了user_auth_tuple这里在我们认证类的这个方法中返回了两个值:第一个是当前登录用户,第二个的token,只走这一个认证类,后面的不再走了也可以返回None,这样就会继续执行下一个认证类'''user_auth_tuple = authenticator.authenticate(self)'''如果这里没有重写这个方法就抛出异常,它并没有捕获AuthenticationFailed,而是APIException但是AuthenticationFailed是继承了APIException。所以我们在认证类抛出异常使用AuthenticationFailed'''except exceptions.APIException:self._not_authenticated()raise'这里如果user_auth_tuple不是空的话,就走这里,就是正常返回了认证类方法的两个值'if user_auth_tuple is not None:self._authenticator = authenticator'''这里的self就还是Resquest的对象,并且使用了解压赋值,然后把user_auth_tuple的两个值分别赋值这就是为什么后续在视图类中,reqeust.user就是当前登录的用户,request.auth就是另一个参数当认证类没有返回值,那么这里就是空,如果有第二个认知类那么就会进行第二次循环,如果有返回值就解压赋值完毕后,直接结束了。'''self.user, self.auth = user_auth_tuple'''所以这里我们可以知道,在视图类中配置认证类是可以配置多个的,如果第一个认知类有返回值就不会再执行第二个认证类,如果没有返回值,则会执行第二个认证类。而返回的两个值,第一个给了reqeust.user,第二个给了reqeust.auth,这样在后续视图类中就可以取到'''returnself._not_authenticated()

总结

	1.在认证类中,重写authenticate方法(不重写就无法调用)2.为什么校验失败抛异常,因为我们写了AuthenticationFailed,又AuthenticationFailed是继承了APIException所以能捕获3.通过认证就会返回两个值或者None(如果没有返回值就会执行下一个认证类,或者没有在后续视图类中request.user和reqeust.auth就拿不到值)4.视图类上局部配置和配置文件全局配置跟权限类的一模一样。

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

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

相关文章

YOLOv8可视化:引入多种可视化CAM方法,为科研保驾护航

💡💡💡本文内容:调用pytorch下的CAM可视化库,支持十多种可视化方法,打开“黑盒”,让YOLOv8变得相对可解释性 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm=1001.2014.3001.5482 💡💡💡全网独家首发创新(原创),适…

Vue Echarts 多折线图只有一条X轴(合并X轴数据并去重排序) - 附完整示例

echarts&#xff1a;一个基于 JavaScript 的开源可视化图表库。 目录 效果 一、介绍 1、官方文档&#xff1a;Apache ECharts 2、官方示例 二、准备工作 1、安装依赖包 2、示例版本 三、使用步骤 1、在单页面引入 echarts 2、指定容器并设置容器宽高 3、数据处理&am…

经验分享:构建知识库管理系统只需要这几步

导语&#xff1a; 在当今信息爆炸的时代&#xff0c;构建一个高效的知识库管理系统对于企业来说至关重要。一个好的知识库管理系统可以帮助企业集中管理和共享知识和信息&#xff0c;提高团队的协作效率和创新能力。本文将分享构建知识库管理系统的几个关键步骤&#xff0c;帮…

[Linux] MySQL数据库的备份与恢复

一、数据库备份的分类和备份策略 1.1 数据库备份的分类 1&#xff09;物理备份 物理备份&#xff1a;对数据库操作系统的物理文件&#xff08;如数据文件、日志文件等&#xff09;的备份。 物理备份方法&#xff1a; 冷备份(脱机备份) &#xff1a;是在关闭数据库的时候进…

3D视觉方案的优势

随着机器视觉在工业领域的应用逐渐深入&#xff0c;传统的 2D 视觉方案已经趋向成熟&#xff0c;应用局限性也已经显现出来。 2D 视觉方案易受照明条件影响&#xff0c;一致性和稳定性难以保证&#xff0c;且无法实现三维高精度测量和定位&#xff0c; 3D 视觉方案应运而生&…

奇富科技跻身国际AI学术顶级会议ICASSP 2024,AI智能感知能力迈入新纪元

近日&#xff0c;2024年IEEE声学、语音与信号处理国际会议ICASSP 2024&#xff08;2024 IEEE International Conference on Acoustics, Speech, and Signal Processing&#xff09;宣布录用奇富科技关于语音情感计算的最新研究成果论文“MS-SENet: Enhancing Speech Emotion Re…

如何发送大型文件 ---- 分卷压缩

不知道各位小伙伴有没有这样的烦恼&#xff0c;发送很大很大的压缩包会受到限制&#xff0c;比如QQ邮箱需要付费来进行中转的扩容&#xff0c;下面我将会介绍一种分卷压缩的方法来传送较大的压缩包给对方 使用7-zip软件进行分卷压缩 如果有7-zip压缩软件直接跳过这一步 7-zi…

利用Milvus Cloud和LangChain构建机器人:一种引人入胜且通俗易懂的方法

一、引言 机器人已经深入我们的日常生活&#xff0c;从家庭服务到工业生产&#xff0c;再到医疗和运输等领域。然而&#xff0c;这些机器人往往需要复杂的算法和数据处理技术才能有效地执行任务。在这个过程中&#xff0c;人工智能&#xff08;AI&#xff09;和机器学习&#…

Spring Boot快速搭建一个简易商城项目【一展示商城首页篇】

前言&#xff1a;今天我来使用Spring Boot快速搭建一个简易商城项目以下是相关的思路流程&#xff0c;如果有更好的思路&#xff0c;欢迎大佬评论留言&#xff01;&#xff01;&#xff01; 一&#xff0c;实现思路&#xff1a; 创建 Spring Boot 项目&#xff1a; 使用 Spring…

Hikvision SPON IP网络对讲广播系统存在命令执行漏洞CVE-2023-6895 附POC软件

免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. Hikvision SPON IP网络对讲广播系统简介 微信公众…

理解文件系统

一 什么是文件系统 文件系统是计算机操作系统中的一个核心组件&#xff0c;用于管理计算机中的文件和文件夹。它提供了一种组织和访问计算机存储设备上数据的方式。文件系统使用户能够创建、修改、删除和查找文件&#xff0c;以及组织文件和文件夹的层次结构。 ps: linux一共有…

【FPGA】高云FPGA之科学的FPGA开发流程

FPGA开发流程 开发流程1、设计定义2、设计输入3、分析和综合4、功能仿真5、布局布线6、时序仿真7、IO分配以及配置文件&#xff08;bit流文件&#xff09;的生成8、配置&#xff08;烧录&#xff09;FPGA9、在线调试 例子1、设计定义1.1 需求1.2 原理图1.3 真值表 2、设计输入2…

Docker - 镜像 | 容器 | 数据卷 日常开发常用指令 + 演示(一文通关)

目录 Docker 开发常用指令汇总 辅助命令 docker version docker info docker --help 镜像命令 查看镜像信息 下载镜像 搜索镜像 删除镜像 容器命令 查看运行中的容器 运行容器 停止、启动、重启、暂停、恢复容器 杀死容器 删除容器 查看容器日志 进入容器内部…

软件测试/测试开发丨Pytest学习笔记

Pytest 格式要求 文件: 以 test_ 开头或以 _test 结尾类: 以 Test 开头方法/函数: 以 _test 开头测试类中不可以添加构造函数, 若添加构造函数将导致Pytest无法识别类下的测试方法 断言 与Unittest不同, 在Pytest中我们需要使用python自带的 assert 关键字进行断言 assert…

中介者模式-Mediator Pattern-1

如果在一个系统中对象之间的联系呈现为网状结构&#xff0c; 对象之间存在大量的多对多联系&#xff0c;将导致系统非常复杂。 这些对象既会影响别的对象&#xff0c;也会被别的对象所影响。 这些对象称为同事对象&#xff0c;它们之间通过彼此的相互作用实现系统的行为。 在网…

找不到msvcp140.dll怎么办-msvcp140.dll丢失的解决方法分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140.dll丢失”。那么&#xff0c;msvcp140.dll究竟是什么文件&#xff1f;为什么会出现丢失的情况&#xff1f;本文将详细介绍msvcp140.dll的属性、作用以及丢失的原因&#xff0c;并…

Java学习笔记(八)——面向对象编程(高级)

目录 一、类变量和类方法 &#xff08;一&#xff09;类变量/静态变量 类变量内存布局 类变量使用注意事项和细节 &#xff08;二&#xff09;类方法 类方法经典的使用场景 类方法使用注意事项和细节 二、理解main方法语法 三、代码块 代码块使用注意事项和细节 四、…

Graylog日志搜索技巧

graylog搜索日志用的语法是Syntax接近Lucene&#xff0c;搜起来比较方便 Search query languagehttps://go2docs.graylog.org/4-0/making_sense_of_your_log_data/writing_search_queries.html?tocpathSearching%20Your%20Log%20Data|_____1 1.Syntax 语法 1.1 基本匹配 搜…

java keytool.exe ssl

JDK如果没有先安装 JDK8 install_jdk aleady install-CSDN博客 java keytool.exe ssl keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore D:\server.keystore -validity 3650 server.ssl.key-storeD:\server.keystore server.ssl.key-…

怎么使用jupter notebook并配置环境变量

有的时候需要使用Jupyter Notebook运行代码&#xff0c;Jupyter Notebook的主要特点&#xff1a; ① 编程时具有语法高亮、缩进、tab补全的功能。 ② 可直接通过浏览器运行代码&#xff0c;同时在代码块下方展示运行结果。 ③ 以富媒体格式展示计算结果。富媒体格式包括&…