drf知识-08

news2025/1/15 21:03:17

Django之了解DRF框架

# 介绍:DRF全称 django rest framework

# 背景:

        在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写
        增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
        删:判断要删除的数据是否存在 -> 执行数据库删除
        改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
        查:查询数据库 -> 将数据序列化并返回
# 作用:Django REST framework可以帮助我们简化上述两部分的代码编写,大大提高REST API的开发速度

# DRF特点:

        1.提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
        2.提供了丰富的类视图、Mixin扩展类,简化视图的编写;
        3.丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
        4.多种身份认证和权限认证方式的支持;
        5.内置了限流系统;
        6.直观的 API web 界面;
        7.可扩展性,插件丰富

# 环境安装与配置:

1、安装DRF

pip install djangorestframework

2、在settings.py的INSTALLED_APPS中添加’rest_framework’

INSTALLED_APPS = [
    ...
    'rest_framework',
]

# DRF牛刀小试:

1、创建序列化器,在books应用中新建serializers.py用于保存该应用的序列化器,创建一个类用于序列化与反序列化:

from rest_framework import serializers
from books.models import Book

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = Book
        fields = '__all__'

        model 指明该序列化器处理的数据字段从模型类Book参考生成
        fields 指明该序列化器包含模型类中的哪些字段,'all’指明包含所有字段

2、编写视图,在books应用的views.py中创建视图BookViewSet,这是一个视图集合:

from rest_framework.viewsets import ModelViewSet
from .serializers import BookSerializer
from .models import Book

class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

        queryset 指明该视图集在查询数据时使用的查询集
        serializer_class 指明该视图在进行序列化或反序列化时使用的序列化器

3、定义路由,在books应用的urls.py中定义路由信息

from . import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()  # 可以处理视图的路由器
router.register(r'books', views.BookViewSet, 'books')  # 向路由器中注册视图集
urlpatterns = [
]
urlpatterns += router.urls  # 将路由器中的所以路由信息追到到django的路由列表中

三大认证组件回顾

# 认证类的编写
用户登录后,会有登录标识,早期直接写入到浏览器中了

session['name']='lqz'
obj.set_cookie()

写认证类的目的:校验它携带的登录标识,是否合法,是否在库中存着
只需要按照固定规则去写即可:
  1、写一个类,继承 BaseAuthentication
  2、重写 authenticate 方法
  3、在方法中完成校验--》用户标识

             用户标识带在请求头 / 请求地址 / 请求体
            校验携带的标识正不正确---> 去数据库查
            查到返回俩值:第一个值会给后续的request.user,第二个值给request.auth
            校验失败:抛异常

class LoginAuth(BaseAuthentication):   # 不一定继承BaseAuthentication
    def authenticate(self, request):   # 目的是重写authenticate,有authenticate就是认证类
        token = request.query_params.get('token') or request.META.get('HTTP_TOKEN')
        user_token = UserToken.objects.filter(token=token).first()
        if user_token:
            user = user_token.user      # 重写是因为源码里在一个个调用这个方法,在方法中完成校验
            return user, user_token     # 返回两个值,第一个值会给request.user,第二个给了request.auth
        else:                           # 标识一般带到请求头、请求地址和请求体中,由后端决定
            raise AuthenticationFailed("您没有登录")

  4、放在视图类上,局部禁用:
            authentication_classes=[ ]
 5、放在配置文件中--drf配置文件中找 :         

 REST_FRAMEWORK = {
                'DEFAULT_AUTHENTICATION_CLASSES': ['app01.auth.LoginAuth'],
            }

#  权限类
  用户登录了,有没有权限访问接口
  权限放在了认证之后,request.user :当前登录用户,根据是谁来做权限
  编写规则:
 1、写一个类类,继承 BasePermission
 2、 重写 has_permission 方法
 3、在方法中完成权限校验--》当前登录用户
            能有用户,就能取出用户的权限
            如果有,返回True,没有返回False
            前端看到中文提示:self.message

class CommonPermission(BasePermission):
    def has_permission(self, request, view):
        try:
            user_type = request.user.user_type
            if user_type == 2:
                return True
            else:
                # user.get_字段名_display()  返回这个字段的choice对应的文字
                self.message = '您是:%s,您没有权限操作这个' % request.user.get_user_type_display()
                return False
        except Exception as e:
            # 未登录用户也没有权限
            if 'login' in request.path:
                return True
            else:
                self.message = '您没有登录,您没有权限操作这个'
                return False

  4、放在视图类上(可以配多个),局部禁用:
            permission_classes=[ ]
 5、放在配置文件中--drf配置文件中找:

 REST_FRAMEWORK = {
                'DEFAULT_permission_CLASSES': [''],
            }

