【DRF】Django Rest Framework(5.DRF中的通用视图类-GenericAPIView方法说明与使用说明)

1. GenericAPIView [通用视图类],概述

  • 继承自 APIView
  • 增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。
  • 通常在使用时,可搭配一个或者多个Mixin扩展类
  • 源码
    当我们查看 GenericAPIView 的源码时,发现,他也是继承了views.APIView
class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """
    # You'll need to either set these attributes,
    # or override `get_queryset()`/`get_serializer_class()`.
    # If you are overriding a view method, it is important that you call
    # `get_queryset()` instead of accessing the `queryset` property directly,
    # as `queryset` will get evaluated only once, and those results are cached
    # for all subsequent requests.
    queryset = None
    serializer_class = None

    # If you want to use object lookups other than pk, set 'lookup_field'.
    # For more complex lookup requirements override `get_object()`.
    lookup_field = 'pk'
    lookup_url_kwarg = None

    # The filter backend classes to use for queryset filtering
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

    # The style to use for queryset pagination.
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

    def get_queryset(self):
        """
        Get the list of items for this view.
        This must be an iterable, and may be a queryset.
        Defaults to using `self.queryset`.

        This method should always be used rather than accessing `self.queryset`
        directly, as `self.queryset` gets evaluated only once, and those results
        are cached for all subsequent requests.

        You may want to override this if you need to provide different
        querysets depending on the incoming request.

        (Eg. return a list of items that is specific to the user)
        """
        assert self.queryset is not None, (
            "'%s' should either include a `queryset` attribute, "
            "or override the `get_queryset()` method."
            % self.__class__.__name__
        )

        queryset = self.queryset
        if isinstance(queryset, QuerySet):
            # Ensure queryset is re-evaluated on each request.
            queryset = queryset.all()
        return queryset

    def get_object(self):
        """
        Returns the object the view is displaying.

        You may want to override this if you need to provide non-standard
        queryset lookups.  Eg if objects are referenced using multiple
        keyword arguments in the url conf.
        """
        queryset = self.filter_queryset(self.get_queryset())

        # Perform the lookup filtering.
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

        assert lookup_url_kwarg in self.kwargs, (
            'Expected view %s to be called with a URL keyword argument '
            'named "%s". Fix your URL conf, or set the `.lookup_field` '
            'attribute on the view correctly.' %
            (self.__class__.__name__, lookup_url_kwarg)
        )

        filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
        obj = get_object_or_404(queryset, **filter_kwargs)

        # May raise a permission denied
        self.check_object_permissions(self.request, obj)

        return obj

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        kwargs.setdefault('context', self.get_serializer_context())
        return serializer_class(*args, **kwargs)
 
    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.

        You may want to override this if you need to provide different
        serializations depending on the incoming request.

        (Eg. admins get full serialization, others get basic serialization)
        """
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method."
            % self.__class__.__name__
        )

        return self.serializer_class

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return {
            'request': self.request,
            'format': self.format_kwarg,
            'view': self
        }

    def filter_queryset(self, queryset):
        """
        Given a queryset, filter it with whichever filter backend is in use.

        You are unlikely to want to override this method, although you may need
        to call it either from a list view, or from a custom `get_object`
        method if you want to apply the configured filtering backend to the
        default queryset.
        """
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

    @property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator

    def paginate_queryset(self, queryset):
        """
        Return a single page of results, or `None` if pagination is disabled.
        """
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

    def get_paginated_response(self, data):
        """
        Return a paginated style `Response` object for the given output data.
        """
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)

2.get_serializer_class(self)

  • 当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在 get_serializer_class 方法中通过返回不同的序列化
  • 类名就可以让视图方法执行不同的序列化器对象了
  • 函数返回序列化器类,默认返回 serializer_class ,可以重写
def get_serializer_class(self):
    """
    Return the class to use for the serializer.
    Defaults to using `self.serializer_class`.

    You may want to override this if you need to provide different
    serializations depending on the incoming request.

    (Eg. admins get full serialization, others get basic serialization)
    """
    assert self.serializer_class is not None, (
        "'%s' should either include a `serializer_class` attribute, "
        "or override the `get_serializer_class()` method."
        % self.__class__.__name__
    )

    return self.serializer_class

3.get_serializer_class(self)

  • 函数返回序列化器队对象
  • 主要用来提供给Mixin扩展类使用,如果我们在视图中,想要获取序列化器对象,也可以直接调用此方法
  • 注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、
    format、view、这三个数据对象可以定义序列化器时使用
    • request 当前视图的请求对象
    • view 当前请求的类视图对象
    • format 当前请求期望返回的数据格式
