drf请求、响应与视图组件

drf请求、响应与视图组件

RBAC是什么

  • RBAC模型概述

    • RBAC模型(Role-Based Access Control:基于角色的访问控制)模型是20世纪90年代研究出来的一种新模型,但其实在20世纪70年代的多用户计算时期,这种思想就已经被提出来,直到20世纪90年代中后期,RBAC才在研究团体中得到一些重视,并先后提出了许多类型的RBAC模型。其中以美国George Mason大学信息安全技术实验室(LIST)提出的RBAC96模型最具有代表,并得到了普遍的公认。
    • RBAC认为权限授权的过程可以抽象地概括为:Who是否可以对What进行How的访问操作,并对这个逻辑表达式进行判断是否为True的求解过程,也即是将权限问题转换为What、How的问题,Who、What、How构成了访问权限三元组;
  • RBAC的组成

    • 在RBAC模型里面,有3个基础组成部分,分别是:用户、角色和权限
    • RBAC通过定义角色的权限,并对用户授予某个角色从而来控制用户的权限,实现了用户和权限的逻辑分离(区别于ACL模型),极大地方便了权限的管理:
      • User(用户):每个用户都有唯一的UID识别,并被授予不同的角色
      • Role(角色):不同角色具有不同的权限
      • Permission(权限):访问权限
      • 用户-角色映射:用户和角色之间的映射关系
      • 角色-权限映射:角色和权限之间的映射

keepalive

在TCP中可以检测死连接的机制
keeplive原理很简单,TCP会在空闲了一定时间后发送数据给对方:
1.如果主机可达,对方就会响应ACK应答,就会认为是存活的,
2.如果可达,但应用程序退出,对方就会发FIN应答,发送TCP撤销连接
3.如果可达,但应用程序崩溃,对方就会发RST消息
4.如果对方主机不响应ack,rst,继续发送知道超过,就撤销连接诶,这个时间就是默认的两个小时。
	
    SYN表示建立连接,FIN表示关闭连接,ACK表示响应,PSH表示有 DATA数据传输,RST表示连接重置。
    
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:

 位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)
    TCP数据包中的序列号(Sequence Number)不是以报文段来进行编号的,而是 将连接生存周期内传输的所有数据当作一个字节流,序列号就是整个字节流中每个字节的编号。一个TCP数据包中包含多个字节流的数据(即数据段),而且每个TCP数据包中的数据大小不一定相同。在建立TCP连接的三次握手过程中,通信双方各自已确定了初始的序号x和y,TCP每次传送的报文段中的序号字段值表示所要传送本报文中的第一个字节的序号。
    TCP的报文到达确认(ACK),是对接收到的数据的最高序列号的确认,表示这前面的数据已经接收到,并向发送端返回一个下次接收时期望的TCP数据包的序列号(Ack Number) 。例如,主机A发送的当前数据序号是400,数据长度是100,则接收端收到后会返回一个确认号是500的确认号给主机A。
    TCP提供的确认机制,可以在通信过程中可以不对每一个TCP数据包发出单独的确认包(Delayed ACK机制),而是在传送数据时,顺便把确认信息传出,这样可以大大提高网络的利用率和传输效率。同时,TCP的确认机制,也可以一次确认多个数据报,例如,接收方收到了201,301,401的数据报,则只需要对401的数据包进行确认即可,对401的数据包的确认也意味着401之前的所有数据包都已经确认,这样也可以提高系统的效率。
    若发送方在规定时间内没有收到接收方的确认信息,就要将未被确认的数据包重新发送。接收方如果收到一个有差错的报文,则丢弃此报文,并不向发送方发送确认信息。因此,TCP报文的重传机制是由设置的超时定时器来决定的,在定时的时间内没有收到确认信息,则进行重传。这个定时的时间值的设定非常重要,太大会使包重传的延时比较大,太小则可能没有来得及收到对方的确认包发送方就再次重传,会使网络陷入无休止的重传过程中。接收方如果收到了重复的报文,将会丢弃重复的报文,但是必须发回确认信息,否则对方会再次发送。 丢包重传直到收到ACK报文或发送方达到配置的最大重传次数,最大重传次数取决于发送操作系统的配置值。默认情况下,Windows主机默认重传5次。大多数Linux系统默认最大15次。两种操作系统都可配置。
    TCP协议应当保证数据报按序到达接收方。如果接收方收到的数据报文没有错误,只是未按序号,这种现象如何处理呢?TCP协议本身没有规定,而是由TCP协议的实现者自己去确定。通常有两种方法进行处理:一是对没有按序号到达的报文直接丢弃,二是将未按序号到达的数据包先放于缓冲区内,等待它前面的序号包到达后,再将它交给应用进程。后一种方法将会提高系统的效率。例如,发送方连续发送了每个报文中100个字节的TCP数据报,其序号分别是1,101,201,…,701。假如其它数据报都收到了,而201这个数据报没有收到,则接收端应当对1和101这两个数据报进行确认,并将数据递交给相关的应用进程,301至701这5个数据报则应当放于缓冲区,等到201这个数据报到达后,然后按序将201至701这些数据报递交给相关应用进程,并对701数据报进行确认,确保了应用进程级的TCP数据的按序到达。