# 频率类使用
限制用户访问频次:用户登录或不登录都可能会限制
限制条件:ip,用户id
编写步骤:
    1、写一个类类,继承 SimpleRateThrottle
    2、重写 get_cache_key 方法
           返回什么就以什么做限制:ip或id号
            类上写个属性:rate = '5/d'    # s m h d 

class CommonThrottle(SimpleRateThrottle):
    rate = '3/m'
    def get_cache_key(self, request, view):
        ip = request.META.get('REMOTE_ADDR')
        return ip

  3、放在视图类上(可以配多个),局部禁用:
            throttle_classes=[ ]
  4、 放在配置文件中--drf配置文件中找:            

REST_FRAMEWORK = {
                'DEFAULT_throttle_CLASSES': [''],
            }

排序之继承GenericAPIView

# 1 只有查询所有需要排序
# 2 如何使用
     1 必须是继承 GenericAPIView 及其子类
    2 在类中配置类属性
        filter_backends = [OrderingFilter]
    3 类中写属性
        ordering_fields = ['price','id']  # 必须表的字段        
    4 以后再前端,就可以访问
        http://127.0.0.1:8000/api/v1/books/?ordering=price 按price升序排
        http://127.0.0.1:8000/api/v1/books/?ordering=-price 按price降序排
        http://127.0.0.1:8000/api/v1/books/?ordering=-price,id

from .models import Book
from rest_framework.viewsets import ViewSetMixin
from rest_framework.generics import ListAPIView
from .serializer import BookSerializer

# 排序之继承 GenericAPIView
from rest_framework.filters import OrderingFilter
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [OrderingFilter]  # 排序
    ordering_fields = ['price','id']
    # http://127.0.0.1:8000/api/v1/books/?ordering=-price,id

排序之继承APIview

# 如果继承APIView,过滤规则自己写

# 单条排序:

# 排序之继承 APIView
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(ViewSetMixin, APIView):
    def list(self, request):
        # 从地址兰中取出用户过滤条件
        # http://127.0.0.1:7000/api/v1/books/?ordering=-price
        query_params = request.query_params  #< QueryDict: {'ordering': ['-price']}>
        obj_list = Book.objects.all().order_by(query_params.get('ordering'))
        ser = BookSerializer(instance=obj_list, many=True)
        return Response(ser.data)

# 多条排序:

# 排序之继承 APIView
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(ViewSetMixin, APIView):
    def list(self, request):
        # 从地址兰中取出用户过滤条件
        # http://127.0.0.1:7000/api/v1/books/?ordering=-price,id
        query_params = request.query_params  #<QueryDict: {'ordering': ['-price,id']}>
        print(query_params)
        if ',' in query_params.get('ordering'):
            query = query_params.get('ordering').split(',')
        obj_list = Book.objects.all().order_by(*query)
        ser = BookSerializer(instance=obj_list, many=True)
        return Response(ser.data)

过滤之使用drf内置过滤类

#  restful规范中有一条是请求地址中带过滤条件,查询所有数据,只查询出我们想要的

# 如何使用
     1 必须是继承 GenericAPIView 及其子类
     2 在类中配置类属性
        filter_backends = [SearchFilter]
     3 类中写属性
       search_fields = ['price','id']  # 必须表的字段        
    4 以后再前端,就可以访问
        http://127.0.0.1:7000/api/v1/books/?search=风

        http://127.0.0.1:7000/api/v1/books/?search=摆

# 过滤之使用drf内置过滤类
from rest_framework.filters import SearchFilter
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [SearchFilter]  # 排序
    search_fields = ['name']
    # http://127.0.0.1:7000/api/v1/books/?search=风

过滤之使用djagno-filter过滤

# 下载  pip3 install django-filter

# 导入  from django_filters.rest_framework import DjangoFilterBackend
# 3 使用

# 过滤之使用djagno-filter过滤
from django_filters.rest_framework import DjangoFilterBackend
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [DjangoFilterBackend]  # 排序
    filterset_fields = ['name','price']
    # http://127.0.0.1:7000/api/v1/books/?name=摆渡人&price=34
    # 查询书名为摆渡人且价格为34的

过滤之自定制过滤类

# 写个类,继承BaseFilterBackend重写filter_queryset,在内部完成过滤

# filter
from rest_framework.filters import BaseFilterBackend
class CommonFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # queryset 是之前所有数据 Book.object.all()
        # request 当次请求request
        name = request.query_params.get('name')
        price = request.query_params.get('price')
        if name:
            queryset = queryset.filter(name__contains=name)
        if price:
            queryset = queryset.filter(price=price)
        return queryset
