📌  相关文章
📜  基于类的视图——Django Rest Framework

📅  最后修改于: 2022-05-13 01:54:25.052000             🧑  作者: Mango

基于类的视图——Django Rest Framework

基于类的视图有助于组成可重用的行为位。 Django REST Framework 提供了几个预构建的视图,允许我们重用通用功能并保持代码干燥。在本节中,我们将深入研究 Django REST Framework 中不同的基于类的视图。

接口视图

APIView 类为标准列表和详细信息视图提供了通常需要的行为。使用 APIView 类,我们可以将根视图重写为基于类的视图。它们提供诸如 get()、post()、put()、patch() 和 delete() 等操作方法,而不是定义处理程序方法。

使用 APIView 创建视图

我们来看看如何使用 APIView 创建视图。 views.py 文件模块如下:

Python3
from django.shortcuts import render
from django.http import Http404
  
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
  
from transformers.models import Transformer
from transformers.serializers import TransformerSerializer
  
class TransformerList(APIView):
    """
    List all Transformers, or create a new Transformer
    """
  
    def get(self, request, format=None):
        transformers = Transformer.objects.all()
        serializer = TransformerSerializer(transformers, many=True)
        return Response(serializer.data)
  
    def post(self, request, format=None):
        serializer = TransformerSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data,
                            status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  
class TransformerDetail(APIView):
    """
    Retrieve, update or delete a transformer instance
    """
    def get_object(self, pk):
        # Returns an object instance that should 
        # be used for detail views.
        try:
            return Transformer.objects.get(pk=pk)
        except Transformer.DoesNotExist:
            raise Http404
  
    def get(self, request, pk, format=None):
        transformer = self.get_object(pk)
        serializer = TransformerSerializer(transformer)
        return Response(serializer.data)
  
    def put(self, request, pk, format=None):
        transformer = self.get_object(pk)
        serializer = TransformerSerializer(transformer, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  
    def patch(self, request, pk, format=None):
        transformer = self.get_object(pk)
        serializer = TransformerSerializer(transformer,
                                           data=request.data,
                                           partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
          
  
    def delete(self, request, pk, format=None):
        transformer = self.get_object(pk)
        transformer.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


Python3
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from transformers import views
  
urlpatterns = [
    path('transformers/', views.TransformerList.as_view()),
    path('transformers//', views.TransformerDetail.as_view()),
]
  
urlpatterns = format_suffix_patterns(urlpatterns)


Python3
from django.contrib import admin
from django.urls import path, include
  
urlpatterns = [
    path('', include('transformers.urls')),
]


Python3
from rest_framework import mixins
from rest_framework import generics
from transformers.models import Transformer
from transformers.serializers import TransformerSerializer
  
class TransformerList(mixins.ListModelMixin,
                      mixins.CreateModelMixin,
                      generics.GenericAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer
  
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
  
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
  
class TransformerDetail(mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        generics.GenericAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer
  
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
  
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
  
    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)
  
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)


Python3
from rest_framework import generics
  
from transformers.models import Transformer
from transformers.serializers import TransformerSerializer
  
class TransformerList(generics.ListCreateAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer
  
class TransformerDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer


代码类似于常规的 Django 视图,但不同 HTTP 方法之间有更好的分离。

  • get() 方法处理 HTTP GET 请求
  • post() 方法处理 HTTP POST 请求
  • put() 方法处理 HTTP PUT 请求
  • patch() 方法处理 HTTP PATCH 请求
  • delete() 方法处理 HTTP DELETE 请求

设置 URL 配置

由于我们使用基于类的视图,因此我们在 urls.py 文件路径中提及视图的方式略有不同。在 app (transformers) 文件夹中创建一个名为 urls.py 的新文件(如果不存在)并添加以下代码

蟒蛇3

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from transformers import views
  
urlpatterns = [
    path('transformers/', views.TransformerList.as_view()),
    path('transformers//', views.TransformerDetail.as_view()),
]
  
urlpatterns = format_suffix_patterns(urlpatterns)

接下来,设置根 URL 配置。您可以打开urls.py(settings.py文件所在的文件夹)并添加以下代码

蟒蛇3

from django.contrib import admin
from django.urls import path, include
  
urlpatterns = [
    path('', include('transformers.urls')),
]

编写和发送 HTTP 请求

1. 创建一个新条目——

HTTPie 命令是:

输出

HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 194
Content-Type: application/json
Date: Sat, 23 Jan 2021 03:48:46 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader",
    "id": 1,
    "name": "Optimus Prime"
}

分享命令提示符截图供您参考:

2. 检索现有条目

擎天柱的pk值是1,让我们传递pk值并检索详情

HTTPie 命令是:

输出

HTTP/1.1 200 OK
Allow: GET, HEAD, OPTIONS
Content-Length: 194
Content-Type: application/json
Date: Sat, 23 Jan 2021 03:50:42 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader",
    "id": 1,
    "name": "Optimus Prime"
}

分享命令提示符截图供大家参考

3. 更新现有条目

让我们通过将其设置为 False 来更新名为 alive 的字段。 HTTPie 命令是:

输出

HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 195
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:22:30 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": false,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader",
    "id": 1,
    "name": "Optimus Prime"
}

