DRF

作者: 不咸的Yan | 来源:发表于2019-06-30 11:28 被阅读0次
    • 概述

    Django REST framework
    在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的。
    在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:
    增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    删:判断要删除的数据是否存在 -> 执行数据库删除
    改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    查:查询数据库 -> 将数据序列化并返回
    Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。
    通常简称为DRF框架 或 REST framework。
    DRF框架是建立在Django框架基础之上,由Tom Christie大牛二次开发的开源项目
    特点
    提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
    提供了丰富的类视图、Mixin扩展类,简化视图的编写;
    丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
    多种身份认证和权限认证方式的支持;
    内置了限流系统;
    直观的 API web 界面;
    可扩展性,插件丰富

    开发方式


    特点


    序列化器

    序列化:
    序列化(serialization)
    在计算机科学的资料处理中,是指将数据结构或物件状态转换成可取用格式(例如存成档案,存于缓冲,或经由网络中传送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。
    依照序列化格式重新获取字节的结果时,可以利用它来产生与原始物件相同语义的副本。对于许多物件,像是使用大量参照的复杂物件,这种序列化重建的过程并不容易。
    面向对象中的物件序列化,并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。
    从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组, deserialization, unmarshalling)。

    ​ 在数据储存与传送的部分是指将一个对象)存储至一个储存媒介,例如档案或是记亿体缓冲等,或者透过网络传送资料时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象)。这程序被应用在不同应用程序之间传送对象),以及服务器将对象)储存到档案或数据库。相反的过程又称为反序列化。



    基本序列化器

    from rest_framework.serializers import Serializer
    作用: 进行数据的校验 对数据对象进行转换
    使用:

    1 为模型类提供序列化器,定义一个Serializer类


    class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
        id = serializers.IntegerField(label='ID', read_only=True)
        btitle = serializers.CharField(label='名称', max_length=20)
        bpub_date = serializers.DateField(label='发布日期', required=False)
        bread = serializers.IntegerField(label='阅读量', required=False)
        bcomment = serializers.IntegerField(label='评论量', required=False)
        image = serializers.ImageField(label='图片', required=False)
    
    字段与选项
    
    字段
    字段构造方式
    BooleanField
    BooleanField()
    ImageField
    ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    CharField
    CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
    EmailField
    EmailField(max_length=None, min_length=None, allow_blank=False)
    RegexField
    RegexField(regex, max_length=None, min_length=None, allow_blank=False)
    FileField
    FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    IntegerField
    IntegerField(max_value=None, min_value=None)
    UUIDField
    UUIDField(format='hex_verbose') 
    format: 
    1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 
    2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 
    3)'int' - 如: "123456789012312313134124512351145145114" 
    4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    FloatField
    FloatField(max_value=None, min_value=None)
    TimeField
    TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    DateField
    DateField(format=api_settings.DATE_FORMAT, input_formats=None)
    DecimalField
    DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
    max_digits: 最多位数
    decimal_palces: 小数点位置
    DateTimeField
    DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    
    
    选项参数
    
    参数名称
    作用
    max_length
    最大长度
    min_length
    最小长度
    allow_blank
    是否允许为空
    trim_whitespace
    是否截断空白字符
    max_value
    最小值
    min_value
    最大值
    
    通用参数
    
    参数名称
    说明
    read_only
    表明该字段仅用于序列化输出,默认False
    write_only
    表明该字段仅用于反序列化输入,默认False
    required
    表明该字段在反序列化时必须输入,默认True
    default
    反序列化时使用的默认值
    allow_null
    表明该字段是否允许传入None,默认False
    validators
    该字段使用的验证器
    error_messages
    包含错误编号与错误信息的字典
    label
    用于HTML展示API页面时,显示的字段名称
    help_text
    用于HTML展示API页面时,显示的字段帮助提示信息
    
    

    备注:


    2 创建Serializer对象
    ser = Serializer(instance=None, data=empty, **kwarg)


    输出ser 可以打印出ser的字段信息
    3 根据传入的参数。进行序列化/反序列化操作

    序列化过程


    class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
        id = serializers.IntegerField(label='ID', read_only=True)
        btitle = serializers.CharField(label='名称', max_length=20)
        bpub_date = serializers.DateField(label='发布日期', required=False)
        bread = serializers.IntegerField(label='阅读量', required=False)
        bcomment = serializers.IntegerField(label='评论量', required=False)
        image = serializers.ImageField(label='图片', required=False)
        heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  # 新增many=True
    
    from booktest.serializers import BookInfoSerializer
    from booktest.models import BookInfo
    book = BookInfo.objects.get(id=2)
    serializer = BookInfoSerializer(book)
    serializer.data
    # {'id': 2, 'btitle': '天龙八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None, 'heroinfo_set': [6,8, 9]}
    

    反序列化过程


    流程
    1 postman给data构造参数
    注意 json数据最后不加逗号。 json数据中的True,False。都应该 小写
    2 验证 is_valid()
    ser.is_valid( raise_exception=true)
    验证失败的话,REST framework接收到此异常,直接给前端返回一个HTTP 400 Bad Request响应,不再返回T/F
    
    在序列化器外定义函数
    def about_django(value):
      if 'django' not in value.lower():
      raise serializers.ValidationError("图书不是关于Django的")
    
    
    字段中添加参数
    class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
        id = serializers.IntegerField(label='ID', read_only=True)
    
        btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])
    
        bpub_date = serializers.DateField(label='发布日期', required=False)
        bread = serializers.IntegerField(label='阅读量', required=False)
        bcomment = serializers.IntegerField(label='评论量', required=False)
        image = serializers.ImageField(label='图片', required=False)
    
    

    3 保存 ser.save()


    class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
        ...
        def create(self, validated_data):
    """新建"""
            returnBookInfo.objects.create(**validated_data)
    
        def update(self, instance,validated_data):
    """更新,instance为要更新的对象实例"""
            instance.btitle = validated_data.get('btitle', instance.btitle)
            instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
            instance.bread = validated_data.get('bread', instance.bread)
            instance.bcomment = validated_data.get('bcomment', instance.bcomment)
            instance.save()
            return instance
    
    create 传入validated_data
        def create(self, validated_data):
             #保存数据
             # 方法1
            # book=BookInfo()
            # book.btitle = validated_data['btitle']
            # book.bpub_date = validated_data['bpub_date']
            # book.bread = validated_data['bread']
            # book.bcomment = validated_data['bcomment']
            # book.is_delete = validated_data['is_delete']
            # book.save()
             #方法2
            book=BookInfo.objects.create(btitle = validated_data['btitle'],bpub_date = validated_data['bpub_date'],bread = validated_data['bread'],bcomment = validated_data['bcomment'],is_delete = validated_data['is_delete'])
            return book
    
    创建序列化器对象的时候,
    from db.serializers import BookInfoSerializer
    data = {'btitle': '封神演义'}
    serializer = BookInfoSerializer(data=data)  没有实例的传入,得到的数据新增到数据库
    serializer.is_valid()  # True
    serializer.save()  # <BookInfo: 封神演义>
    
    
    
    from db.models import BookInfo
    book = BookInfo.objects.get(id=2)
    data = {'btitle': '倚天剑'}
    serializer = BookInfoSerializer(book, data=data)   传入实例,在实例的基础上进行数据修                            改,更新实例对象
    serializer.is_valid()  # True
    serializer.save()  # <BookInfo: 倚天剑>
    book.btitle  # '倚天剑'
    
    模型类序列化器 ModelSerializer

    from rest_framework . serializers import ModelSerializer 继承基本的序列化器 serializers
    继承serializers,更高一层的封装,在Meta中对模型、字段进行设置,与基本序列化器相比,字段不用自己写了


    流程
    1 创建序列化器 serializers.py
    定义序列化器,指定对应的模型类、控制的字段,定义对字段校验的方法
    from rest_framework import serializers
    from book.models import BookInfo
    
    class BookModelSerializer(serializers.ModelSerializer):
        image_code = serializers.CharField(max_length=4,min_length=4,allow_null=True)
        class Meta:
            model = BookInfo
            # 所有字段都选中
            # fields = "__all__"
            # fields = ['btitle','bread','bcomment','bpub_date']  
            exclude = ['is_delete']
            read_only_fields = ['bread','bcomment']
            extra_kwargs = {
                'btitle':{
                    'min_length':'10',
                }
            }
    

    2 编写视图 views.py
    定义视图,指定序列化器的类、指定查询集

    from rest_framework.viewsets import ModelViewSet
    from DRF.serializer import BookSerializer   引入刚才所创建的序列化器
    from book.models import BookInfo
    
    
    class DRFBookViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()    指明该视图集在查询数据时使用的查询集
    serializer_class = BookSerializer    指明该视图在进行序列化或反序列化时使用的序列化器
    

    3 定义路由 urls.py
    配置路由,应用了rest_framework可以自动生成url,

    from . import views
    from rest_framework.routers import DefaultRouter
    
    urlpatterns = [
        ...
    ]
    
    router = DefaultRouter()  # 可以处理视图的路由器
    router.register(r'books', views.BookInfoViewSet)  # 向路由器中注册视图集
    
    urlpatterns += router.urls  # 将路由器中的所有路由信息追到到django的路由列表中
    

    判断使用哪种序列化类
    根据操作的字段是否和模型类有关系来判断用那种序列化器
    有关 模型类 ModelSerializer
    无关 基本类Serializer

    视图

    在原先Django框架视图中的简化

    import json
    from DRF.serializer import BookSerializer,HeroSerializer
    from book.models import BookInfo,HeroInfo
    from django.views import View
    from django.http import HttpResponse,JsonResponse
    
    class DRFView(View):      #继承Django的View视图
        def get(self,request):
            books = BookInfo.objects.all()
            ser = BookSerializer(books,many=True)   
            #使用序列化器进行操作 注意  many=True
            return JsonResponse(ser.data,safe=False)      
            #在初始化json响应对象时,safe默认是True,非字典数据无法传输,设置为False,允许非字典数据传输
            #safe=False 非字典传输    将列表格式的数据(在前端叫做数组)也可转成json进行传输
            #为True,会提示(In order to allow non-dict objects to be serialized set the safe parameter to False.)
    
        def post(self,request):
            #获取数据
            json_byte = request.body
            json_str = json_byte.decode()
            json_dict = json.loads(json_str)
    
            #将数据传入序列化器
            ser = BookSerializer(data=json_dict)
            #校验
            ser.is_valid()#判断不通过直接报错,给前端返回400
            print(ser.is_valid())
            print(ser.errors)
            #保存是模型对象
            ser.save()
            return JsonResponse(ser.data,safe=False)
    

    作用
    控制序列化器的执行(校验,保存,转换数据)
    控制数据库查询的执行

    Request

    常用属性:
    对Django的request更高封装(GET,POST,body,meta)
    request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和request.FILES属性

    request.query_params

    url(^(?P<mobile>\d+)/$),views.方法()
    在后端中,
    def get(self,request,mobile):
        正则匹配到的mobile可以直接作为参数传递使用
    
    
    对于后面查询字符串的获取
    def get(self,request):
        name = request.query_params.get('name')
    
    Response

    from rest_framework.response import Response
    封装了Django的HTTPResponse,JsonResponse,render,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型
    Response(data, status=None, template_name=None, headers=None, content_type=None)


    状态码
    from rest_framework import status
    status.HTTP....
    
    信息告知 - 1xx
    HTTP_100_CONTINUE
    HTTP_101_SWITCHING_PROTOCOLS
    
    成功 - 2xx
    HTTP_200_OK
    HTTP_201_CREATED  创建成功
    HTTP_202_ACCEPTED
    HTTP_203_NON_AUTHORITATIVE_INFORMATION
    HTTP_204_NO_CONTENT
    HTTP_205_RESET_CONTENT
    HTTP_206_PARTIAL_CONTENT
    HTTP_207_MULTI_STATUS
    
    重定向 - 3xx
    HTTP_300_MULTIPLE_CHOICES
    HTTP_301_MOVED_PERMANENTLY
    HTTP_302_FOUND
    HTTP_303_SEE_OTHER
    HTTP_304_NOT_MODIFIED
    HTTP_305_USE_PROXY
    HTTP_306_RESERVED
    HTTP_307_TEMPORARY_REDIRECT
    
    客户端错误 - 4xx
    HTTP_400_BAD_REQUEST
    HTTP_401_UNAUTHORIZED
    HTTP_402_PAYMENT_REQUIRED
    HTTP_403_FORBIDDEN
    HTTP_404_NOT_FOUND
    HTTP_405_METHOD_NOT_ALLOWED
    HTTP_406_NOT_ACCEPTABLE
    HTTP_407_PROXY_AUTHENTICATION_REQUIRED
    HTTP_408_REQUEST_TIMEOUT
    HTTP_409_CONFLICT
    HTTP_410_GONE
    HTTP_411_LENGTH_REQUIRED
    HTTP_412_PRECONDITION_FAILED
    HTTP_413_REQUEST_ENTITY_TOO_LARGE
    HTTP_414_REQUEST_URI_TOO_LONG
    HTTP_415_UNSUPPORTED_MEDIA_TYPE
    HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
    HTTP_417_EXPECTATION_FAILED
    HTTP_422_UNPROCESSABLE_ENTITY
    HTTP_423_LOCKED
    HTTP_424_FAILED_DEPENDENCY
    HTTP_428_PRECONDITION_REQUIRED
    HTTP_429_TOO_MANY_REQUESTS
    HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
    HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
    
    服务器错误 - 5xx
    HTTP_500_INTERNAL_SERVER_ERROR
    HTTP_501_NOT_IMPLEMENTED
    HTTP_502_BAD_GATEWAY
    HTTP_503_SERVICE_UNAVAILABLE
    HTTP_504_GATEWAY_TIMEOUT
    HTTP_505_HTTP_VERSION_NOT_SUPPORTED
    HTTP_507_INSUFFICIENT_STORAGE
    HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
    

    基本类视图

    APIView

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

    APIView与View的不同点:


    APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    # url(r'^books/$', views.BookListView.as_view()),
    class BookListView(APIView):
        def get(self, request):
            books = BookInfo.objects.all()
            serializer = BookInfoSerializer(books, many=True)
            return Response(serializer.data)
    
    view.py
    class BookModelAPIView(APIView):
        def get(self,request):
            data1= request.query_params
            print(data1)
            books = BookInfo.objects.all()
            ser = BookModelSerializer(books,many=True)
            return Response(ser.data,status.HTTP_200_OK)
    
        def post(self,request):
            data = request.data
            print(data,type(data))
    
            ser = BookModelSerializer(data=data)
            ser.is_valid()
            ser.save()
            return Response('ok',status.HTTP_201_CREATED)
    
    serializer.py
    #模型类序列化器
    class BookModelSerializer(serializers.ModelSerializer):
        # image_code = serializers.CharField(max_length=4,min_length=4,allow_null=True)
        class Meta:
            model = BookInfo
            fields = "__all__"
            # exclude = '__all__'
            # read_only_fields = ['bread','bcomment']
    
            extra_kwargs = {
                'btitle':{
                    'min_length':1,
                }
            }
        def create(self, validated_data):
            book=BookInfo.objects.create(btitle = validated_data['btitle'],bpub_date = validated_data['bpub_date'],bread = validated_data['bread'],bcomment = validated_data['bcomment'],is_delete = validated_data['is_delete'])
            return book
    
    
    urls.py
    urlpatterns = [
        #模型类序列化器
        url(r'^drf/$',views.BookModelAPIView.as_view()),
    
    GenericAPIView

    from rest_framework.generics import GenericAPIView
    继承自APIVIew ,自然也继承自Django的view类
    主要增加了操作序列化器和数据库查询的方法,为Mixin扩展类的执行提供方法支持。
    通常在使用时,可搭配一个或多个Mixin扩展类。
    类属性

    class BookModelGenericAPIView(GenericAPIView):
        #指定序列化器
        serializer_class = BookModelSerializer
        queryset = BookInfo.objects.all()
    
        def get(self,request):
            data1= request.query_params
            print(data1)
            # books = BookInfo.objects.all()  类属性指定了queryset这步省略
            # 获取查询对象
            books =self.get_queryset()
            # ser = BookModelSerializer(books,many=True) 类属性指定了序列化器,省略
            #调用序列化器
            ser = self.get_serializer(books,many=True)
    
    
            return Response(ser.data,status.HTTP_200_OK)
    

    类方法
    serialiezer方法
    get_serializer(self, args, *kwargs)

    返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法
    
    源码
    def get_serializer(self,*args, **kwargs):
    serializer_class = self.get_serializer_class()
        kwargs['context'] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)
    
    在继承GeneticAPIView的视图函数中调用此方法 self.get_serializer(获取的参数)。
    1 执行了get_serializer_class()方法,返回的是类属性 serializer_class,
    def get_serializer_class(self):
         return self.serializer_class
    
    2 执行   self.get_serializer_context()方法,得到三个返回值,request,format,view,
    将返回值赋予kwargs键context,构成一个字典
    
    3 返回类属性 serializer_class,并且加上(),代表执行类属性对应的序列化器
    

    get_serializer_class(self)

    重写
     if self.request.method=='get':
        serializer=ser1;
     if self.request.method=='post':
        serializer=ser2;
    

    queryset方法
    get_object(self)

        def get_object(self):
        首先找到类属性指定的查询集,
            queryset = self.filter_queryset(self.get_queryset())
    
    根据lookup_field='pk' 找到url中传递的pk值,
            lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
    
        根据pk值,在查询集找到对应pk值的数据对象,
            filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
            obj = get_object_or_404(queryset, **filter_kwargs)
    
        返回匹配的对象。
            self.check_object_permissions(self.request, obj)
    
            return obj
    
    # url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
    class BookDetailView(GenericAPIView):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def get(self, request, pk):
            book = self.get_object() #get_object()方法根据pk参数查找queryset中的数据对象
            serializer = self.get_serializer(book)
            return Response(serializer.data)
    

    get_queryset(self)
    获取所有查询集数据对象
    返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写

    defget_queryset(self):
        user = self.request.user
        return user.accounts.all()
    

    扩展类
    from rest_framework.mixins import 拓展类

    class CreateModelMixin(object):
    
        def create(self, request, *args, **kwargs):
            通过调用GennericSerializer的get_serializer方法调用序列化器,传入前端发来的data,
            serializer = self.get_serializer(data=request.data)  
    
            序列化器对数据进行验证,同时启用遇错页面报错
            serializer.is_valid(raise_exception=True)
    
            调用此方法,将序列化器传入,执行save方法
            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 {}
    

    扩展类子类
    from rest_framework.generics import CreateAPIView,ListAPIView
    扩展类本身继承的是object类,其中运用的get_serializer方法来自于genericapiview类
    定义视图类的是时候,继承两个类 一个拓展类,一个genericapiview
    class MixinView(CreateAPIView,ListAPIView):



    class MixinView(CreateAPIView,ListAPIView):
        serializer_class = BookModelSerializer
        queryset = BookInfo.objects.all()
    
        什么都不用写,继承,直接实现 get post 查询创建方法
    

    视图集ViewSet
    from rest_framework.viewsets import ViewSet,GenericViewSet,ModelViewSet


    ViewSet
    
    
    from rest_framework.response import Response
    
    from rest_framework.viewsets import ViewSet  #引用视图集,继承于ViewSetMixin, views.APIView
    from book.models import BookInfo
    from DRF.serializer import BookModelSerializer
    
    class DRFViewSet(ViewSet):
        def list_books(self,request):
            # 使用视图集不用再写请求方法,直接一句业务逻辑写方法名,在url匹配的时候添加键值对对应关系
            """
            展示所有图书信息
            :param request:
            :return:
            """
            # 没有GenericAPIView,没有query_set属性,所以查询还得写
            books = BookInfo.objects.all()
    
            #序列化器一旦定义就可以导入引用,不用重复写
            ser = BookModelSerializer(books,many=True)
    
            #返回ref框架的response
            return Response(ser.data)
    
        def create_book(self,request):
            """
            创建一个图书对象
            :param request:
            :return:
            """
            data = request.data
            ser = BookModelSerializer(data=data)
            ser.is_valid()
            ser.save()
            return Response(ser.data)
    
        def create_hero(self,request):
            data = request.data
            ser = BookModelSerializer(data=data)
            ser.is_valid()
            ser.save()
            return Response(ser.data)
    
    
    urls.py中
    
    from . import views
    urlpatterns = [
        url(r'^DRFViewSet/$',views.DRFViewSet.as_view({'get':'list_books','post':'create_book'})),
        # 对于同一个字典,不能有同一个key。所以当同一个请求方式过来要执行不同的方法时,可以再创建一个url
        url(r'^DRFViewSet/hero/$',views.DRFViewSet.as_view({'post':'create_hero'})),
    ]
    
    
    GenericViewset
    
    #GenericViewSet
    class DRFGenericViewSet(GenericViewSet):  #继承ViewSetMixin, generics.GenericAPIView
        # serializer_class = BookModelSerializer #指定序列化器
        queryset = BookInfo.objects.all() #指定查询集
    
        # 当不同的业务逻辑需要不同的序列化器,指定序列化器类属性不能满足需求
        # 解决:重写get_serializer_class
        # 1根据不同的action指定不同的序列化器
        def get_serializer_class(self):
            if self.action == 'list':
                return BookModelSerializer
            if self.action == 'create':
                return BookSerializer
        #2 根据不同的请求方式指定序列化器
        # def get_serializer_class(self):
        #     if self.request.method == 'GET':
        #         return BookSerializer
        #     if self.request.method == 'POST':
        #         return BookModelSerializer
    
        def list(self,request):
            books = self.get_queryset()   #视图集对象调用继承自GenericAPIView的方法,get_queryset()
            ser = self.get_serializer(books,many=True)  #调用,内部执行get_serializer_class方法,在当前类中继承重写,根据action==list判断得到的序列化器为BookModelSerializer,执行
            return Response(ser.data)
    
        def create(self,request):
            data = request.data
    
            ser = self.get_serializer(data = data)
            ser.is_valid()
            ser.save()
    
            return Response(ser.validated_data)
    
    继承五个扩展类和GenericViewSet
    
    class ModelViewSet(
       mixins.CreateModelMixin,
       mixins.RetrieveModelMixin,
       mixins.UpdateModelMixin,
       mixins.DestroyModelMixin,
       mixins.ListModelMixin,
       GenericViewSet):
    

    路由Routers
    依赖于视图集,只有使用了视图集,才可以使用自动生成路由
    在 urls.py中写

    有两种形式:
    SimpleRouter
    from rest_framework.routers import SimpleRouter

    view,py
    class DRFModelViewSet(ModelViewSet):
        serializer_class = BookModelSerializer
        queryset = BookInfo.objects.all()
    
    
    urls.py
    route = SimpleRouter()
    route.register(r'RouteModelSet',views.DRFModelViewSet,base_name='book')
    print(route.urls)
    urlpatterns += route.urls
    

    DefaultRouter

    自定义方法的自动路由


    装饰器自动路由
    class DRFModelViewSet(ModelViewSet):
        serializer_class = BookModelSerializer
        queryset = BookInfo.objects.all()
        @action(methods=['GET'],detail=True)
        def last(self,request,pk):
            book = BookInfo.objects.get(id=pk)
            ser = self.get_serializer(book)
            return Response(ser.data)
    
    
    route1 = SimpleRouter()
    route1.register(r'RouteModelSet',views.DRFModelViewSet,base_name='book')
    print(route1.urls)
    urlpatterns += route1.urls
    
    手动添加路由
    views.py
    class DRFModelViewSet(ModelViewSet):
        serializer_class = BookModelSerializer
        queryset = BookInfo.objects.all()
        def last(self,request,pk):
            book = BookInfo.objects.get(id=pk)
            ser = self.get_serializer(book)
            return Response(ser.data)
    
    urls.py
      url(r'^RouteModelSet/(?P<pk>\d+)/last/$', views.DRFModelViewSet.as_view({'get': 'last',})),
    
    

    其他功能

    认证Authentication + 权限Permissions


    全局配置

    也可以在每个视图中添加

    from rest_framework.authenticationimportSessionAuthentication, BasicAuthentication
    from rest_framework.views import APIView
    from rest_framework.permissionsimportIsAuthenticated
    
    class ExampleView(APIView):
        authentication_classes = (SessionAuthentication, BasicAuthentication)
        permission_classes = (IsAuthenticated,)
    
        ...
        继承APIView的类拥有它的属性,验证,权限,限流。
        类属性接受的是 元组或者列表
    
    自定义权限
    class MyPermission(BasePermission):
        def has_object_permission(self, request, view, obj):
    """控制对obj对象的访问权限,此案例决绝所有对对象的访问"""
        returnFalse
    
    classBookInfoViewSet(ModelViewSet):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
        permission_classes = [IsAuthenticated, MyPermission]
    

    限流Throttling


    全局配置

    在视图中添加
    from rest_framework.throttling import UserRateThrottle
    from rest_framework.views import APIView
    
    classExampleView(APIView):
        throttle_classes = (UserRateThrottle,)
        ...
    
    可选限流类
    from rest_framework.authentication import SessionAuthentication
    from rest_framework.permissions import IsAuthenticated
    from rest_framework.generics import RetrieveAPIView
    from rest_framework.throttling import UserRateThrottle
    
    classBookDetailView(RetrieveAPIView):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
        authentication_classes = [SessionAuthentication]
        permission_classes = [IsAuthenticated]
        throttle_classes = (UserRateThrottle,)
    
    

    ScopedRateThrottle

    class ContactListView(APIView):
        throttle_scope = 'contacts'
        ...
    
    class ContactDetailView(APIView):
        throttle_scope = 'contacts'
        ...
    
    class UploadView(APIView):
        throttle_scope = 'uploads'
        ...
    
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.ScopedRateThrottle',
        ),
        'DEFAULT_THROTTLE_RATES': {
            'contacts': '1000/day',
            'uploads': '20/day'
        }
    }
    

    过滤
    注意 >> 排序跟过滤互斥,只能存在一个

    注册到INSTALL_APP



    在视图中指定

    classBookListView(ListAPIView):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
        filter_fields = ['btitle', 'bread']
    

    排序

    classBookListView(ListAPIView):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
        filter_backends = [OrderingFilter]   指定用哪个类进行排序
        ordering_fields = ('id', 'bread', 'bpub_date')  指定字段排序
    

    分页Pagination
    from rest_framework.pagination import PageNumberPagination
    全局配置


    视图中使用
    局部配置
    class Pageset(PageNumberPagination):
        #page_query_param='a'   #将默认page参数,改名为a,page=1 >> a=1第一页
        #page_size = 3 #后端控制前端显示的数据条数
    
    常用的:
       #page_size_query_param = 'page_size' # 给前端字段,让前端自己决定显示多少条数据
        max_page_size = 10  #后端设定最大显示数据数
    

    异常处理 Exceptions
    REST framework提供了大多异常处理

    REST framework定义的异常
    
    APIException 所有异常的父类
    ParseError 解析错误
    AuthenticationFailed 认证失败
    NotAuthenticated 尚未认证
    PermissionDenied 权限决绝
    NotFound 未找到
    MethodNotAllowed 请求方式不支持
    NotAcceptable 要获取的数据格式不支持
    Throttled 超过限流次数
    ValidationError 校验失败
    
    

    但对于数据库查询异常没有。可自定义
    通过自定义异常处理函数。
    1 测试数据库异常报错

    from django.db import DatabaseError
    在任意视图中 raise DatabaseError,
    访问该url,直接返回报错界面,没有友好界面。
    

    2 自定义异常处理文件exception.py

    from rest_framework.views import exception_handler as drf_exception_handler
    from rest_framework import status
    from django.db import DatabaseError
    
    def exception_handler(exc, context):
        response = drf_exception_handler(exc, context)
    
      if response isNone:
            view = context['view']
      if isinstance(exc, DatabaseError):
                print('[%s]: %s' % (view, exc))
                response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
    
      return response
    先判断异常在不在DRF定义好的异常中
    然后选定数据库异常。返回
    

    3 在配置文件settings.py中配置

    REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'DRF.exception.exception_handler'
    }
    

    如果未声明,会采用默认的方式

    REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
    }
    

    自动生成接口文档

    相关文章

      网友评论

        本文标题:DRF

        本文链接:https://www.haomeiwen.com/subject/mqqvcctx.html