# views.py
# 过滤之自定制过滤类,重写了类里方法,再引用
from .filter import CommonFilter
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [CommonFilter]  # 排序
    # http://127.0.0.1:7000/api/v1/books/?name=追&price=31.2
    # 书名用了模糊查法,价格是精准查法

自定义过滤+排序

# 自定义过滤+排序
from .filter import CommonFilter
from rest_framework.filters import OrderingFilter
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [CommonFilter,OrderingFilter]  # 过滤,排序
    ordering_fields = ['price']
    # http://127.0.0.1:7000/api/v1/books/?name=渡&ordering=-price
    # 查询书名含渡的且按照价格降序

分页之基础分页

# 查询所有接口,分页

# 使用drf内置了三种分页方式:

        PageNumberPagination, LimitOffsetPagination, CursorPagination

1、写个类,继承基础分页类,重写类属性       

# pagination.py  基本分页PageNumberPagination
from rest_framework.pagination import PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
    page_size = 1      # 默认显示,每页大小,一页显示多少条
    page_query_param = 'page'    # 分页查询条件  ?page=1
    page_size_query_param = 'size'  #每页最多显示多少条的查询条件  &size=2
    max_page_size = 3   # 每页最多显示多少条
    # http://127.0.0.1:7000/api/v1/books/?search=34&size=2
    # 过滤查询价格为34且一页显示2条数据的(不写size默认显示1条)

2、在继承自 GenericAPIView及其子类, 在视图类配置分页类即可

# 分页之基础分页
# 在内置过滤器的条件下分页
from rest_framework.filters import SearchFilter
from .pagination import CommonPageNumberPagination
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [SearchFilter]  # 过滤,排序
    search_fields = ['price']
    pagination_class = CommonPageNumberPagination

分页之偏移分页

 # 查询所有接口,分页

# 使用drf内置了三种分页方式:

        PageNumberPagination, LimitOffsetPagination, CursorPagination

1、写个类,继承基础分页类,重写类属性       

# pagination.py  基本分页LimitOffsetPagination
from rest_framework.pagination import LimitOffsetPagination
class CommonLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 1   # 默认显示,每页显示的条数
    limit_query_param = 'limit'  # 分页查询条件  ?limit=1
    offset_query_param = 'offset'   # # 偏移量 从第2条开始,拿2条 offset=2&limit=2
    max_limit = 3   # # 每页最多显示多少条
    # http://127.0.0.1:7000/api/v1/books/?limit=1&page=3  显示第三页的一条数据
    # http://127.0.0.1:7000/api/v1/books/?offset=1&limit=2  从第一条数据开始显示2条数据

2、在继承自 GenericAPIView及其子类, 在视图类配置分页类即可

# 分页之基础分页
# 在内置过滤器的条件下分页
from rest_framework.filters import SearchFilter
from .pagination import CommonPageNumberPagination
from .pagination import CommonLimitOffsetPagination
class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [SearchFilter]  # 过滤,排序
    search_fields = ['price']
    pagination_class = CommonPageNumberPagination
    pagination_class = CommonLimitOffsetPagination

分页之游标分页

# 特点:只能从第一页开始,只能上一页和下一页,不能自定义哪页,但是效率高很多

1、写个类,继承基础分页类,重写类属性       

# pagination.py 游标分页  CursorPagination
from rest_framework.pagination import CursorPagination
class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'   # 分页查询条件  ?cursor=1
    page_size = 2    # 每页显示的条数
    ordering = 'id'  # 排序规则,必须是表中字段
    # http://127.0.0.1:7000/api/v1/books/
    # 内部已经写死,从第一页查起,显示2条,只能上下翻页

2、在继承自 GenericAPIView及其子类, 在视图类配置分页类即可

# views.py
# 分页之基础分页
# 在内置过滤器的条件下分页
from rest_framework.filters import SearchFilter
from .pagination import CommonPageNumberPagination
from .pagination import CommonLimitOffsetPagination
from .pagination import CommonCursorPagination

class BookView(ViewSetMixin,ListAPIView):     # 改路径和查询所有
    queryset = Book.objects.all()
    serializer_class = BookSerializer   # 序列类映射
    filter_backends = [SearchFilter]  # 过滤,排序
    search_fields = ['price']
    pagination_class = CommonPageNumberPagination
    pagination_class = CommonLimitOffsetPagination
    pagination_class = CommonCursorPagination

全局异常处理

# 三大认证和视图类的方法中出现了异常,都会被try捕获,做全局异常处理

# 捕获到统一处理,无论我是否出异常,返回的格式都是固定的

        {code:100,msg:成功}
