REST framework-ViewSets学习

ViewSets

1. 简介

Django REST framework 中的 ViewSet 允许将一组相关视图的逻辑组合在一个类中。它与其他框架中类似的概念,如“Resources”或“Controllers”相似。

ViewSet 类与普通基于类的视图不同,它不直接提供像 get()post() 这样的方法处理程序,而是提供了诸如 list()create() 等动作。

ViewSet 的方法处理程序只有在使用 as_view() 方法最终确定视图时,才与相应的动作绑定。

通常,不是在 URL 配置中显式地注册 ViewSet 中的视图,**而是使用路由器类来注册 ViewSe**t,路由器类会自动为您确定 URL 配置。

例如:

from rest_framework import viewsets
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer

class MyModelViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

然后通过路由器来处理 URL 映射:

from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'mymodels', MyModelViewSet)


from django.urls import include, path

urlpatterns = [
    path('', include(router.urls)),
    # 其他 URL 模式...
]

2.viewset

示例: 列出系统中的用户

from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response

class UserViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving users.
    """
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)

可以将此视图绑定到两个单独的视图中:

user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})

但是可以使用rest_framework.routers

from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = router.urls

通常希望使用提供默认行为集的现有基类,而不是编写自己的视集。例如

class UserViewSet(viewsets.ModelViewSet):
    """
    A viewset for viewing and editing user instances.
    """
    serializer_class = UserSerializer
    queryset = User.objects.all()

相比较view和viewset:

  • 重复的逻辑可以组合成一个类
  • 通过使用路由器,不需要自己处理url的配置问题

这两者都需要权衡取舍。使用常规视图和 URL confs 更明确,并为您提供更多控制权。如果您想快速启动并运行,或者当您有一个大型 API 并且希望在整个过程中强制执行一致的 URL 配置时,ViewSet 非常有用。

viewset操作

REST框架附带的默认路由器将为一组标准的创建/检索/更新/销毁样式操作提供路由,如下所示:

class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

Introspecting ViewSet actions

以下是关于 ViewSet 内省(Introspecting)操作的解释:

在分发(dispatch)过程中,ViewSet 具有以下可用的属性:

  1. basename:用于创建的 URL 名称的基础部分。
  2. action:当前操作的名称(例如,listcreate)。
  3. detail:一个布尔值,指示当前操作是针对列表视图还是详细视图进行配置。
  4. suffix:视图集类型的显示后缀,与 detail 属性相关。
  5. name:视图集的显示名称。此参数与 suffix 相互排斥。
  6. description:视图集中单个视图的显示描述。

这些属性可用于在视图的处理过程中获取有关当前操作和视图配置的信息,以便根据不同的情况进行定制化的处理,例如调整响应、进行权限检查或记录日志等。

def get_permissions(self):
    """
    Instantiates and returns the list of permissions that this view requires.
    """
    if self.action == 'list':
        permission_classes = [IsAuthenticated]
    else:
        permission_classes = [IsAdminUser]
    return [permission() for permission in permission_classes]

Marking extra actions for routing

以下是对关于标记额外路由操作的解释:

如果您有一些临时的方法应该是可路由的,您可以使用 @action 装饰器将它们标记为可路由。和常规操作一样,额外的操作可以针对单个对象或整个集合。要表明这一点,可以将 detail 参数设置为 TrueFalse

例如,DefaultRouter 会相应地配置 URL 模式。如果将 detail=True ,那么配置的详细操作的 URL 模式中将包含对象的主键(pk)。

以下是一个示例:

from rest_framework import viewsets
from rest_framework.decorators import action

class UserViewSet(viewsets.ModelViewSet):
    # 常规的视图集设置...

    @action(detail=True, methods=['get'])
    def custom_detail_action(self, request, pk=None):
        # 处理针对单个用户的自定义操作的逻辑
        return Response({'message': f'Custom detail action for user {pk}'})

    @action(detail=False, methods=['get'])
    def custom_collection_action(self, request):
        # 处理针对用户集合的自定义操作的逻辑
        return Response({'message': 'Custom collection action'})

在上述示例中,custom_detail_action 是一个针对单个用户(通过主键 pk 识别)的自定义操作,而 custom_collection_action 是针对用户集合的操作。

默认情况下,装饰器将路由请求,但也可以通过设置参数来接受其他 HTTP 方法。

 @action(detail=True, methods=['post', 'delete'])
    def unset_password(self, request, pk=None):
       ...

装饰器允许您覆盖任何视图集级别的配置,例如:permission_classes,serializer_class,filter_backends

    @action(detail=True, methods=['post'], permission_classes=[IsAdminOrIsSelf])
    def set_password(self, request, pk=None):
       ...

然后,这两个新操作将在 urls 和 中可用。使用 and 参数更改操作的 URL 段和反向 URL 名称。^users/{pk}/set_password/$``^users/{pk}/unset_password/$``url_path``url_name

若要查看所有额外的操作,请调用该方法。.get_extra_actions()

3.GenericViewSet

GenericViewSet 是 Django REST framework 中的一个类,它继承自 ViewSetMixinGenericAPIView

GenericViewSet 本身并不提供任何默认的操作实现,但是结合 mixins 类和使用 @action 装饰器,可以方便地构建出各种自定义的视图行为。

它的主要优势在于:

  1. 继承了 GenericAPIView 的常见属性和方法,如 querysetserializer_class 等,方便进行数据获取和序列化的配置。
  2. 可以灵活地组合不同的 mixins 类(如 CreateModelMixinRetrieveModelMixin 等)来实现具体的视图操作(如创建、获取、更新等)。
  3. 通过 @action 装饰器能够添加自定义的额外操作,并且可以精确控制这些操作的细节,比如请求方法、是否针对单个对象还是对象集合等。

以下是一个使用 GenericViewSet 构建 API 的示例:

首先,创建模型、序列化器和视图:

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    publication_year = models.IntegerField()

# serializers.py
from rest_framework import serializers
from.models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

# views.py
from rest_framework import viewsets
from rest_framework.mixins import (
    CreateModelMixin,
    RetrieveModelMixin,
    UpdateModelMixin,
    DestroyModelMixin,
    ListModelMixin
)
from.serializers import BookSerializer
from.models import Book

class BookViewSet(viewsets.GenericViewSet,
                  CreateModelMixin,
                  RetrieveModelMixin,
                  UpdateModelMixin,
                  DestroyModelMixin,
                  ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

然后,设置路由:

# urls.py
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from.views import BookViewSet

router = DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

这样,就可以通过相应的 URL 对书籍数据进行创建、获取、更新、删除和获取列表等操作。

4.ModelViewSet

ModelViewSet 是 Django REST framework 中一个非常强大和方便的类,它继承自 GenericViewSet,并结合了多个 Mixin 类(CreateModelMixinRetrieveModelMixinUpdateModelMixinDestroyModelMixinListModelMixin),从而提供了对模型数据的完整的 CRUD 操作(创建、读取、更新、删除和列表获取)的支持。

使用 ModelViewSet 的一般步骤如下:

  1. 定义模型、序列化器和 ModelViewSet 类:
from django.db import models
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet

# 模型
class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    publication_year = models.IntegerField()

# 序列化器
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

# ModelViewSet
class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
  1. 设置路由:
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from.views import BookViewSet

router = DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

这样,就可以通过发送相应的 HTTP 请求(如 GET 用于获取列表或单个对象,POST 用于创建,PUTPATCH 用于更新,DELETE 用于删除)来操作书籍数据。

例如,使用 GET 请求 http://your_domain/books/ 可以获取书籍列表,使用 GET 请求 http://your_domain/books/1/ 可以获取 ID 为 1 的书籍详情,使用 POST 请求 http://your_domain/books/ 并提供相应的数据可以创建新的书籍,等等。

关于权限设置

要在 ModelViewSet 中设置权限,可以通过以下几种方式:

  1. 在视图类中直接设置权限类:
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet

class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticated]

在上述示例中,使用了 IsAuthenticated 权限类,这意味着只有经过身份验证的用户才能访问该视图的操作。

  1. 自定义权限类并在视图中使用:

首先创建自定义的权限类:

from rest_framework import permissions

class IsAdminOrReadOnly(permissions.BasePermission):
    def has_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return True
        return request.user.is_staff

然后在视图中应用:

class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAdminOrReadOnly]
  1. 基于不同的操作设置不同的权限:
class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get_permissions(self):
        if self.action == 'create':
            permission_classes = [IsAuthenticated]
        elif self.action == 'update':
            permission_classes = [IsAdminUser]
        else:
            permission_classes = [AllowAny]
        return [permission() for permission in permission_classes]

上述示例中,根据不同的操作(createupdate 等)设置了不同的权限类。

Django REST framework 中除了 IsAuthenticated ,还有以下一些常用的权限类

  1. IsAdminUser:只允许管理员用户访问。管理员用户通常是指 is_staff=True 的用户。

  2. AllowAny:允许任何用户访问,不进行任何权限检查。

  3. IsAuthenticatedOrReadOnly:已认证的用户可以进行读写操作,未认证的用户只能进行只读(如 GET 请求)操作。

  4. DjangoModelPermissions:检查用户是否具有与 Django 模型权限相关的权限。这通常与 Django 的默认权限系统配合使用,需要在模型的 Meta 中定义权限。

  5. DjangoObjectPermissions:类似于 DjangoModelPermissions,但作用于对象级别,而不仅仅是模型级别。

  6. TokenHasReadWriteScope:用于验证 OAuth2 令牌是否具有读写权限。

  7. ReadOnly:只允许只读操作(如 GETHEADOPTIONS 请求)。

  8. SAFE_METHODS:这不是一个权限类,但常用于权限判断,表示 GETHEADOPTIONS 等安全方法。

可以根据具体的需求选择和组合使用这些权限类来控制对 API 的访问。

5.ReadOnlyModelViewSet

ReadOnlyModelViewSet 是 Django REST framework 中的一个视图集类。

它继承自 ModelViewSet ,但只允许只读操作,即只支持 GET 方法来获取列表(list)和单个对象详情(retrieve),不支持创建(create)、更新(update)和删除(destroy)操作。

这对于只需要提供数据读取访问而不允许修改数据的场景非常有用,例如展示一些公共的信息、只读的资源等

使用 ReadOnlyModelViewSet 与使用其他视图集类类似,您需要指定 querysetserializer_class 等属性。

示例:

from rest_framework.viewsets import ReadOnlyModelViewSet
from your_app.models import YourModel
from your_app.serializers import YourModelSerializer

class YourReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer

ViewSetGenericAPIView

ViewSetGenericAPIView 有以下一些区别:

  1. 功能完整性:

    • GenericAPIView 提供了一些基础的属性和方法,如 querysetserializer_class 等,以及一些用于获取数据和对象的基本方法,但不直接包含具体的请求处理方法(如 getpost 等)。
    • ViewSet 则更像是一组相关操作的集合,它默认提供了常见的操作方法(如 listcreateretrieveupdatedestroy),但这些方法在未通过 as_view 方法绑定之前是未实现的。
  2. 处理请求方式:

    • GenericAPIView 需要开发者自己重写具体的请求处理方法(如 getpost 等)来实现相应的功能。
    • ViewSet 中的操作方法是通过 as_view 方法在最终确定视图时与具体的请求方法进行绑定。
  3. 路由配置:

    • 对于 GenericAPIView ,通常需要手动在 URL 配置中为每个请求方法明确指定对应的路由。
    • ViewSet 更常与路由器(如 DefaultRouter )配合使用,路由器会根据 ViewSet 中定义的操作自动生成相应的路由。
  4. 代码复用性:

    • ViewSet 更适合处理一组相关且逻辑紧密的视图操作,有利于提高代码的复用性和一致性。
    • GenericAPIView 则更灵活,适用于需要更精细自定义的场景。
  5. 复杂程度:

    • GenericAPIView 相对较简单,更易于理解和直接控制每个请求的处理逻辑。
    • ViewSet 由于其集成度较高,对于初学者来说可能在理解和使用上稍微复杂一些。

在开发中选择 ViewSet 还是 GenericAPIView 可以考虑以下几个因素:

  1. 功能需求的复杂性:

    • 如果您的视图逻辑相对简单,只需要处理基本的 CRUD 操作,并且希望利用框架提供的默认行为和自动路由生成,ViewSet 可能是一个较好的选择。
    • 如果您的视图需要更复杂的定制逻辑,例如根据不同的条件执行不同的操作,或者需要对请求和响应进行更精细的控制,GenericAPIView 可能更合适,因为您可以更灵活地重写具体的方法。
  2. 代码复用性和一致性:

    • 如果您有一组相关的视图操作,它们共享很多相同的属性和逻辑,ViewSet 可以更好地封装这些共同部分,提高代码的复用性和一致性。
    • GenericAPIView 在处理多个不同但又有些相似的视图时,可能需要更多的重复代码设置。
  3. 开发效率:

    • 对于快速开发和原型设计,ViewSet 结合路由器可以快速搭建起基本的 API 结构。
    • 如果您对 Django REST framework 的细节和底层原理有更深入的理解,并且需要更精确地控制视图的行为,使用 GenericAPIView 可能不会花费太多额外的时间,同时能满足特定需求。
  4. 团队技术水平和项目规范:

    • 如果团队成员对 ViewSet 的概念和使用比较熟悉,或者项目中有明确的规范要求使用某种方式,那么应遵循相应的规范。
  5. 未来的可扩展性:

    • 考虑项目未来可能的功能扩展和变更。如果预计会有较多的定制和扩展需求,GenericAPIView 可能提供了更大的灵活性。

总之,没有绝对的规则说一定要使用哪一个,需要根据具体的项目需求、团队情况和个人偏好来决定。

  • 29
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白日与明月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值