栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

DRF 定义视图与路由

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

DRF 定义视图与路由

一、DRF 中的 Request 与 Response
  • Request 相关
  • Response 相关
  • DRF 状态码
二、APIView

APIView是DRF提供的所有视图的基类,继承自Django的View。与之不同之处在于:

  • 传入视图方法对象不同:DRF是Request,DJango是HTTPRequest
  • DRF视图方法可以返回Response对象,视图会为响应数据设置(render)符合前端的格式
  • APIException异常都会被捕获,并且处理为合适的响应信息
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制等
  • APIView中仍以常规的类视图定义来实现get、post等请求方法
from rest_framework import serializers
from book.models import Book,Publish

# class Publish(serializers.ModelSerializer):
#     class meta:
#         model = Publish
#         fields = ['publish',]


class BookModelSerializer(serializers.ModelSerializer):
    # publish = Publish()
    class meta:
        model = Book
        fields = '__all__'
# views.py
'''
列表视图:
    GET /books/ 提供所有记录
    POST /books/ 新增一条记录
详情视图:
    GET /books// 提供一条记录
    PUT /books// 修改一条记录
    DELETe /books// 删除一条记录
    APIView + ModelSerializer
'''

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from book.models import Book
from book.serializers import BookModelSerializer

class BookListAPIView(APIView):
    """ 列表视图 """
    def get(self,request):
        '''查询所有'''
        # 查询所有的书
        books = Book.objects.all()
        # 序列化数据
        serializer = BookModelSerializer(books,many=True)
        print(serializer.data)
        res = Response(serializer.data)
        # 1).data传给response对象的序列化后,但尚未render处理的数据
        print(res.data)
        # 2).status_code状态码的数字
        print(res.status_code)
        # 3).content经过render处理后的响应数据
        # print(res.content)
        # 状态码默认200
        return Response(serializer.data)
    def post(self,request):
        '''新增一条'''
        # 获取从前端传过来的请求体数据
        data = request.data
        # 创建序列化器进行反序列化
        serializer = BookModelSerializer(data=data)
        # 调用序列化器的is_valid()方法进行校验
        serializer.is_valid(raise_exception=True)
        # 调用序列化器的save方法进行执行create方法
        serializer.save()
        # 响应
        return Response(data=serializer.data,status=status.HTTP_201_CREATED)
class BookDetailAPIView(APIView):
    """ 详情视图 """
    def get(self,request,pk):
        # 查询为pk模型对象
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            # 使用序列化器类进行序列化
            serializer = BookModelSerializer(instance=book)
            return Response(serializer.data)
    def put(self,request,pk):
        # 修改为pk的模型对象
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            data = request.data
            serializer = BookModelSerializer(instance=book,data=data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
    def delete(self,request,pk):
        # 修改为pk的模型对象
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            book.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
# urls.py
from django.contrib import admin
from django.urls import path
from book.views import BookListAPIView,BookDetailAPIView
from rest_framework.routers import DefaultRouter

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/',BookListAPIView.as_view()),
    path('books//',BookDetailAPIView.as_view())
]lo9 

# # 指定 DRF-ModelView 路由
# router = DefaultRouter()
# router.register(r'api/books',BookView)
# urlpatterns += router.urls

在增加或者修改时,若有外键,需要将外键的关联部分也放进去才能添加。

三、GenericAPIView

继承自APIView,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类执行提供支持,使用时常常搭配一个或多个Mixin扩展类。除了继承了APIView身份认证、权限检查、流量控制这三个功能外,还新增了分页和过滤。

3.1 GenericAPIView 单独使用
  • 列表视图:self.get_queryset()
  • 详情视图:self.get_object(),还多了个pk,或者其它参数