# 新建py文件,写一个函数,在函数中处理异常

# exceptions.py
# drf的异常处理是exception_handler处理,没处理非drf的异常
# 自己写个函数,处理drf异常和自己的异常
from rest_framework.views import exception_handler
from rest_framework.response import Response

def common_exception_handler(exc, context):
    res = exception_handler(exc, context)  # 处理drf异常处理
    if res:
        # data = {'detail': exc.detail},错误信息
        # return Response(data)
        # {code: 100, msg: 成功}
        detail = res.data.get('detil') or "drf异常,请联系系统管理员"
        return Response({'code': 101, 'msg': detail})
    else:
        return Response({'code': 102, 'msg': '系统异常,请联系系统管理员:%s'%str(exc)})

# 把函数配置在配置文件中,setting.py

REST_FRAMEWORK = {
            'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler',
        }

#  只要三大认证或视图类的方法出了异常,就会走这个函数

# 全局异常处理
# 无论我是否出异常,返回的格式都是固定的
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import AuthenticationFailed,ValidationError,APIException

class UserView(ViewSetMixin, APIView):
    def create(self, request):  # post--->create
        # l = [1, 2, 3]
        # print(l[9])
        # raise Exception("你出错了")

        # drf  默认能处理自己的异常:继承自APIException的异常
        raise APIException('认证失败')
        return Response({'code': 100, 'msg': '成功'})

今日思维导图:

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

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

相关文章

leaflet学习笔记-地图图层控制(二)

图层介绍 Leaflet的地图图层控件可控制两类图层&#xff1a;一类是底图图层&#xff08;Base Layers&#xff09;&#xff0c;一次只能选择一个图层作为地图的背景图层&#xff0c;即底图图层&#xff0c;在地图图层控件中用单选按钮控制&#xff1b;另一类是覆盖图层&#xff…

目标检测损失函数:IoU、GIoU、DIoU、CIoU、EIoU、alpha IoU、SIoU、WIoU原理及Pytorch实现

前言 损失函数是用来评价模型的预测值和真实值一致程度&#xff0c;损失函数越小&#xff0c;通常模型的性能越好。不同的模型用的损失函数一般也不一样。损失函数主要是用在模型的训练阶段&#xff0c;如果我们想让预测值无限接近于真实值&#xff0c;就需要将损失值降到最低…

Ubuntu18.04安装GTSAM库并验证GTSAM是否安装成功(亲测可用)

在SLAM&#xff08;Simultaneous Localization and Mapping&#xff09;和SFM&#xff08;Structure from Motion&#xff09;这些复杂的估计问题中&#xff0c;因子图算法以其高效和灵活性而脱颖而出&#xff0c;成为图模型领域的核心技术。GTSAM&#xff08;Georgia Tech Smo…

【论文阅读】Resource Allocation for Text Semantic Communications

这是一篇关于语义通信中资源分配的论文。全文共5页&#xff0c;篇幅较短。 目录在这里 摘要关键字引言语义通信资源分配贡献公式符号 系统模型DeepSC TransmitterTransmission ModelDeepSC Receiver 语义感知资源分配策略Semantic Spectral Efficiency &#xff08;S-SE&#…

Docker七 | 搭建Swarm集群

目录 创建Swarm集群 创建管理节点 增加工作节点 查看集群 部署服务 新建服务 查看服务 服务伸缩 增加服务 减少服务 删除服务 创建Swarm集群 创建管理节点 在192.168.117.131下执行docker swarm init命令的节点自动成为管理节点 [rootlocalhost ~]# docker swar…

idea中切换JDK8、JDK11、JDK17

有时候&#xff0c;我们可能需要在不同的Java版本中去测试或者查看源码&#xff0c;idea可以让我们修改Java的版本。 前提&#xff1a;你必须下载安装好对应的Java版本&#xff0c;可参考文章【windows下切换JDK8、JDK11、JDK17】&#xff08;https://blog.csdn.net/xijinno1/a…

深度学习核心技术与实践之深度学习基础篇

非书中全部内容&#xff0c;只是写了些自认为有收获的部分 神经网络 生物神经元的特点 &#xff08;1&#xff09;人体各种神经元本身的构成很相似 &#xff08;2&#xff09;早期的大脑损伤&#xff0c;其功能可能是以其他部位的神经元来代替实现的 &#xff08;3&#x…

腾讯云服务器怎么买划算?最新优惠价格表

2023腾讯云轻量应用服务器优惠价格表&#xff0c;12月最新报价&#xff0c;腾讯云轻量2核2G3M带宽62元一年、2核2G4M轻量服务器118元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;756元三年、4核8G12M轻量服务器646元15个月&#xff0c;CVM云服务器S5实例2核2G…

