1. mixin 和 viewsets
drf
视图中用到最多的(继承)就是 viewsets.GenericViewSet
和 mixin
中的五个方法,视图主要可分为以下几类:
GenericViewSet(viewsets) # drf 最高级
GenericAPIView # drf
APIView # drf
View # django 自带
每个 view
的功能也不尽相同,主要是因为 mixin
的存在,mixin
总共分为五个通用类视图,每个都与模型相关:
CreateModelMixin
:新增单条ListModelMixin
:获取多个UpdateModelMixin
:更新单个RetrieveModelMixin
:获取单个(详情)DestoryModelMixin
:删除单个
可以说这五个类涉及到了模型相关的所有操作:增删改查,还有数据的序列化、分页等操作,继承它们可以免去自己写的烦恼。
mixin.py
源码:
"""
Basic building blocks for generic class based views.
We don't bind behaviour to http method handlers yet,
which allows mixin classes to be composed in interesting ways.
"""
from rest_framework import status
from rest_framework.response import Response
from rest_framework.settings import api_settings
class CreateModelMixin:
"""
Create a model instance. 创建一个模型实例
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
class ListModelMixin:
"""
List a queryset. 列出一个查询集
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class RetrieveModelMixin:
"""
Retrieve a model instance. 检索模型实例
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class UpdateModelMixin:
"""
Update a model instance. 更新模型实例
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
class DestroyModelMixin:
"""
Destroy a model instance. 销毁一个模型实例
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
示例对比
以下均为获取商品列表数据,视图函数分别继承的是APIView
和 ``
1、使用 APIView
:
class GoodsListView(APIView):
"""
商品列表
"""
def get(self, request, format=None):
goods = Goods.objects.all()
goods_serilizer = GoodsSerializer(goods, many=True)
return Response(goods_serilizer.data)
2、使用 ListModelMixin 和 GenericViewSet
:
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
商品列表页
"""
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
因为 ListModelMixin
内部实现了数据查询集(商品列表数据查询)、分页以及序列化,在使用时只需重写即可。
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
# 数据集
queryset = self.filter_queryset(self.get_queryset())
# 分页
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
# 序列化
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
这里采用的是 mixin
混入类,ListModelMixin
中并没有 get_queryset()、paginate_queryset() 和 get_serializer()
方法,而是调用的 GenericViewSet
中的相关方法。
2. Request 和 Response 对象
drf
对原有 Django
的 HttpRequest、HttpResponse
做了相应的增强,使用起来更加灵活。
2.1 Request 对象
常用方法或属性
方法 | 作用 | 说明 |
---|---|---|
request.data | 返回请求的解析内容 | 可解析文件、非文件(non-file inputs)、POST 以外的请求方式(如 PUT、PATCH)等 |
.query_params | 类似于 request.GET | 推荐使用,不仅适用 GET 请求,其他请求方式也适用 |
.parser | 解析器 | 通常不需要关注 |
2.2 Response 对象
Response
对象可以根据客户端请求返回不同的数据格式(如:JSON、HTML、FORM 表单之类)。
Response
类使用的渲染器不能处理复杂的数据类型(如:Django 模型实例),需要在创建 Response
对象之前将数据序列化为基本的数据类型(如:drf
的 Serializer
类,或其他)。
Response
构造方法:
Response(data, status=None, template_name=None, headers=None, content_type=None)
data
:响应的序列化数据status
:响应状态码,默认 200template_name
:选择HTMLRenderer
时使用的模板名称headers
:设置HTTP header
字典类型content_type
:响应的内存类型,通常渲染器会根据内容协商的结果自动设置,但有时也需要手动设置
属性
.data
:未渲染,但已序列化的响应数据.status_code
:状态码.content
:将会响应的内容,必须先调用.render()
方法,才能访问.content
.template_name
:只有在response
的渲染器是HTMLRenderer
或其他自定义模板渲染器时才需要提供.accepted_renderer
:用于将会返回的响应内容的渲染器实例,从视图返回响应之前由APIView
或@api_view
自动设置.accepted_media_type
:内容协商阶段选择的媒体类型,从视图返回响应之前由APIView
或@api_view
自动设置.renderer_context
:将传递给渲染器的.render()
方法的附加的上下文信息字典,视图返回响应之前由APIView
或@api_view
自动设置
3. 全自动路由 DefaultRouter
1、urls.py
from django.conf.urls import url, include
from rest_framework import routers
from api.views import TestView, TestView1
router = routers.DefaultRouter()
router.register(r'test1', TestView1)
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
]
2、views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView1(ModelViewSet):
queryset = models.Role.objects.all()
serializer_class = TestSerializers
pagination_class = PageNumberPagination
自定义路由:
from django.conf.urls import url, include
from rest_framework import routers
from api.views import TestView, TestView1
urlpatterns = [
path('test1/', TestView1.as_view(), name='test1')
]