"""
后续面对其他序列化类和数据来源时,只需要替换 step1 和 step2 即可
"""
class BookListGenericView(GenericAPIView):
    """ 列表视图 """
    # step1 指定序列化器类
    serializer_class = BookModelSerializer
    # step2 指定查询集,即明确数据来源
    queryset = Book.objects.all()
    # step3 定义请求方法函数
    def get(self,request):
        qs = self.get_queryset()
        serializer = self.get_serializer(qs,many=True)
        return Response(serializer.data)
    # 其余同上 post
    
''' 对于详情视图,只需要在后面指定查询的pk即可 
lookup_field = 'pk'
若需要更改查询 pk 可修改 lookup_field 为你所需查询的字段名
'''
class BookDetailGenericView(GenericAPIView):
    """ 列表视图 """
    # step1 指定序列化器类
    serializer_class = BookModelSerializer
    # step2 指定查询集,即明确数据来源
    queryset = Book.objects.all()
    # step3 定义请求方法函数
    def get(self,request,pk):
        book = self.get_object()
        serializer = self.get_serializer(book)
        return Response(serializer.data)
    # 其余同上 put delete
urlpatterns = [
    path('admin/', admin.site.urls),
    # path('books/',BookListAPIView.as_view()),
    # path('books//',BookDetailAPIView.as_view()),
    path('books/',BookListGenericView.as_view()),
    path('books//',BookDetailGenericView.as_view())
]
3.2 GenericAPIView & Mixin 实现接口

提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

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。

class BookListMixinGenericView(ListModelMixin, CreateModelMixin, GenericAPIView):
    # 指定序列化器类
    serializer_class = BookModelSerializer
    # 指定数据来源
    queryset = Book.objects.all()

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

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


class BookDetailMixinGenericView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
    # 指定序列化器类
    serializer_class = BookModelSerializer
    # 指定数据来源
    queryset = Book.objects.all()

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

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

    def delete(self, request, pk):
        return self.destroy(request, pk)
3.3 ListAPIView & CreateAPIView & ListCreateAPIView … 1)CreateAPIView
  • 提供 post方法

  • 继承自: GenericAPIView、CreateModelMixin

2)ListAPIView
  • 提供 get 方法

  • 继承自:GenericAPIView、ListModelMixin

3)RetrieveAPIView
  • 提供 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

class BookListMixinGenericView(ListModelMixin, CreateModelMixin, GenericAPIView):
    # 指定序列化器类
    serializer_class = BookModelSerializer
    # 指定数据来源
    queryset = Book.objects.all()

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

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


class BookListMixinGenericView(ListAPIView,CreateAPIView):
    # 指定序列化器类
    serializer_class = BookModelSerializer
    # 指定数据来源
    queryset = Book.objects.all()

class BookListMixinGenericView(ListCreateAPIView):
    # 指定序列化器类
    serializer_class = BookModelSerializer
    # 指定数据来源
    queryset = Book.objects.all()
四、视图集

视图集:之前是通过将详情视图和列表视图分开编写,因为存在两个get请求(查询所有和单个),而视图集就是为了统一这些接口,将这两个视图统一写到同一个视图类中,并能够自定义其它方法

4.1 ViewSet

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 保存数据
  • destory() 删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list()、create()等。视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。

