DRF框架的使用入门(三)ModelSerializer和各类View详解

DRF框架的使用入门(三)ModelSerializer和各类View详解

  • 详解ModelSerializer
    • 三种基本序列化字段方式
    • 指定嵌套序列化
    • 指定字段序列化(即覆盖)
    • 附加关键字参数
  • request和response
    • request请求
    • response类
  • View视图使用
    • APIView(一级视图)
      • 点击查看类内容:
      • 写一个get和post请求实例:
    • GenericAPIView(二级视图)和mixins
      • GenericAPIView的属性
      • mixins类
      • 混合使用实例:
    • 三级视图(XXAPIView)
    • ViewSet的使用
      • ViewSet添加自定义动作
      • ViewSet的默认url配置动作:

前文:推荐看官网
环境:版本(django1.11, python3.5),适用于前后端分离项目

详解ModelSerializer

三种基本序列化字段方式

拿之前的过来用:

from rest_framework import serializers
from goods.models import GoodsInfo
# 定义一些序列号程序

class GoodsInfoSerializer(serializers.ModelSerializer):
    # 创建序列化器
    class Meta:
        # 定义元类
        # model指明了当前的序列化器和哪个模型产生联系
        model = GoodsInfo
        fields = '__all__'   # 意思是所有的字段都要
        # 这样写是自己选择需要的字段
        # fields = ('url', 'username', 'email', 'groups')

除了之前两中设置字段对应之外还有第三种:
exclude设置为要从序列化程序中排除的字段列表。

# 不需要写fields
model = GoodsInfo
exclude = ('is_delete',)  # 意思是除了这个字段都包含

指定嵌套序列化

用于有外键的数据库,设置depth为整数,通常为1

from user.models import UserInfo
from rest_framework import serializers


class UserAutoSerializers(serializers.ModelSerializer):

    class Meta:
        model = UserInfo
        fields = '__all__'
        depth = 1

用shell调试结果为:

>>> from user.serializers import *
>>> ser = UserAutoSerializers()
>>> ser
UserAutoSerializers():
    id = IntegerField(label='ID', read_only=True)
    name = CharField(max_length=20)
    password = CharField(max_length=20, required=False)
    phone = CharField(max_length=11)
    addkey = NestedSerializer(read_only=True):
        id = IntegerField(label='ID', read_only=True)
        add = CharField(max_length=50)
>>> 

指定字段序列化(即覆盖)

class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    groups = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Account

想要指定readonly字段还有第二个Meta选项,read_only_fields.:

read_only_fields = ('account_name',)

附加关键字参数

还有一个快捷方式,允许您在字段上指定任意附加关键字参数,使用extra_kwargs选择。如在.的情况下read_only_fields,这意味着不需要显式声明序列化程序上的字段。

class Meta:
        model = User
        fields = ('email', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

request和response

request请求

就是HttpRequest的扩展功能
.data:
request.data返回请求主体的解析内容(可以解析各种类型请求包括POST等)。这与标准类似。request.POST和request.FILES属性除外:

  • 它包括所有已解析的内容,包括文件和非文件投入。
  • 它支持解析除HTTP之外的HTTP方法的内容POST,这意味着您可以访问PUT和PATCH请求。
  • 它支持REST框架灵活的请求解析,而不仅仅是支持表单数据。例如,您可以处理传入表单数据的方式处理传入的JSON数据。

.query_params:
相当于request.GET,但是任何HTTP方法类型都可能包含查询参数,而不仅仅是GET请求

response类

数据类型可以是str,list,dict等

class Response(SimpleTemplateResponse):
    """
    An HttpResponse that allows its data to be rendered into
    arbitrary media types.
    """

    def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):

data:为响应准备的序列化之后的数据,status是状态码,template_name模板的名称
headers:响应头信息,content_type:一般不需要指定,框架根据前端传递的信息来指定

View视图使用

还是推荐看官网:https://www.django-rest-framework.org/api-guide/views/

APIView(一级视图)

集成于Django的view类,和view不同地方在于:

  • 传递给处理程序方法的请求将是REST框架的Request实例,而不是Django的HttpRequest实例。
  • 处理程序方法可能返回REST框架的Response,而不是Django的HttpResponse…视图将管理内容协商和在响应上设置正确的呈现器。
  • 任何APIException例外情况将被捕获并调解成适当的反应。
  • 传入的请求将进行身份验证,并在将请求发送给处理程序方法之前,将运行适当的权限和/或节流检查。

点击查看类内容:

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    # 身份认证
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

写一个get和post请求实例:

from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework import authentication, permissions
from goods.serializers import *

class ListGoodsView(APIView):
	# 可以不需要验证
    # authentication_classes = (authentication.TokenAuthentication, )
    # permission_classes = (permissions.IsAdminUser, )

    def get(self, request, format=None):
        goods = [good.name for good in GoodsInfo.objects.all()]
        # 多条数据要写many=True
        data = GoodsInfo.objects.all()
        ser = GoodsInfoNewSerializer(data, many=True)
        return Response(ser.data)

    def post(self, request):
    	# 反序列化需要data=
        ser = GoodsInfoNewSerializer(data=request.data)
        # 需要验证
        ser.is_valid()
        print(ser.validated_data)
        ser.save()
        return Response(ser.validated_data)

GenericAPIView(二级视图)和mixins

这个是对APIView的再次封装,实现更强和更简洁的功能,通常还会和mixins联合使用:

GenericAPIView的属性

  • 加入queryset属性,可以直接设置这个属性,不必再将实例化的courses,再次传给seriliazer,系统会自动检测到。除此之外,可以重载get_queryset(),这样就不必设置’queryset=*’,这样就变得更加灵活,可以进行完全的自定义。
  • 加入serializer_class属性与实现get_serializer_class()方法。两者的存在一个即可,通过这个,在返回时,不必去指定某个serilizer
  • lookup_field-模型字段,用于对单个模型实例执行对象查找。默认为’pk’…注意,在使用超链接API时,需要确保双管齐下API视图和如果需要使用自定义值,序列化程序类将设置查找字段
  • 设置过滤器模板:filter_backends
  • 设置分页模板:pagination_class

mixins类

1.ListModelMixin
列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。

2.CreateModelMixin
创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。

3.RetrieveModelMixin
详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。

4.UpdateModelMixin
更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。

5.DestroyModelMixin
删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。

混合使用实例:

mixins的子类中会带有对应可以使用的方法,看上文,这时候要写queryset和serializer_class以及对应的请求方式,并返回mixins子类中的方法

from goods.serializers import *
from rest_framework.mixins import *
from rest_framework.generics import *
class GenericsView(GenericAPIView, ListModelMixin):
    queryset = GoodsInfo.objects.all()
    serializer_class = GoodsInfoNewSerializer

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

如果直接使用下文的子类更简单:
意思是自动调用post方法,不需要再自己调用这个方法

from goods.serializers import *
from rest_framework.generics import *
class CreateGoodsView(CreateAPIView):
    # queryset = GoodsInfo.objects.all() # 创建的时候可以不用设置数据库内容
    serializer_class = GoodsInfoNewSerializer

三级视图(XXAPIView)

使用已有的子类代表GenericAPIView和mixins的混合使用
几个子类视图

1) CreateAPIView
提供 post 方法
继承自: GenericAPIView、CreateModelMixin

2)ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin

3)RetireveAPIView
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin

4)DestoryAPIView
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin

5)UpdateAPIView
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin

6)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

7)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

ViewSet的使用

视图集ViewSet,使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中。使用ViewSet时不需要再views.py里写get->return list这种类型的,只需要在urls.py里写对应逻辑:
views.py内容:自己导包,写了GenericViewSet,ModelViewSet,ViewSet

class MyViewSet(GenericViewSet, ListModelMixin):
    queryset = GoodsInfo.objects.filter(id__gt=15)
    serializer_class = GoodsInfoNewSerializer
class GoodsInfoView(ModelViewSet):
    # 先导包ModelViewSet和数据库Model和serializers下的类
    # queryset是一个查询集,存储所有的数据库查询之后的数据,是一个属性不能修改名字
    queryset = GoodsInfo.objects.all()
    '''serializer_class用来指定再当前的视图立面进行序列化和反序列化时
    使用的序列化器(也叫串行器)'''
    serializer_class = GoodsInfoNewSerializer
class UserViewSet(ViewSet):
	"""
	A simple ViewSet for listing or retrieving users.
	"""
	def list(self, request):
	    queryset = User.objects.all()
	    serializer = UserSerializer(queryset, many=True)
	    return Response(serializer.data)
	
	def retrieve(self, request, pk=None):
	    queryset = User.objects.all()
	    user = get_object_or_404(queryset, pk=pk)
	    serializer = UserSerializer(user)
	    return Response(serializer.data)

urls.py内容,两种方式,router是自动完成绑定:

from django.conf.urls import url, include
from goods.views import *
from rest_framework.routers import DefaultRouter

# 定义视图处理的路由器
router = DefaultRouter()
# 在路由器中注册视图集
router.register('showgoods', GoodsInfoView, base_name='hello')
router.register('viewset', MyViewSet, base_name='viewset')

urlpatterns = [
    url(r'', include(router.urls)),
    url(r'^goodslist/$', ListGoodsView.as_view()),
    url(r'^show/$', GenericsView.as_view()),
    url(r'^(?P\d+)+(/showgoods/)$', GoodsInfoView.as_view({'get':'retrieve','post':'create','put':'update'})),
]

或者这样写之一:

viewset = MyViewSet.as_view({
    'get': 'list',
})
# 商品列表页
url('viewset/', goods_list,name="viewset"),

这样区别并写自己的特殊方法:

user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})

1) ViewSet
继承自APIView,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

2)GenericViewSet
继承自GenericAPIView,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于列表视图与详情信息视图的开发。

3)ModelViewSet
继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

4)ReadOnlyModelViewSet
继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin。

ViewSet添加自定义动作

添加自定义动作需要使用rest_framework.decorators.action装饰器。

以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。

action装饰器可以接收两个参数:

methods: 该action支持的请求方式,列表传递
detail: 表示是action中要处理的是否是视图资源的对象(即是否通过url路径获取主键)
True 表示使用通过URL获取的主键对应的数据对象
False 表示不使用URL获取主键
实例:

from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
 
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
 
    # detail为False 表示不需要处理具体的BookInfo对象
    @action(methods=['get'], detail=False)
    def latest(self, request):
        """
        返回最新的图书信息
        """
        book = BookInfo.objects.latest('id')
        serializer = self.get_serializer(book)
        return Response(serializer.data)
 
    # detail为True,表示要处理具体与pk主键对应的BookInfo对象
    @action(methods=['put'], detail=True)
    def read(self, request, pk):
        """
        修改图书的阅读量数据
        """
        book = self.get_object()
        book.bread = request.data.get('read')
        book.save()
        serializer = self.get_serializer(book)
        return Response(serializer.data)

urls.py的跳转逻辑:

urlpatterns = [
    url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
    url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
    url(r'^books/(?P\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
    url(r'^books/(?P\d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
]

ViewSet的默认url配置动作:

    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

你可能感兴趣的:(Django)