反射

  • 反射其实就是通过字符串的形式去对象(模块)中操作(查询/获取/删除/添加)成员,一种基于字符串的事件驱动

  • 可使用反射的地方:

    • 反射类中的变量:静态属性,类方法,静态方法

      下面的三个不常用

    • 反射对象中的变量,对象属性,普通方法

    • 反射模块中的变量

    • 反射本文件中的变量

  • 反射:

    • getattr()获取类、对象等中的属性和方法
    • hasattr()判断类、对象是否有该方法和属性
    • setattr()对该对象设置新的属性
    • delattr()删除对象中的属性

请求与响应

  • Request

    • 1.restframework传入视图的request对象不再是Django默认的HttpResponse对象,而是restframework提供的扩展了HttpResponse类的Request类的对象
    • 2.restframework提供了parser解析器,在接受请求后会自动根据Content-Type知名的请求数据类型(如Json、表单增)将请求的数据parse解析,解析为类字典[QuerDict]对象的保存到Request对象中
    • 3.Request对象的数据是根据前端发送数据的格式进行解析之后的结果
    • 4.无论前端发送的哪种格式的数据,我们都可以使用统一的方式读取数据。
  • restframework内的Request常用属性

    • 1.request.data返回解析之后的请求体数据,类似于Django标准的request.POST和request.FILES属性,但提供如下特征:
      • 1.1包含了解析之后的文件和费文件
      • 1.2包含了对POST、PUT、PATCH请求方式解析后的数据
      • 1.3利用了RESTfarmework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
    • 2.request.quert.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。d底层原理 getattr

    Response

restframework提供了一个响应类Response,使用该类构造响应对象时,相应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

restframework提供了Renderer渲染器,用来根据请求头中的Accept(接受数据类型声明)来自动转换相应数据到对应格式,如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

可以在rest_franewirk.settings查找所有drf默认配置项

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [  # 影响默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.TemplateHTMLRenderer',  # 浏览API渲染器
    ],
  • restframework内的Response常用属性
class Response(SimpleTemplateResponse):
    """
    An HttpResponse that allows its data to be rendered into
    arbitrary media types.
    """

    def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):

