查看 rest_framework.generics.CreateAPIView
rest_framework.generics.ListAPIView
可以看到很多重复的代码
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//', views.ProjectsViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}), name='project_detail')
]
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
创建SimpleRouter路由对象
注册路由
第一个参数prefix为路由前缀,一般添加为应用名称即可 第二个参数viewset为视图集「不要加as_view」
将自动生成的路由添加到列表中
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))
]
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=1
的 interfaces
信息
添加序列化器
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)
添加 url_path
和 url_name
@action(methods=['get'], detail=False, url_path='nm', url_name='url_name')
urlpath url的路径名 urlname url的别名「应用名称-url_name」
$ http :8000/projects/names/