• 分解drf


    注意:
        DRF是一种编程风格,不是框架。drf真实好用,其好处可以认为是组件式的。他主要很好的解决下面几个问题。

    权限

    身份认证
    权限
    注意:都可以使用全局,或者局部;个人建议局部使用
    身份认证
    from rest_framework.permissions import IsAuthenticated,IsAdminUser;具体使用见jwt
    自定义权限
    局部使用
    from rest_framework import permissions
    class IsOwnerOrReadOnly(permissions.BasePermission):
      """
      自定义权限只允许对象的所有者编辑它。
      """
      def has_object_permission(self, request, view, obj):
          # 读取权限允许任何请求,
          # 所以我们总是允许GET,HEAD或OPTIONS请求。
          if request.method in permissions.SAFE_METHODS:
              return True
          # 只有该snippet的所有者才允许写权限。
          return obj.owner == request.user

    序列化

    概要
    序列化 序列化器会将模型类对象转化为字典,response 后变成 json 字符串。

    反序列化 把客户发送过来的数据, request 后变成字典,序列化器可以将字典转成模型,同时校验客户发送数据的合法性。

    序列化器(类) 开发者定义的一个实现序列化和反序列化的类。

    模型序列化器(类) 一种对应 Django 模型的序列化器。【ModelSerializer】

    序列化器基类 DRF 中所有的序列化器类都必须继承于序列化器基类(rest_framework.serializers.Serializer) 。

    模型序列化器基类 序列化器基类的子类,同时 DRF 中所有的序列化器类都必须继承于 rest_framework.serializers.ModelSerializer。
    ModelSerializer
    from rest_framework import serializers 
    class CategoryModelserializers(serializers.ModelSerializer):
    #todo 这里可以添加对某些参数的校验,如下:BB
      class Meta:
          model = Category
          # 指定
          fields =['id',"name"]
          # 所有的
    fields ="__all__"
    # 排除某些字段
    exclude = ('status',)
    BB实例
    name = serializers.CharField(max_length=50, label='分类名称', help_text='帮助文档',
                                    validators=[validators.UniqueValidator(queryset=Project.objects.all(), message="分类名已存在")])
    email = serializers.EmailField(max_length=50)
    如果创建和更新较固定。序列化与反序列化
    from rest_framework import serializers
    from .models import book, LANGUAGE_CHOICES, STYLE_CHOICES


    class bookSerializer(serializers.Serializer):
      id = serializers.IntegerField(read_only=True)
      title = serializers.CharField(required=False, allow_blank=True, max_length=100)
      style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

      def create(self, validated_data):
          """
          根据提供的验证过的数据创建并返回一个新的`Snippet`实例。
          """
          return book.objects.create(**validated_data)

      def update(self, instance, validated_data):
          """
          根据提供的验证过的数据更新和返回一个已经存在的`Snippet`实例。
          """
          instance.title = validated_data.get('title', instance.title)
          instance.style = validated_data.get('style', instance.style)
          instance.save()
          return instance
    注意:
    create还是update,django内部会自行调用。开发者只管在视图中save即可。
    参考链接:https://www.cnblogs.com/zhaoyuanshi/p/16079279.html
    数据校验
    字段校验
    验证一个字段
    class TestSerializer(serializers.Serializer):
      def validate_<字段名>(self,value):
            pass
            return value

    验证多个字段
    class TestSerializer(serializers.Serializer):
      def validate(self,attrs):
          pass
          return attrs
    自定义校验validators
    一般在模型序列调用is_valid方法时才会校验。不限于get,post请求
    serializer = StudentSerializer(instance=student, data=data)
    # 获取验证结果
    serializer.is_valid(raise_exception=True) # 抛出异常

    自定义实现如下

    def check_sex(value):
      """
      外部校验器 validator
      """
      if value not in [0, 1, 2]:
          raise serializers.ValidationError(
              detail='性别设置错误',
              code='check_sex'
          )
      return value

    class StudentSerializer(serializers.Serializer):
      # read_only=True,在客户端提交数据[反序列化阶段]不要求的字段
      id = serializers.IntegerField(read_only=True)
      # 最大值 max_value 和最小值 min_value
      age = serializers.IntegerField(
          max_value=100,
          min_value=0,
          error_messages={
              "min_value": "Age must older than 0",
              "max_value": "Age must younger than 100"
          }
      )
      # 默认值为 True
      active = serializers.BooleanField(default=True)
      # validator的值为列表,列表的成员为函数名,而不是函数的调用
      sex = serializers.IntegerField(validators=[check_sex])

     

    视图

    DRF框架的视图的基类是 APIView
    APIView的基本使用和View类似
    用户发起请求,请求会转向到apiview时,apiview会继承drf的as_view,然后as_view继承django的view。
    django的view会调用apiview的dispatch方法【这里其实就知道了请求的名字,也就知道路由】,然后将结果返回到django的as_view方法。
    接着django的as_view返回给apiview的as_view,最后apiview将结果指向到用户定义的apiview

    视图如下

     

    apiview与view的区别
    Django默认的View请求对象是 HttpRequest,REST framework 的请求对象是 Request。
    Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
    HttpRequest.GET.get ————> Request.query_params
    HttpRequest.POST.get 、HttpRequest.body.get————> Request.data;json.loads(request.body)
    Django默认的View响应对象是 HttpResponse(以及子类),REST framework 的响应对象是Response。
    支持定义的属性:
      authentication_classes列表或元祖,身份认证类
      permissoin_classes列表或元祖,权限检查类
      throttle_classes列表或元祖,流量控制类。
       
    4. 任何APIException异常都会被捕获到,并且处理成合适的响应信息;APIException异常捕获  
    GenericAPIView
    GenericAPIView是继承自APIView,GenericAPIView肯定在APIView的基础上封装了一些属性和方法:增加了对于列表视图和详情视图可能用到的通用方法和属性的支持

      属性:
          queryset 设置结果集
          serializer_class 设置序列化器
          lookup_field 查询指定的对象
      方法:
          get_queryset(self) 返回视图使用的查询集
          get_serializer(self,_args, *_kwargs) 返回序列化器对象
          get_object(self) 返回详情视图所需的模型类数据对象
    GenericAPIView和Mixin配合使用
    mixin类提供用于提供基本视图行为的操作。
    请注意,mixin类提供了操作方法,而不是直接定义处理程序方法,例如.get()和.post()。这允许更灵活的行为组合。

    ListModelMixin
    提供一种.list(request, *args, **kwargs)实现列出查询集的方法。

    CreateModelMixin
    提供.create(request, *args, **kwargs)实现创建和保存新模型实例的方法。

    RetrieveModelMixin
    提供一种.retrieve(request, *args, **kwargs)方法

    UpdateModelMixin
    提供.update(request, *args, **kwargs)实现更新和保存现有模型实例的方法。

    DestroyModelMixin
    提供一种.destroy(request, *args, **kwargs)实现删除现有模型实例的方法。
    viewSet
    APIView,GenericAPIView,ListAPIView 都是继承自View
    继承自View的类视图,只能定义相同的一个函数名,例如:只能定义一个get,post方法
    那么:
      列表视图中 设置了 queryset,serializer_class get,post
      详情视图中也设置了 queryset,serializer_class get,put,delete
      能否将这两个视图合并?我们是可以将 列表和详情视图 组合到一起的,称之为 视图集 ViewSet
    它不提供任何方法处理程序( 如get(),post() ),而是提供了诸如list() create()之类的操作
    三级视图
    CreateAPIView
    提供post方法处理程序。
    ListAPIView
    用于只读端点以表示模型实例的集合。
    提供get方法处理程序。

    RetrieveAPIView
    用于表示单个模型实例的只读端点。
    提供get方法处理程序。

    DestroyAPIView
    用于单个模型实例的仅删除端点。
    提供delete方法处理程序。

    UpdateAPIView
    用于单个模型实例的仅更新端点。
    提供put和patch方法处理程序。

    ListCreateAPIView
    用于读写端点以表示模型实例的集合。
    提供get和post方法处理程序。

    RetrieveUpdateAPIView
    用于读取或更新端点以表示单个模型实例。
    提供get,put并且patch方法处理。
    RetrieveDestroyAPIView
    用于读取或删除端点以表示单个模型实例。
    提供get和delete方法处理程序。
    RetrieveUpdateDestroyAPIView
    用于读写 - 删除端点以表示单个模型实例。
    提供get,put,patch和delete方法处理。

    分页器

    分页模式
    rest framework中提供了三种分页模式:
    from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
    全局配置在setting文件
      REST_FRAMEWORK = {
          'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
          'PAGE_SIZE': 100
      }

    局部配置
      class PublisherViewSet(ModelViewSet):
          queryset = models.Publisher.objects.all()   # 只有差所有才需要分页
          serializer_class = PublisherModelSerializer
          pagination_class = PageNumberPagination # 注意不是列表(只能有一个分页模式)

    DRF内置分页器
      PageNumberPagination
      按页码数分页,第n页,每页显示m条数据
      例如:http://127.0.0.1:8000/api/article/?page=2&size=1
      class MyPageNumberPagination(PageNumberPagination):
          page_size=3 #每页条数
          page_query_param='aaa' #查询第几页的key, 默认是page
          page_size_query_param='size' # 每一页显示的条数
          max_page_size=5   # 每页最大显示条数


      LimitOffsetPagination
      分页,在n位置,向后查看m条数据
      例如:http://127.0.0.1:8000/api/article/?offset=2&limit=2
      class MyLimitOffsetPagination(LimitOffsetPagination):
          default_limit = 3   # 每页条数
          limit_query_param = 'limit' # 往后拿几条
          offset_query_param = 'offset' # 标杆
          max_limit = 5   # 每页最大几条


      CursorPagination
      加密分页,把上一页和下一页的id值记住,只提供上一页和下一页url,效率最高,速度最快
      列如: http://127.0.0.1:8000/api/book2/?cursor=cD0xMw%3D%3D
      class MyCursorPagination(CursorPagination):
          cursor_query_param = 'cursor' # 每一页查询的key
          page_size = 2   # 每页显示的条数
          ordering = '-id' # 排序字段
    调用方式
    # 查询语句
      ret=models.Book.objects.all()
          # 实例化对象
      page=MyPageNumberPagination()
          # 在数据库中获取分页的数据
      page_list=page.paginate_queryset(ret,request,view=self)

    频率

    # 获取登录主机的id
    id = request.META.get('REMOTE_ADDR')
    # 访问者,dict类型
    visit_record
    #访问时间
    self.history

    路由

    1.一般路由
    viewSet
      2.DefaultRouter
      3.SimpleRouter
    4.自定义视图路由action
    一般路由
    我们在使用视图集的过程中,要对路由进行映射,当扩展方法过多时,路由会写的很长,如下:
    如果在括号中不写东西的话,那么自带的方法是比较少的get,post,put,delete
    urlpatterns = [
    path('bookinfo/',BookOperation.as_view({'get':'list','post':'create'})),
    re_path(r'bookinfo/(?P<pk>\d+)/',BookOperation.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
    ]
    DefaultRouter
    from django.urls import path,re_path
    from rest_framework.routers import DefaultRouter,SimpleRouter
    from .views import BookOperation

    urlpatterns = [
    # path('bookinfo/',BookOperation.as_view({'get':'list','post':'create'})),
    # re_path(r'bookinfo/(?P<pk>\d+)/',BookOperation.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
    ]

    # 创建路由对象
    router = DefaultRouter()
    SimpleRouter
    # views.py
    class BookModelViewSet(ModelViewSet):
      queryset = models.Book.objects.all()
      serializer_class = ser.BookModelSerializer

      def list(self, request, *args, **kwargs):
          book_list = self.get_queryset()[:3]
          ser_obj = self.get_serializer(book_list, many=True)
          return Response(ser_obj.data)

       
    # urls.py
    # 第一步
    from rest_framework import routers
    from app01 import views
    # 第二步
    router = routers.SimpleRouter()
    # 第三步
    router.register(prefix='books', viewset=views.BookModelViewSet)

    urlpatterns = [
      url(r'^admin/', admin.site.urls),
    ]
    # 第四步
    urlpatterns += router.urls


    # 新增的两条url
    print(router.urls)
    [
      <RegexURLPattern book-list ^books/$>,
      <RegexURLPattern book-detail ^books/(?P<pk>[^/.]+)/$>
    ]
    自定义视图路由action
    # 用途
    为了给继承自ModelViewSet的视图类中定义的函数也添加路由
    # 使用
    from rest_framework.decorators import action
      class BookModelViewSet(ModelViewSet):

          queryset = models.Book.objects.all()
          serializer_class = ser.BookModelSerializer

          @action(methods=['get'], detail=False)
          def get_top3(self, request):
              print(request.user.username)
              book_list = self.get_queryset()[:3]
              ser_obj = self.get_serializer(book_list, many=True)
              return Response(ser_obj.data)
    # 参数说明:
    methods参数赋值一个列表,放可以访问该方法的请求方式
      detail参数是布尔值:
      detail=False表示方法是不使用pk;^books/get_top3/$
          反之使用pk参数;^books/(?P<pk>[^/.]+)/get_top3/$
           
    # 总结:action装饰器,放在被装饰的函数上方,method:请求方式,detail:是否带pk

    DefaultRouter 与SimpleRouter区别

    在这里可以看到基于drf的viewSet与传统的django view有本质的不同DRF编写的ViewSet不是直接写在urlpatterns中,而是通过router注册的形式。
    先声明一个Router类的实例,然后再这个router中调用register方式注册api
    相比较DefaultRouter,SimpleRouter少了很多URLPAttern,一般多出的是detail,对应的方法。

     

    解析器

    get
    request.query_params.get("data")
    put
    update_data = request.data.get("is_show")
    post
    data = json.loads(request.body.decode())

    原生的Django的Request只支持如下两种类型
    application/x-www-form-urlencoded(只能上传文本格式的文件)----->request.POST
    multipart/form-data(以二进制的形式上传)---->reuqest.FILES
    很好的解析了django为何使用json的json.loads进行转化,而不是直接使用自己的方法。
    当然drf解决了这个问题,但是实际的开发过程中并没有太多的开发者直接使用。
    具体使用如下:
    全局配置
    REST_FRAMEWORK = {
      'DEFAULT_PARSER_CLASSES': (
          'rest_framework.parsers.JSONParser',
      )
    }
    局部使用
    class BookViewSet(ModelViewSet):
      queryset = models.Book.objects.all()
      serializer_class = BookModelSerializer
      parser_classes = [JSONParser, ]

    响应器

    全局使用
    settings里配置:
    REST_FRAMEWORK = {
      'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer']
    }
    局部使用
    from rest_framework.renderers import HTMLFormRenderer,BrowsableAPIRenderer
    class BookDetailView(APIView):
      renderer_classes = [HTMLFormRenderer,BrowsableAPIRenderer ]
      def get(self,request,pk):
          book_obj=models.Book.objects.filter(pk=pk).first()
          bs=BookSerializers(book_obj,many=False)
          return Response(bs.data)
     
  • 相关阅读:
    LAMP架构实现-单机module形式
    16.同步类容器Collections.synchronized
    【dart 语法】String 介绍
    【flutter】Widget
    【flutter 入门】项目结构
    【flutter 安装详解 一步到位的】
    【iOS知识汇】storyboard tableview 自适应高度cell
    pod install 卡住 去掉 pods更新直接下载库文件
    【iOS知识汇】textField监听
    纪念第一次笔试全AC,居然来自滴滴~
  • 原文地址:https://www.cnblogs.com/topass123/p/16609637.html
Copyright © 2020-2023  润新知