补充

  • renderers渲染器用于响应序列化为特定的媒体类型,如JSON,XML,YAML等,Django REST框架提供了各种内置的渲染器类,还支持编写自定义渲染器。将渲染器指定为可迭代类型(即元组、列表、集合等)。这意味着可以为单个视图/视图集使用多个渲染器,根据请求中收到的媒体类型选择渲染器。我们还可以在设置总全局指定默认渲染器。
  • RESTAPI最常见的相应类型通常是JSON。Django还支持定义自己的自定义渲染器,这使您可以灵活地设计自己的媒体类型。结合前端模板进行数据渲染,可视化目标。
  • 1.data数据不要是render处理之后的数据,只需要传递python的内建类型数据即可,restframework会使用renderer渲染器处理data。
  • data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了python字典类型)再传递给data参数

属性

  • data=None:为了响应准备的序列化处理后的数据,传给response对象的序列化后,但尚未render处理的数据,常用img

  • status=None:状态码,默认200,drf帮咱们把所有的http响应状态码都做成了常量,可以直接导进来并使用,我们也可以通过点的方式主动修改状态码img

  • headers=None:用于存放响应头信息的字典,我们就可以在响应头的地方看到我们所携带的数据,如果在浏览器访问不到那么可能就是没有配置该app,我们到setting中配置一下即可,如果我们内部前面设置的需要传入的字典中和我们想要传递给响应头的数据重名那么就会修改该value值换成我们后面给它增加的值,如果没有那么我们后面加的值就会被前端响应头接收img

    def sponse(request):
        d = {'aaa':'bbb'}
        res = JsonResponse(d)
        res['xxx'] = 'yyy'
        return res
    
  • tempate_name=None:模板名称,如果使用HTMLRenderer时需要知名数据类型

  • content_type=None:响数据来设置该参数应数据的Content-Type,通常此参数无需传递,RESTframework会根据前端所需类型

  • drf能够解析的请求编码与响应编码

    • urlencoded
    • form-data
    • json
  • 其实通过配置完成,即使我们的项目中没有配置改文件,他也可以在drf内置文件中帮我们解析出该编码,因为他内置文件中也有一套默认的配置,是drf提前帮我们配好的

  • drf和Django一样都是有两套配置,一套是项目中的配置(setting.py),另一套则是默认的配置

  • drf的配置文件wettings.py中有DEFAULT_PARSER_CLASSES(默认的解析类)

DEFAULTS = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',  # 可以解析json格式的数据
        'rest_framework.parsers.FormParser',  # 可以解析urlencoded格式数据
        'rest_framework.parsers.MultiPartParser'  # 可以解析form-data格式的数据
    ]}
  • 如何让我们的接口统一只能接受某一种格式,例如(JSON格式)
  • 方式一:全局配置中修改该配置(注释掉),那么我们以后所有的接口都会遵循改配置,除非我们在自己的项目中再次重写该配置,一般不建议这样做
REST_FRAMEWORK = {
                'DEFAULT_PARSER_CLASSES': [
                    'rest_framework.parsers.JSONParser',
                    # 'rest_framework.parsers.FormParser',
                    # 'rest_framework.parsers.MultiPartParser',
                ],
            }

方式二:局部配置,由于解析类的使用顺序是优先使用自己的,然后再去项目的配置文件中寻找,最后去内置文件中寻找,只要找到一个那么就不会使用后面的配置

class TestView(APIView):
    cparser_classes = [JSONarser.FormParser,MultiPartParser]
    
  • 在我们实际的项目中,使用最多的就是运行JSONParser,FormParser,如果上传文件的话只允许使用MultiPartParser,为了避免出错的情况,少使用一种格式的数据就会少一分报错的风险。

响应编码

如果使用浏览器,那么就会被restframework渲染变得更好看一些,如果使用postman看到的就会是json格式的格式
# 全局配置:在项目的配置文件
    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES': [
            # 'rest_framework.renderers.JSONRenderer', # json格式
            'rest_framework.renderers.BrowsableAPIRenderer', #浏览器的格式
        ]
    }
# 局部配置:
class TestView(APIView):
    renderer_classes = [JSONRenderer,]
    
# 实际编码中,响应一般步配,就用默认

drf视图组件

基于APIView写五个接口

  • Serializer页面
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
  • views页面