分享命令提示符截图供大家参考

4. 部分更新现有条目

让我们部分更新名为 description 的字段。 HTTPie 命令是:

输出

HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 181
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:32:40 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": false,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous and leader of all Autobots",
    "id": 1,
    "name": "Optimus Prime"
}

分享命令提示符截图

5. 删除现有条目

我们将创建一个新条目并将其删除。让我们使用以下 HTTPie 命令创建一个“测试”条目:

输出

HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 77
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:34:41 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": false,
    "alternate_mode": null,
    "description": null,
    "id": 2,
    "name": "Test"
}

现在让我们删除“测试”条目(pk = 2)。删除条目的 HTTPie 命令是

输出

HTTP/1.1 204 No Content
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 0
Date: Sat, 23 Jan 2021 04:35:06 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

分享命令提示符截图

混合

Mixin 类允许我们组合可重用的行为。它们可以从 rest_framework.mixins 导入。让我们讨论不同类型的 mixin 类

  • ListModelMixin :它提供了一个.list(request, *args, **kwargs)方法来列出查询集。如果查询集已填充,则响应正文将具有200 OK响应,其中包含查询集的序列化表示。
  • CreateModelMixin :它提供了一个.create(request, *args, **kwargs)方法来创建和保存新的模型实例。如果创建了对象,则响应正文具有201 Created响应,并带有对象的序列化表示。如果无效,它会返回带有错误详细信息的400 Bad Request响应。
  • RetrieveModelMixin :它提供了一个.retrieve(request, *args, **kwargs)方法,用于在响应中返回现有模型实例。如果可以检索到对象,则响应正文具有200 OK响应,并带有对象的序列化表示。否则,它将返回404 Not Found
  • UpdateModelMixin :它提供了一个.update(request, *args, **kwargs)方法来更新和保存现有的模型实例。它还提供了一个.partial_update(request, *args, **kwargs)方法用于部分更新和现有模型实例。 .如果对象被更新,响应正文有一个200 OK响应,带有对象的序列化表示。否则,将返回带有错误详细信息的 400 Bad Request 响应。
  • DestroyModelMixin :它提供了一个.destroy(request, *args, **kwargs)方法来删除现有的模型实例。如果对象被删除,则响应正文有204 No Content响应,否则将返回404 Not Found

使用 Mixin 创建视图

让我们来看看如何使用 Mixin 类。 views.py 文件模块如下:

蟒蛇3

from rest_framework import mixins
from rest_framework import generics
from transformers.models import Transformer
from transformers.serializers import TransformerSerializer
  
class TransformerList(mixins.ListModelMixin,
                      mixins.CreateModelMixin,
                      generics.GenericAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer
  
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
  
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
  
class TransformerDetail(mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        generics.GenericAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer
  
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
  
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
  
    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)
  
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

在这里,GenericAPIView 类提供了核心功能,我们正在向它添加 mixin 类。 querysetserializer_class是 GenericAPIView 类的基本属性。 queryset 属性用于从该视图返回对象,serializer_class 属性用于验证、反序列化输入和序列化输出。

在 TransformerList 类中,我们使用提供 .list() 和 .create() 操作的 mixin 类并将这些操作绑定到 get() 和 post() 方法。在 TransformerDetail 类中,我们使用提供 .retrieve()、.update()、.partial_update() 和 . destroy() 操作并将操作绑定到 get()、put()、patch() 和 delete() 方法。

编写和发送 HTTP 请求

1.新建一个条目

HTTPie 命令是

输出

HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 161
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:58:26 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 VW Beetle",
    "description": "Small, eager, and brave, Bumblebee acts as a messenger, scout, and spy",
    "id": 3,
    "name": "Bumblebee"
}

2. 检索所有条目

HTTPie 命令是

输出

HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 345
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:59:42 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "alive": true,
        "alternate_mode": "1979 VW Beetle",
        "description": "Small, eager, and brave, Bumblebee acts as a messenger, scout, and spy",
        "id": 3,
        "name": "Bumblebee"
    },
    {
        "alive": false,
        "alternate_mode": "1979 Freightliner Semi",
        "description": "Optimus Prime is the strongest and most courageous and leader of all Autobots",
        "id": 1,
        "name": "Optimus Prime"
    }
]

分享命令提示符截图供大家参考

基于类的通用视图

为了使用基于类的通用视图,视图类应该从rest_framework.generics 导入。

  • CreateAPIView :它提供了一个 post 方法处理程序,用于仅创建端点。 CreateAPIView 扩展了 GenericAPIView 和 CreateModelMixin
  • ListAPIView :它提供了一个 get 方法处理程序,用于只读端点来表示模型实例的集合。 ListAPIView 扩展了 GenericAPIView 和 ListModelMixin。
  • RetrieveAPIView :它提供了一个 get 方法处理程序,用于只读端点来表示单个模型实例。 RetrieveAPIView 扩展了 GenericAPIView 和 RetrieveModelMixin。
  • DestroyAPIView :它提供了一个删除方法处理程序,用于单个模型实例的仅删除端点。 DestroyAPIView 扩展了 GenericAPIView 和 DestroyModelMixin。
  • UpdateAPIView :它提供 put 和 patch 方法处理程序,用于单个模型实例的仅更新端点。 UpdateAPIView 扩展了 GenericAPIView 和 UpdateModelMixin。
  • ListCreateAPIView :它提供了 get 和 post 方法处理程序,用于读写端点来表示模型实例的集合。 ListCreateAPIView 扩展了 GenericAPIView、ListModelMixin 和 CreateModelMixin..
  • RetrieveUpdateAPIView :它提供了 get、put 和 patch 方法处理程序。它用于读取或更新端点以表示单个模型实例。 RetrieveUpdateAPIView 扩展了 GenericAPIView、RetrieveModelMixin 和 UpdateModelMixin。
  • RetrieveDestroyAPIView :它提供 get 和 delete 方法处理程序,用于读取或删除端点以表示单个模型实例。 RetrieveDestroyAPIView 扩展了 GenericAPIView、RetrieveModelMixin 和 DestroyModelMixin。
  • RetrieveUpdateDestroyAPIView :它提供了 get、put、patch 和 delete 方法处理程序。它用于读写删除端点以表示单个模型实例。它扩展了 GenericAPIView、RetrieveModelMixin、UpdateModelMixin 和 DestroyModelMixin。

使用基于类的通用视图创建视图

让我们来看看如何使用 Mixin 类。这里我们将利用 ListCreateAPIView 和 RetrieveUpdateDestroyAPIView。 views.py 文件模块如下:

蟒蛇3

from rest_framework import generics
  
from transformers.models import Transformer
from transformers.serializers import TransformerSerializer
  
class TransformerList(generics.ListCreateAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer
  
class TransformerDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Transformer.objects.all()
    serializer_class = TransformerSerializer

您会注意到我们能够避免大量样板代码。这些通用视图结合了来自 mixin 类的可重用行为。我们来看一下 ListCreateAPIView 和 RetrieveUpdateDestroyAPIView 的声明:

class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
   ......

class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
                                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                                   GenericAPIView):
  ......

编写和发送 HTTP 请求

1.新建一个条目

HTTPie 命令是

输出

HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 133
Content-Type: application/json
Date: Sat, 23 Jan 2021 05:28:45 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Porsche 924",
    "description": "His eagerness and daring have no equal",
    "id": 5,
    "name": "Cliffjumper"
}

分享命令提示符截图供大家参考

2. 更新现有条目

HTTPie 命令是

输出

HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 111
Content-Type: application/json
Date: Sat, 23 Jan 2021 05:35:39 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Porsche 924",
    "description": "Eager and Daring",
    "id": 5,
    "name": "Cliffjumper"
}

分享命令提示符截图供大家参考

3.部分更新现有条目

输出

HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 151
Content-Type: application/json
Date: Sat, 23 Jan 2021 05:37:54 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 VW Beetle",
    "description": "Small, eager, and brave. Acts as a messenger, scout, and spy",
    "id": 3,
    "name": "Bumblebee"
}

分享命令提示符截图供大家参考

在本节中,我们探索了 Django REST 框架提供的不同类型的基于类的视图。我们使用 APIView 实现了视图并解释了不同类型的 mixin 类。最后,我们展示了各种类型的基于类的通用视图,并演示了它们如何避免大量样板代码。