class BookViewSet(ViewSet):
    """ 视图集:之前是通过将详情视图和列表视图分开编写,
    因为存在两个get请求(查询所有和单个),而视图集就是为了统一这些接口,
    将这两个视图统一写到同一个视图类中,并能够自定义其它方法 """
    def list(self,request):
        # 查询所有
        books = Book.objects.all()
        # 查询集要添加 many=True
        serializer = BookModelSerializer(books,many=True)
        return Response(serializer.data)
    def create(self,request):
        serializer = BookModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)
    def retrieve(self,request,pk):
        # 查询 pk 为 pk 的对象
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            serializer = BookModelSerializer(book)
            return Response(serializer.data)
    def update(self,request,pk):
        # 查询 pk 为 pk 的对象
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            # data 前端传过来的 json 数据
            serializer = BookModelSerializer(book, data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
    def destroy(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            book.delete()
            return Response(status.HTTP_204_NO_CONTENT)
urlpatterns = [
    path('admin/', admin.site.urls),
    # path('books/',BookListAPIView.as_view()),
    # path('books//',BookDetailAPIView.as_view()),
    # path('books/',BookListGenericView.as_view()),
    # path('books//',BookDetailGenericView.as_view()),
    path('books/',BookViewSet.as_view({'get':'list','post':'create'})),
    path('books//',BookViewSet.as_view({'get':'retrieve','put':'update','delete':'destory'}))
]
4.2 GenericViewSet

使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。

GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

ModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin

ReadOnlyModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin

class BookViewSet(ListModelMixin,RetrieveModelMixin,GenericViewSet):
# class BookViewSet(ModelViewSet):
    """ 视图集:之前是通过将详情视图和列表视图分开编写,
    因为存在两个get请求(查询所有和单个),而视图集就是为了统一这些接口,
    将这两个视图统一写到同一个视图类中,并能够自定义其它方法 """
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer

class BookViewSet(ReadOnlyModelViewSet):
# class BookViewSet(ModelViewSet):
    """
        ReadOnlyModelViewSet: books/ & books/1/  get请求
        ModelViewSet: books/ & books/1/  get请求 put delete
    """
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    """ 额外定义无pk """
    # 在通常的增删改查之外定义的行为,应该为其单独定义路由
    # 若果此行为不需要加pk,那么他就是列表视图,
    # 但是列表视图只有 list create
    # URL:path(r'books/latest/',BookViewSet.as_view({'get':'latest'}))
    """action装饰器参数详解
    methods:此操作响应的HTTP方法名称列表。默认仅GET。
    detail:必要参数。确定此操作是否应用于实例/详细信息请求或集合/列表请求。detail=False不是详情视图;detail=TRUE 是详情视图
    url_path:定义此操作的URL段。默认为被修饰的方法的名称。
    url_name:为这个动作定义内部(' reverse ') URL名称。默认为方法名,用下划线代替破折号。
    """
    @action(methods="get",detail=False)
    def latest(self,request):
        pass
    """ 额外定义有pk """
    # 有pk就是详情视图
    # 详情视图有:get put delete
    # URL:path(r'books//latest/',BookViewSet.as_view({'get':'read'}))
    @action(methods='get',detail=True)
    def title(self, request,pk):
        book = self.get_object()
        book.title = request.data['title']
        book.save()
        # return Response(self.get_serializer(book).data)
        pass
4.3 路由定义 常规定义
""" 额外定义无pk """
    # 在通常的增删改查之外定义的行为,应该为其单独定义路由
    # 若果此行为不需要加pk,那么他就是列表视图,
    # 但是列表视图只有 list create
    # URL:path(r'books/latest/',BookViewSet.as_view({'get':'latest'}))

""" 额外定义有pk """
    # 有pk就是详情视图
    # 详情视图有:get put delete
    # URL:path(r'books//latest/',BookViewSet.as_view({'get':'read'}))
DefaultRouter & SimpleRouter 定义
# # 指定 DRF-ModelView 路由
# 此方法只适合在视图集中使用,且只能生成标准的增删改查这五个基础的路由
# 若想要自定义的行为也生成路由,需要在自定义行为使用action行为,并指定相应的请求方法
    """action装饰器参数详解
    methods:此操作响应的HTTP方法名称列表。默认仅GET。
    detail:必要参数。确定此操作是否应用于实例/详细信息请求或集合/列表请求。detail=False不是详情视图;detail=TRUE 是详情视图
    url_path:定义此操作的URL段。默认为被修饰的方法的名称。
    url_name:为这个动作定义内部(' reverse ') URL名称。默认为方法名,用下划线代替破折号。
    """
# DefaultRouter,SimpleRouter 唯一区别:DefaultRouter会默认生成一个根路由,SimpleRouter不会
# router = DefaultRouter()
# router.register(r'api/books',BookViewSet)
# urlpatterns += router.urls
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/315887.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号