mework import serializers
from rest_framework.response import Response
from .serializer import BookSerializer
from .models import Book
from rest_framework.views import APIView


class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        res = BookSerializer(instance=book_list, many=True)
        return Response(res.data)

    def post(self, request):
        res = BookSerializer(data=request.data)
        if res.is_valid():
            res.save()
            return Response({'code': 100, 'msg': '新增成功'}, status=201)
        else:
            return Response({'code': 101, 'msg': res.errors})


class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        res = BookSerializer(instance=book)
        return Response(res)

    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        res = BookSerializer(instance=book, data=request.data)
        if res.is_valid():
            res.save()
            return Response({'code': '100', 'msg': '修改成功'}, status=201)
        else:
            return Response({'code': 101, 'msg': res.errors})

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

基于GenericAPIView写五个接口

from rest_framework.response import Response
from .serializer import BookSerializer
from .models import Book
from rest_framework.views import APIView

from rest_framework.generics import GenericAPIView


class BookView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        book_list = self.get_queryset()
        res = self.get_serializer(instance=book_list, many=True)
        return Response(res.data)

    def post(self, request):
        res = self.get_serializer(data=request.data)
        if res.is_valid():
            res.save()
            return Response({'code': 100, 'msg': '新增成功'})
        else:
            return Response({'code': 101, 'msg': res.error})

class BookDetailView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get(self, request, pk):
        book = self.get_object()
        res = self.get_serializer(instance=book)
        return Response(res.data)

    def put(self, request, pk):
        book = self.get_object()
        res = self.get_serializer(instance=book, data=request.data)
        if res.is_valid():
            res.save()
            return Response({'code':100, 'msg':'修改成功'}, status=201)
        else:
            return Response({'code':101, 'msg':res.error})

    def delete(self, request, pk):
        self.get_queryset().filter(pk=pk).delete()
        return Response('')

练习:

  • 五视图

class GetListView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class GetListData(GenericAPIView):

    def get(self, request):
        book_list = self.get_queryset()
        res = self.get_serializer(instance=book_list, many=True)
        return Response(res.data)


class PostData(GenericAPIView):
    def post(self, request):
        res = self.get_serializer(data=request.data)
        if res.is_valid():
            res.save()
            return Response({'code': 100, 'msg': '新增成功'})
        else:
            return Response({'code': 101, 'msg': res.error})
        # Postmsg.postinfo(self, res)


class GetOneData(GenericAPIView):
    def get(self, request, pk):
        book = self.get_object()
        res = self.get_serializer(instance=book)
        return Response(res.data)


class PutData(GenericAPIView):
    def put(self, request, pk):
        book = self.get_object()
        res = self.get_serializer(instance=book, data=request.data)
        if res.is_valid():
            res.save()
            return Response({'code': 100, 'msg': '修改成功'}, status=201)
        else:
            return Response({'code': 101, 'msg': res.error})
        # Postmsg.postinfo(self, res)


class DeleteData(GenericAPIView):
    def delete(self, request, pk):
        self.get_queryset().filter(pk=pk).delete()
        return Response('')
  • 九视图

class GetListView(GenericAPIView, GetListData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class GetOneView(GenericAPIView, GetOneData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class GetAndPostView(GenericAPIView, GetListData, PostData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class PostView(GenericAPIView, PostData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class PutView(GenericAPIView, PutData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class DeleteView(GenericAPIView, DeleteData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class GETOneAndPutView(GenericAPIView, GetOneData, PutData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class GetOneAndDeleteDataView(GenericAPIView, GetOneData, DeleteData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class GetOneAndPutAndDeleteDataView(GenericAPIView, GetOneData, DeleteData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class PutDataAndDeleteDataView(GenericAPIView, PutData, DeleteData):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
posted @ 2022-09-29 22:07  Joseph-bright  阅读(38)  评论(0编辑  收藏  举报