C# 常用数据类型及取值范围

1.常见数据类型和取值范围 序号数据类型占字节数取值范围1byte10 到 2552sbyte1-128 到 1273short 2-32,768 到 32,7674ushort20 到 65,5355int4-2,147,483,648 到 2,147,483,6476uint40 到 4,294,967,2957float41.5 x 10−45 至 3.4 x 10388double85.0 10−324 到 1.…

15种线上Bug梳理,这坑我算是踩全了

日常开发过程中大家肯定或多或少都会遇到一些偶现的问题&#xff0c;最常见的一句话就是&#xff1a;在我本地运行的时候都是好的呀&#xff1f;在测试环境跑的时候都是好的呀&#xff1f;在预发布环境都是正常的呀&#xff1f;在灰度阶段都是没问题的呀&#xff1f; 怎么到生…

MFC工程中无法使用cygwin64的库

文章目录 MFC工程中无法使用cygwin64的库概述在MFC中使用cygwin64的静态库在MFC中使用cygwin64的DLL进行静态包含在MFC中使用cygwin64的DLL进行动态调用唯一可以使用cygwin64的方法是进程隔离来通讯cygwin64的官方用途修正后的启动进程隐藏dos窗口的函数动态载入DLL的实现 - La…

SCENIC+:增强子和基因调控网络的单细胞多组学推理

摘要 对单个细胞中染色质可及性和基因表达的联合分析为破译增强子驱动的基因调控网络&#xff08;GRN&#xff09;提供了机会。在这里&#xff0c;我们提出了一种用于推理增强器驱动的 GRN 的方法&#xff0c;称为 SCENIC。 SCENIC 预测基因组增强子以及候选上游转录因子 (TF)…

Ubuntu及Docker 安装rabbitmq

安装ubuntu 前 先暴露端口&#xff1a; 5672 用于与mq服务器通信用 15672 管理界面使用的端口 docker命令&#xff1a;docker run -itd --name ubuntu -p 5672:5672 -p 15672:15672 ubuntu 进入docker : docker exec -it ubuntu /bin/bash 步骤&#xff1a; 1. 更新安装源…

Android开发笔记(四)

中级控件 图形定制图形Drawable形状图形Shape状态列表图形 选择按钮复选框CheckBox开关按钮Switch单选按钮RadioButton 文本输入编辑框EditText焦点变更监听器 图形定制 图形Drawable Android把所有能够显示的图形都抽象为Drawable类&#xff08;可绘制的&#xff09;&#x…

【Fastadmin】通用排序weigh不执行model模型的事件

在model模型类支持的before_delete、after_delete、before_write、after_write、before_update、after_update、before_insert、after_insert事件行为中&#xff0c;我们可以快捷的做很多操作&#xff0c;如删除缓存、逻辑判断等 但是在fastadmin的通用排序weigh拖动中无法触发…

【我与Java的成长记】之this引用和构造方法的使用详解

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、this的使用this引用的特…

设备智能运维利器:无线振温一体式传感器

在现代工业领域中&#xff0c;设备的状态监测和维护是确保生产正常运行的关键环节。随着技术的不断进步&#xff0c;传感器在设备监测中发挥着越来越重要的作用。其中&#xff0c;无线振温一体式传感器作为设备智能运维的利器&#xff0c;具有独特的优势和潜力。本文将介绍无线…

Python+OpenCV 零基础学习笔记(6):ROI

文章目录 相关链接运行环境前言ROI颜色区域分割颜色通道合并 相关链接 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程 CSDN标题里个括号对应视频的分P OpenCVPython CSDN专栏 Gitee 项目地址 运行环境 Python:3.11.5Anaconda:23.7.4IDE:vscode运行环境&#x…

一次性带屏电子烟解决方案,基于32位单片机开发

电子烟一般是指液态雾化电子烟&#xff0c;就是加烟油进行雾化的品类。电子烟根据烟油种类、烟雾量及使用情况有不同划分&#xff0c;如一次性小烟、换弹式电子烟、开放式注油电子烟、大烟、CBD雾化器等。一次性电子烟外形小巧&#xff0c;重量轻&#xff0c;便于随身携带&…

K8S 日志方案

目录 一、统一日志管理的整体方案 1、基础日志 2、Node级别的日志 3、集群级别的日志架构 二、安装统一日志管理组件 1、 部署Elasticsearch 2、部署Fluentd 3、部署Kibana 三、日志数据展示 一、统一日志管理的整体方案 通过应用和系统日志可以了解Kubernetes集群内…