def get_serializer(self, *args, **kwargs):
    """
    Return the serializer instance that should be used for validating and
    deserializing input, and for serializing output.
    """
    serializer_class = self.get_serializer_class()
    kwargs.setdefault('context', self.get_serializer_context())
    return serializer_class(*args, **kwargs)

4.get_queryset(self)

  • 返回视图使用的查询集
  • 主要用来提供Mixin扩展类使用,是列表视图与详情视图获取数据的基础
  • 默认返回queryset属性,可以重写
def get_queryset(self):
    """
    Get the list of items for this view.
    This must be an iterable, and may be a queryset.
    Defaults to using `self.queryset`.

    This method should always be used rather than accessing `self.queryset`
    directly, as `self.queryset` gets evaluated only once, and those results
    are cached for all subsequent requests.

    You may want to override this if you need to provide different
    querysets depending on the incoming request.

    (Eg. return a list of items that is specific to the user)
    """
    assert self.queryset is not None, (
        "'%s' should either include a `queryset` attribute, "
        "or override the `get_queryset()` method."
        % self.__class__.__name__
    )

    queryset = self.queryset
    if isinstance(queryset, QuerySet):
        # Ensure queryset is re-evaluated on each request.
        queryset = queryset.all()
    return queryset

5.def get_object(self):

  • 返回详情视图所需要的模型类的数据对象
  • 主要用来提供给Mixin扩展类使用
  • 在视图中可以调用该方法获取详情信息的模型对象
  • 若详情访问的模型类对象不存在,会返回404
  • 该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问
def get_object(self):
    """
    Returns the object the view is displaying.

    You may want to override this if you need to provide non-standard
    queryset lookups.  Eg if objects are referenced using multiple
    keyword arguments in the url conf.
    """
    queryset = self.filter_queryset(self.get_queryset())

    # Perform the lookup filtering.
    lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

    assert lookup_url_kwarg in self.kwargs, (
        'Expected view %s to be called with a URL keyword argument '
        'named "%s". Fix your URL conf, or set the `.lookup_field` '
        'attribute on the view correctly.' %
        (self.__class__.__name__, lookup_url_kwarg)
    )

    filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
    obj = get_object_or_404(queryset, **filter_kwargs)

    # May raise a permission denied
    self.check_object_permissions(self.request, obj)

    return obj

5. 使用实例

  • view.py
from rest_framework.generics import GenericAPIView


class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"


class BookView(GenericAPIView):

    # queryset 这个变量名称不能变
    queryset = Book.objects.all()
    # # serializer_class 这个变量名称不能变
    serializer_class = BookSerializers


    # 查所有
    def get(self, request):
        # get_queryset() 就是取 queryset 这个变量的值,即 Book.objects.all(),取出所有的数据
        # book_list = self.get_queryset()
        # 构建序列化器对象
        # serializer = self.get_serializer_class()(instance=self.get_queryset(), many=True)
        serializer = self.get_serializer(instance=self.get_queryset(), many=True)
        return Response(serializer.data)

    # 增加一个
    def post(self, request):
        # 获取参数
        data = request.data

        #  构建序列化器对象
        serializer = self.get_serializer(data=data)

        # 校验数据
        # 校验原理:
        # 1.所有符合的数据都放在,serializer.validated_data
        # 2.不符合数据的都放在,serializer.errors
        if serializer.is_valid():  # 返回一个布尔值,所有字段都符合才返回True,反之,返回False
            # 数据校验通过,存入数据库中
            # new_book = Book.objects.create(**serializer.validated_data)

            serializer.save()

            return Response(serializer.data)
        else:
            # 数据校验失败
            return Response(serializer.errors)


class BookDetailsView(GenericAPIView):
    # queryset 这个变量名称不能变
    queryset = Book.objects.all()
    # # serializer_class 这个变量名称不能变
    serializer_class = BookSerializers

    # 查一个
    def get(self, request, pk):
        serializer = self.get_serializer(instance=self.get_object(), many=False)
        return Response(serializer.data)

    # 修改一个
    def put(self, request, pk):
        book = request.data

        # 构建序列化器对象
        serializer = self.get_serializer(instance=self.get_object(), data=book)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

    # 删除一个
    def delete(self, request, pk):
        self.get_object().delete()
        return Response()
  • urls.py
from django.contrib import admin
from django.urls import path, re_path
from sers import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('sers/book/', views.BookView.as_view()),
    # 注意: 这块是固定的pk
    re_path(r'sers/book/(?P<pk>\d+)', views.BookDetailsView.as_view()),
]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

还是那个同伟伟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值