pythonPython项目实战

Django测试开发学习笔记(三)

2020-10-22  本文已影响0人  DayBreakL

restframework

restframework简介

它是基于Django的,帮助我们快速开发符合restful规范的接口框架,它主要适用于前后端分离项目。

文档1:https://www.django.cn/course/show-20.html

文档2:https://www.django-rest-framework.org/

快速入门

from rest_framework import routers
from . import views
router = routers.DefaultRouter()
router.register(r'projects', views.Projects)

urlpatterns = [
 ]
urlpatterns += router.urls
- 因为我们使用的是viewsets而不是views,所以我们可以通过简单地使用路由器类注册视图来自动生成API的URL conf。再次,如果我们需要对API URL进行更多的控制,我们可以简单地将其拉出来使用常规基于类的视图,并明确地编写URL conf。最后,我们将包括用于支持浏览器浏览的API的默认登录和注销视图。这是可选的,但如果您的API需要身份验证,并且你想要使用支持浏览器浏览的API,那么它们很有用。

序列化器

在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回

删:判断要删除的数据是否存在 -> 执行数据库删除

改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回

查:查询数据库 -> 将数据序列化并返回

Django REST framework(DRF) 提供了Serializer可以快速根据 Django ORM 或者其它库自动序列化/反序列化可以帮助我们简化上述部分代码编写,大大提高开发速度。

