Django Rest-Framework

零,DRF框架预备知识

  APIView与View的区别

    APIView继承了View

    csrf的豁免

    重现封装request对象

      原生的request赋值给了request._request

      request.query_params封装了原生的request.GET

      request.data封装了除GET外的所有信息(request.POST,request.files)

  响应对象Response

    携带HTTP表中状态码

    做模板的渲染

一,restful规范

  REST风格

    表述状态转移:web交换方案,前后端的数据传输的设计思想

    资源的概念:在web中只要又被引用的必要都是资源

    URI

      URI:同一资源标识符

      URL:统一资源定位符,URI的子集

    统一资源接口

      根据HTTP请求方式的不同对资源进行不同的操作

      遵循HTTP请求的语义

    资源的表述

      前后端的传输叫资源的表述

      传输的不是资源的本身,而是资源的某一种表述形式

    资源的状态

      前端展示的叫资源的状态

    通过超链接的指引告诉用户接下来有哪些资源状态可以进入

    

    核心思想

      面向资源编程

         每个url就是资源的体现,不体现操作,url命名尽量用名词不要用动词

      根据HTTP请求方式的不同对资源进行不同的操作

    URL体现:

      版本

        htttps://v1.xxx.com

        https://xxx.com/v3

        体现是否为API接口

        https://v1.xxx.com/api

      过滤信息

        https://v1.xxx.com?page=1

      尽量使用HTTPS

    返回值的体现(响应请求)

      携带状态码

      携带错误信息

      返回值

        get 返回查看的所有或单条信息

        post 返回新增的那条数据

        put/patch 返回更新的那条数据

        delete 返回空

        携带超链接

    

  

二,序列化组件

  1、序列化

    实现流程

      1.如果设置了many=True

      2.把queryset当成可迭代对象去循环,得到每个模型对象

      3.把每个模型对象放入序列化器进行序列化

      4.进行字段匹配,匹配上的字段进行序列化,匹配不上的丢弃

      5.序列化的时候必须满足序列化的所有字段要求

    声明一个序列化器

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  # required=False 忽略校验
    title = serializers.CharField(max_length=32)
    pub_time = serializers.DateField()

    在视图中引用我们定义的序列化器,序列化我们的queryset数据  

ser_obj = BookSerializer(queryset, many=True) # many=True 支持(当成)可迭代对象,循环遍历并序列化
ser_obj = BookSerializer(models_obj) # 同样支持单个模型对象的序列化
ser_obj.validated_data # 校验通过的数据
return Response(ser_obj.data)

  2、反序列化

    获取前端传过来的数据

    用序列化器进行校验      

 BookSerializer(data=request.data)
if ser_obj.is_valid():
    ser_obj.save() # 调用序列化器中的create方法操作orm创建新对象
    return Response(ser_obj.data)
else:
    return Response

   

  3、序列化以及反序列化的时候字段类型不统一的情况

-- required=False  # 对字段取消校验
-- read_only=True  #  仅序列化是进行校验
-- write_only=True  # 仅反序列化是校验

  4、ModeSerializer 帮我们实现create以及update方法

class BookSerializer(serilalizers.ModelSerializer)
       # SerializerMethodField方法字段,会将钩子方法的返回值给字段
       text = serializers.SerializerMethodField(read_only=True)

        class Meta:
            model = Book # 模型类
            fields = "__all__" / ["",""]
            exclude = [""]  # 排除某些字段
            depth = 1  # 根据你的外键关系找几层,会让你所有的外键变成read_only = True
            extra_kwargs = {
                "字段名称":{参数:值}  # 为自动生成的字段添加参数
            }

# SerializerMethodField的钩子方法定义
def get_字段名称(self,obj):
    obj 是我们循环序列化的每个模型对象
    return 自己想要的数据    

  

  4.字段的校验方法

    多个字段的校验方法,优先级为 低     

def validate(self,attrs):
    # attrs 前端传过来的所有的数据组成的字典
    raise serializers.ValidationError("xxxx")
    return value

    单个字段的校验方法,优先级为 中

def validate_字段名(self,value):
    # value字段的值
    raise serializers.ValidationError("xxxx")
    return value

    自定义校验方法,优先级为 高

