首页 > 其他 > 详细

DRF

时间:2019-09-07 18:13:39      阅读:93      评论:0      收藏: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.cnblogs.com/0916m/p/11481925.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!