serializers
    - 反序列化使用
    ```py
    # 在视图中继续添加下面方法
    # 反序列化器的使用代码示例
          def post(self,request):
              data = request.data # 等同于 request.POST request.body
              serializer = SerializersProject(data=data)
              # is_valid按照定义的序列化器校验数据,raise_exception=True表示如果有问题时会抛出异常
              serializer.is_valid(raise_exception=True)
              # 保存数据
              serializer.save()
              # validated_data经过验证的数据
              return Response(serializer.validated_data)
    ```
    ![image](https://img.haomeiwen.com/i12041448/98a0008d9f706024.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    ![image](https://img.haomeiwen.com/i12041448/8fd4c981df14a4e4.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
ModelSerializer

相比于Serializer类序列化器,DRF还提供了一个更加深度封装的ModelSerializer模型类序列化器,可以帮助我们更快的、傻瓜式的创建一个Serializer类。

序列化器常用操作
- Validation自定义验证逻辑(多字段)
```py
# 继承ModelSerializer类
class ModelSerializerProject(serializers.ModelSerializer):
# 新增两个字段,用来讲解validate多字段验证
startTime = serializers.IntegerField()
endTime = serializers.IntegerField()

class Meta:
    # 指定要序列化的model
    model = Project
    # 指定要序列化的字段
    fields = '__all__'  # 所有字段
    # fileds=[] 选择字段
    extra_kwargs = {  # 使用extra_kwargs可以给字段添加额外的参数,而不用重新定义该字段
        "name": {
            "required": True,
            "max_length": 40,
            "min_length": 4,
            "error_messages": {
                "required": "项目名必填",
                "max_length": "项目名不超过40位",
                "min_length": "项目名不少于4位"
            }
        }
    }

def validate_name(self, value):
    # 只能输入字母和汉字
    r = r'^[\da-zA-Z_\u4e00-\u9fa5]{4,40}$'
    if re.match(r, value):
        return value
    else:
        raise serializers.ValidationError("项目名称为4-40位字母或汉字")

# 多字段验证
def validate(self, attrs):
    print("attrs:{}".format(attrs))
    startTime = attrs.pop("startTime")
    endTime = attrs.pop("endTime")
    if endTime > startTime:
        return attrs
    else:
        raise serializers.ValidationError("结束时间必须大于开始时间")
```

结束时间大于开始时间:

![image](https://img.haomeiwen.com/i12041448/f44238c7fa4047ae.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

结束时间小于开始时间:

![image](https://img.haomeiwen.com/i12041448/d3cd5fe91257b578.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
子序列化 (没懂)

view视图

APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIView与View不同之处在于:

用户认证
权限控制
流量控制

节流又叫限流,限制访问。就是通常一个用户在多次请求一个页面,或者点击一个链接的时候,前几次点击是没有问题的,但是一旦连续几次之后,就会出现访问受限,离下一次访问还有50秒等的字样,在django rest framework 中有一个专门的组件来做限制访问。 例如:手机接收验证码

    未登录用户访问5次后,效果:
    
    ![image](https://img.haomeiwen.com/i12041448/8edb4cf73c26df69.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    已登录用户访问10次,效果:
    
    ![image](https://img.haomeiwen.com/i12041448/9b98d101416d3277.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
  - 局部配置(在视图中进行配置)
    
  ```py
  # 导入自定义频率
  from rest_framework.throttling import AnonRateThrottle
  from rest_framework.throttling import UserRateThrottl
  
  class TestLogin(APIView):
    throttle_classes =[AnonRateThrottle,UserRateThrottle]
    
    def get(self, request):
        return Response("{}".format(request.user))
  ```
请求和响应
from django.http import QueryDict
from rest_framework.request import Request

def get_parameter_dic(request, *args, **kwargs):
    if isinstance(request, Request) == False:
        return {}

    query_params = request.query_params
    if isinstance(query_params, QueryDict):
        query_params = query_params.dict()
    result_data = request.data
    if isinstance(result_data, QueryDict):
        result_data = result_data.dict()

    if query_params != {}:
        return query_params
    else:
        return result_data
utils文件夹下新增custom_response.py

```py
from rest_framework.response import Response
# 自定义一个响应,继承自Response类
class CustomResponse(Response):
    def __init__(self, *args, code='0000', msg="成功", **kwargs):
        # 格式化data
        data = {
            "code": code,
            "message": msg
        }
        if args is not None:
            data["data"] = args[0]
            kwargs["data"] = data
        elif "data" in kwargs:
            data["data"] = kwargs["data"]
            kwargs["data"] = data

        super().__init__(**kwargs)

```

views.py下修改:

 ![image](https://img.haomeiwen.com/i12041448/7b888e74144989c9.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

效果如下:

![image](https://img.haomeiwen.com/i12041448/75c6adc034fa1b39.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
GenericAPIView

rest_framework.generics.GenericAPIView,继承自APIVIew,增加了对于列表视图和详情视图可能用到的通用支持方法。通常使用时,可搭配一个或多个Mixin扩展类。

基本使用
```py
from django_filters import rest_framework as filters
from . import models

class ProjectFilter(filters.FilterSet):
    # field_name要过滤的字段 lookup_expr要过滤的规则
    name = filters.CharFilter(field_name="name", lookup_expr='contains')  # 对名字进行模糊查询
    ver = filters.CharFilter(field_name="version")  # 字段可以自己重新命名,对version进行精确查询

    class Meta:
        model = models.Project
        fields = ['name','ver']  # 指定查询参数
```

- 自定义过滤字段和模型对照表

![image](https://img.haomeiwen.com/i12041448/45475a648e36ad55.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

- 视图中指定查询类

```py
# 使用GenericAPIView
class Projects(GenericAPIView):
    queryset = Project.objects.all() 
    serializer_class = serializers.ModelSerializerProject
    # 针对某个GenericAPIView视图添加过滤
    filter_backends = [django_filters.rest_framework.DjangoFilterBackend]
     # 指定查询类
    filterset_class = ProjectFilter

    def get(self, request):
        projects = self.get_queryset()
        # 使用filter_queryset方法对查询集进行过滤
        serializer = self.get_serializer(instance=self.filter_queryset(projects), many=True)
        return Response(serializer.data)
```

![image](https://img.haomeiwen.com/i12041448/04850db0ec269c3f.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我们数据库有几千万条数据,这些数据需要展示,我们不可能直接从数据库把数据全部读取出来.
因为这样会给内存造成巨大的压力,很容易就会内存溢出,所以我们希望一点一点的取。同样,展示的时候也是一样的,我们必定会对数据进行分页显示。

1)分页器配置文件

应用下新建custom_paginations.py

from rest_framework import pagination

class PageNumberPagination(pagination.PageNumberPagination):
    """查第n页,每页显示n条数据"""
    page_size = 1  # 指定每页默认显示多少条数据
    page_size_query_param = 'size'  # URL参数中每页显示条数的参数
    page_query_param = 'page'  # URL中页码的参数
    max_page_size = 40  # 每页最多显示多少条数据

2)视图函数使用分页器

class Projects(GenericAPIView):
  queryset = Project.objects.all()
  serializer_class = serializers.ModelSerializerProject
  filter_backends = [django_filters.rest_framework.DjangoFilterBackend,filters.OrderingFilter]
  filterset_class = ProjectFilter
  ordering_fields = ['id']
  # 指定默认排序字段
  ordering = ['-id']
  # 1. 指定分页器对象
  pagination_class = PageNumberPagination

  def get(self, request):
      # 在过滤后端下,这些写
      projects = self.filter_queryset(self.get_queryset())
      # 2. 使用自己配置的分页器调用分页方法进行分页
      page_obj = self.paginate_queryset(projects)
      # 3. 序列化我们分页好的数据
      serializer = self.get_serializer(instance=page_obj, many=True)
      # 4. 返回带上一页/下一页连接的页面
      return self.get_paginated_response(serializer.data)

效果:可以在过滤下分页,选择第几页,每页展示多少条数据

image

前端展示分页时,可以直接调用上一页链接和下一页链接

image
View、APIView、GenericAPIView的区别

https://www.cnblogs.com/hanbowen/p/9885358.html

mixins类

和GenericAPIView一同搭配使用的还有五个扩展类,他们分别是ListModelMixin, CreateModelMixin,UpdataModelMixin,RetrieveModelMixin,DestroyModelMixin

image

mixin 混合类,不能单独使用,需要利用python支持多继承结合GenericAPIView一起用

class Projects(ListModelMixin,GenericAPIView):
    queryset = Project.objects.all()
    serializer_class = serializers.ModelSerializerProject
    filter_backends = [django_filters.rest_framework.DjangoFilterBackend, filters.OrderingFilter]
    filterset_class = ProjectFilter
    ordering_fields = ['id']
    ordering = ['-id']

    def get(self, request,*args,**kwargs):
        return self.list(request,*args,**kwargs)
GenericAPIView+mixins

继承这些类时,要重写下面的方法。

image image image image image
ViewSet的使用

ModelViewSet继承了下图这些类,所以我们在使用ModelViewSet时,不用再加继承ListModelMixin等。

image

views.py

# 使用ModelViewSet
 class Projects(ModelViewSet):
     queryset = Project.objects.all()
     serializer_class = serializers.ModelSerializerProject
     filter_backends = [django_filters.rest_framework.DjangoFilterBackend, filters.OrderingFilter]
     filterset_class = ProjectFilter
     ordering_fields = ['id']
     ordering = ['-id']
 # 路由配置中显示指定请求方法对应的视图
 urlpatterns = [
   path('projects/',views.Projects.as_view({'get': 'list','post':'create'}))
  ]
image

路由控制

view视图总结

上一篇下一篇

猜你喜欢

热点阅读