# 字段中添加validators指定校验方法
title = serializers.CharField(max_length=32,validators=[my_validate])

def my_validate(value):
    raise serializers.ValidationError("xxxx")
    return value

三,视图组件

  视图的封装

class GenericAPIView(APIView):
    query_set = None
    serializer_class = None

    def get_query_set(self):
        return self.query_set  # 从对象属性开始找

    def get_serializer(self, *args, **kwargs):  # 序列化器实例化时,以传参的方式执行
        return self.serializer_class(*args, **kwargs)


class RetrieveModelMixin(object):
    def retrieve(self, request, pk):
        book_obj = self.get_query_set().filter(pk=pk).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)


class ListModelMixin(object):
    def list(self, request):
        # print(self.action_map) # actions:{'get': 'list', 'post': 'create'}
        ser_obj = self.get_serializer(self.get_query_set(), many=True)
        return Response(ser_obj.data)


class CreateModelMixin(object):
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        # print(ser_obj.errors)
        return Response(ser_obj.errors)


class UpdateModelMixin(object):
    def update(self, request, pk):
        book_obj = self.get_query_set().filter(pk=pk).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data,partial=True) # 不用每个字段强制都要传值
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)


class DestoryModelMixin(object):
    def destory(self, request, pk):
        book_obj = self.get_query_set().filter(pk=pk).first()
        if book_obj:
            book_obj.delete()
            return Response("")
        return Response("删除的对象不存在")


class ListCreateModeMixin(GenericAPIView, ListModelMixin, CreateModelMixin): pass


class RetrieveUpdateDestroyModelMixn(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestoryModelMixin): pass

# 继承了ViewSetMixin并使用了它的as_view方法
class ModelViewSet(ViewSetMixin, ListCreateModeMixin, RetrieveUpdateDestroyModelMixn): pass

# 第一种CBV
class BookListAPIView(ListCreateModeMixin):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookEditAPIView(RetrieveUpdateDestroyModelMixn):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, id):
        return self.retrieve(request, id)

    def put(self, request, id):
        return self.update(request, id)

    def delete(self, request, id):
        return self.destory(request, id)


# 第二种,解耦后的CBV
class BookModelView(ModelViewSet):
    query_set = Book.objects.all()  # 使用路由系统后,需要queryset
    serializer_class = BookSerializer
# queryset 如果重写视图的话,使用queryset作为参数会被框架放入缓存
# 防止数据不更新,应用调用all()方法重新获取数据
# self.get_queryset()
#     return self.queryset.all()




# 第三种,直接继承框架已定义的ModelViewSet类,
from rest_framework.viewsets import ModelViewSet

class BookModelView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class PublisherModelView(ModelViewSet):
    queryset = Publisher.objects.all()
    serializer_class = PublisherSerializer


class AuthorModelView(ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer

  注意

# 如果不利用ViewSetMixin的as_view方法,对self.get=self.list,如此类推赋值,而是重新的ModelViewSet的话,路由的as_view()方法需要手动穿参,重新指定请求的执行方法
urlpatterns = [
    url(r'^list/$', views.BookModelView.as_view({'get':'list','post':'create'})), # 用新的类来处理,由于没有get,post方法,
    url(r'^list/(?P<id>\d+)/$', views.BookModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
]

四,路由组件

# 导入
    from rest_framwork.routers import DefaultRouter
# 实例化
    router = DefaultRouter()
# 注册
    router.register("list",views.BookModelView)  
    # 默认生成的路由都自带参数(pk),所以视图中的方法也要带参数pk
    # actions={'get': 'list', 'post': 'create'} 路由系统自动调用as_view({'get': 'list', 'post': 'create'})
# 把默认生成的路由注册
    urlpattrens += router.urls
# 默认生成的路由都是带参数的!!
    # ^book/ ^list/$ [name='book-list']
    # ^book/ ^list\.(?P<format>[a-z0-9]+)/?$ [name='book-list']
    # ^book/ ^list/(?P<pk>[^/.]+)/$ [name='book-detail']
    # ^book/ ^list/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail']
    # ^book/ ^$ [name='api-root']
    # ^book/ ^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']

 

猜你喜欢

转载自www.cnblogs.com/lianyeah/p/10129185.html