测试开发进阶(二十九)

欢迎关注我的公众号「测试游记」

再次优化

查看 rest_framework.generics.CreateAPIView

rest_framework.generics.ListAPIView

可以看到很多重复的代码

640?wx_fmt=jpeg

rest_framework.generics.ListCreateAPIView

class ListCreateAPIView(mixins.ListModelMixin,	
                        mixins.CreateModelMixin,	
                        GenericAPIView):	
    """	
    Concrete view for listing a queryset or creating a model instance.	
    """	
    def get(self, request, *args, **kwargs):	
        return self.list(request, *args, **kwargs)	
    def post(self, request, *args, **kwargs):	
        return self.create(request, *args, **kwargs)

所以直接继承

from projects.models import Projects	
from projects.serializer import ProjectModelSerializer	
from django_filters.rest_framework import DjangoFilterBackend	
from rest_framework import generics	
class ProjectsList(generics.ListCreateAPIView):	
    ordering_fields = ['name', 'leader']	
    queryset = Projects.objects.all()	
    serializer_class = ProjectModelSerializer	
    filter_backends = [DjangoFilterBackend]	
    filterset_fields = ['name', 'leader', 'tester']	
class ProjectDetail(generics.RetrieveUpdateDestroyAPIView):	
    queryset = Projects.objects.all()	
    serializer_class = ProjectModelSerializer

现有问题

  • 两个类视图,不能合并

  • 有相同的get方法

  • 两个类视图所对应的url地址不一致

再次优化

优化思路:使用动作来触发,而不是请求方法

from rest_framework import viewsets

viewsets不再支持 get/post/put/delete等请求方法,而只支持action动作

但是 ViewSet类中没有提供 get_object(), get_serializer等方法

继承 viewsets.GenericViewSet

将两个类合成一个类

修改url

from django.urls import path	
from projects import views	
urlpatterns = [	
    path('project/', views.ProjectsViewSet.as_view({	
        'get': 'list',	
        'post': 'create'	
    }), name='projects_list'),	
    path('project/<int:pk>/', views.ProjectsViewSet.as_view({	
        'get': 'retrieve',	
        'put': 'update',	
        'delete': 'destroy'	
    }), name='project_detail')	
]

640?wx_fmt=jpeg

from projects.models import Projects	
from rest_framework import viewsets	
from projects.serializer import ProjectModelSerializer	
from django_filters.rest_framework import DjangoFilterBackend	
class ProjectsViewSet(viewsets.ModelViewSet):	
    ordering_fields = ['name', 'leader']	
    queryset = Projects.objects.all()	
    serializer_class = ProjectModelSerializer	
    filter_backends = [DjangoFilterBackend]	
    filterset_fields = ['name', 'leader', 'tester']

视图

Django中

  • View

DRF中

  • APIView

  • GenericAPIView

  • mixins扩展类

  • CreateAPIView(合并拓展类)

视图集

action和请求方法的映射

  • ViewSet

  • GenericViewSet

  • CreateViewSet

路由

from rest_framework import routers
  1. 创建SimpleRouter路由对象

  2. 注册路由

第一个参数prefix为路由前缀,一般添加为应用名称即可 第二个参数viewset为视图集「不要加as_view」

  1. 将自动生成的路由添加到列表中

from django.urls import path, include	
from projects import views	
from rest_framework import routers	
# 1.创建SimpleRouter路由对象	
router = routers.SimpleRouter()	
# 2.注册路由	
# 第一个参数prefix为路由前缀,一般添加为应用名称即可	
# 第二个参数viewset为视图集「不要加as_view」	
router.register(r'projects',views.ProjectsViewSet)	
urlpatterns = [	
        # 将自动生成的路由添加到列表中	
    path('',include(router.urls))	
]

action

自定义action

from rest_framework.decorators import action
def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs):	
    """	
    Mark a ViewSet method as a routable action.	
    Set the `detail` boolean to determine if this action should apply to	
    instance/detail requests or collection/list requests.	
    """	
    methods = ['get'] if (methods is None) else methods	
    methods = [method.lower() for method in methods]	
    assert detail is not None, (	
        "@action() missing required argument: 'detail'"	
    )	
    # name and suffix are mutually exclusive	
    if 'name' in kwargs and 'suffix' in kwargs:	
        raise TypeError("`name` and `suffix` are mutually exclusive arguments.")	
    def decorator(func):	
        func.mapping = MethodMapper(func, methods)	
        func.detail = detail	
        func.url_path = url_path if url_path else func.__name__	
        func.url_name = url_name if url_name else func.__name__.replace('_', '-')	
        func.kwargs = kwargs	
        # Set descriptive arguments for viewsets	
        if 'name' not in kwargs and 'suffix' not in kwargs:	
            func.kwargs['name'] = pretty_name(func.__name__)	
        func.kwargs['description'] = func.__doc__ or None	
        return func	
    return decorator

可以使用action装饰器来声明自定义的动作

默认情况下,实例方法名就是动作名

methods参数用于指定该动作支持的请求方法,默认为get

detail用于指定该动作要处理的是否为详情资源对象「url是否需要传递pk值」

url.py中添加

path('project/names/', views.ProjectsViewSet.as_view({	
    'get', 'names'	
}))

新增序列化器

class ProjectNameSerializer(serializers.ModelSerializer):	
    class Meta:	
        model = Projects	
        fields = ('id', 'name')

view中添加

@action(methods=['get'], detail=False)	
def names(self, request, *args, **kwargs):	
    queryset = self.get_queryset()	
    serializer = ProjectNameSerializer(instance=queryset, many=True)	
    return Response(serializer.data)

同理添加Interface

需要通过 projects/1/interfaces/来拿到 id=1interfaces信息

添加序列化器

class InterfacesNameSerializer(serializers.ModelSerializer):	
    class Meta:	
        model = Interfaces	
        fields = ('id', 'name', 'tester')	
class InterfacesByProjectIdSerializer(serializers.ModelSerializer):	
    interfaces_set = InterfacesNameSerializer(read_only=True, many=True)	
    class Meta:	
        model = Projects	
        fields = ('id', 'interfaces_sets')

添加自定义action

@action(detail=True)	
def interfaces(self, reques, *args, **kwargs):	
    instance = self.get_queryset()	
    serializer = InterfacesByProjectIdSerializer(instance=instance)	
    return Response(serializer.data)

查看路由

640?wx_fmt=jpeg

添加 url_pathurl_name

@action(methods=['get'], detail=False, url_path='nm', url_name='url_name')

640?wx_fmt=jpeg

urlpath url的路径名 urlname url的别名「应用名称-url_name」

测试

$ http :8000/projects/names/        

640?wx_fmt=jpeg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值