一、概述

  • GenericAPIView继承自APIView
  • 为列表视图和详情视图添加了常用的行为和属性,更加方便
  • 可以和一个或者多个Mixin类配合使用
  • APIView虽然相对于django中的View类开发起来更加的便捷,但是在数据对象和序列化器对象上重复的代码很多,依然不够简洁,GenericAPIView提供了更加简便的方式
    • 在类的开头写上queryset、serializer_class、lookup_field、lookup_url_kwarg、filter_backends和pagination_class属性,这样做的优点是:如果这些属性需要改变,只在开头改变即可,很便捷。如果不提取出公共的属性,需要改变很多的地方。
    • 调用:
      • 方式一:直接在方法中使用self.属性名的方式调用
      • 方式二:使用self调用GenericAPIView中已经定义好的方法来调用,例如:self.get_queryset()调用queryset属性,self.get_serializer()调用serializer_class属性等

        二、GenericAPIView实现列表视图

        (一)、get请求获取所有数据

        ```python from rest_framework import status from .models import UserProfile from .serializers import UserProfileSerializers

class UserListGenericView(GenericAPIView): “”” 二级视图列表详情 “”” queryset = UserProfile.objects.all() serializer_class = UserProfileSerializers

  1. def get(self, request):
  2. # users = self.queryset
  3. users = self.get_queryset()
  4. # serializer = self.serializer_class
  5. serializer = self.get_serializer(instance=users, many=True)
  6. return Response(serializer.data, status=status.HTTP_200_OK)
  1. <a name="N0Mb5"></a>
  2. #### (二)、post向数据库中创建一条数据
  3. ```python
  4. from rest_framework import status
  5. from .models import UserProfile
  6. from .serializers import UserProfileSerializers
  7. class UserListGenericView(GenericAPIView):
  8. """ 二级视图列表详情 """
  9. queryset = UserProfile.objects.all()
  10. serializer_class = UserProfileSerializers
  11. def post(self, request):
  12. serializer = self.get_serializer(data=request.data)
  13. serializer.is_valid(raise_exception=True)
  14. serializer.save()
  15. return Response(serializer.data, status=status.HTTP_201_CREATED)

三、GenericAPIView实现详情视图

  • 在方法前边写上queryset,queryset=模型名.objects.all(),注意这里必须是all()
  • 在方法中调用的时候需要使用self.get_object()方法,方法内不需要传入任何参数,就可以通过id/pk创建单条数据对象

(一)、获取某一条数据

  1. from rest_framework.generics import GenericAPIView
  2. from rest_framework.response import Response
  3. from rest_framework import status
  4. from .models import UserProfile
  5. from .serializers import UserProfileSerializers
  6. class UserDetailGenericView(GenericAPIView):
  7. """ 详情视图 """
  8. queryset = UserProfile.objects.all()
  9. serializer_class = UserProfileSerializers
  10. def get(self, request, pk):
  11. user = self.get_object()
  12. serializer = self.get_serializer(instance=user)
  13. return Response(serializer.data, status=status.HTTP_200_OK)

(二)、更新某一条数据

  1. from rest_framework.generics import GenericAPIView
  2. from rest_framework.response import Response
  3. from rest_framework import status
  4. from .models import UserProfile
  5. from .serializers import UserProfileSerializers
  6. class UserDetailGenericView(GenericAPIView):
  7. """ 详情视图 """
  8. queryset = UserProfile.objects.all()
  9. serializer_class = UserProfileSerializers
  10. def put(self, request, pk):
  11. user = self.get_object()
  12. serializer = self.get_serializer(instance=user, data=request.data)
  13. serializer.is_valid(raise_exception=True)
  14. serializer.save()
  15. return Response(serializer.data, status=status.HTTP_201_CREATED)

(三)、删除某一条数据

  1. from rest_framework.generics import GenericAPIView
  2. from rest_framework.response import Response
  3. from rest_framework import status
  4. from .models import UserProfile
  5. from .serializers import UserProfileSerializers
  6. class UserDetailGenericView(GenericAPIView):
  7. """ 详情视图 """
  8. queryset = UserProfile.objects.all()
  9. serializer_class = UserProfileSerializers
  10. def delete(self, request, pk):
  11. self.get_object().delete()
  12. return Response(status=status.HTTP_204_NO_CONTENT)

(四)、lookup_filed和lookup_url_kwarg属性

  • 在使用GenericAPIView时,如果通过url传递参数,参数名默认时pk,如果写id会报如下的错误:

    1. Expected view UserDetailGenericView to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
  • 原因:在源码中设定的是lookup_field字段为’pk’,会先去查找look_url_kwarg参数,如果该参数为空,则取lookup_field为对应的参数名

    1. ####源码分析
    2. class GenericAPIView(views.APIView):
    3. """
    4. Base class for all other generic views.
    5. """
    6. queryset = None
    7. serializer_class = None
    8. # If you want to use object lookups other than pk, set 'lookup_field'.
    9. # For more complex lookup requirements override `get_object()`.
    10. lookup_field = 'pk' ------->默认值为pk
    11. lookup_url_kwarg = None
    12. # The filter backend classes to use for queryset filtering
    13. filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    14. # The style to use for queryset pagination.
    15. pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    16. def get_object(self):
    17. queryset = self.filter_queryset(self.get_queryset())
    18. # Perform the lookup filtering.
    19. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field ---->如果lookup_url_kwarg不是None,而是id作为参数名,如果为None,则取self.lookup_field
    20. assert lookup_url_kwarg in self.kwargs, (
    21. 'Expected view %s to be called with a URL keyword argument '
    22. 'named "%s". Fix your URL conf, or set the `.lookup_field` '
    23. 'attribute on the view correctly.' %
    24. (self.__class__.__name__, lookup_url_kwarg)
    25. )
    26. filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
    27. obj = get_object_or_404(queryset, **filter_kwargs)
    28. # May raise a permission denied
    29. self.check_object_permissions(self.request, obj)
    30. return obj
  • 解决办法:

    • 方法一:设定lookup_url_kwarg=”id”,直接取lookup_url_kwarg
    • 方法二:设定lookup_field=”id”,覆盖源码中的pk

      1. class UserDetailGenericView(GenericAPIView):
      2. """ 详情视图 """
      3. queryset = UserProfile.objects.all()
      4. serializer_class = UserProfileSerializers
      5. # lookup_url_kwarg = 'id'
      6. lookup_field = 'id'
      7. def get(self, request, id):
      8. user = self.get_object()
      9. serializer = self.get_serializer(instance=user)
      10. return Response(serializer.data, status=status.HTTP_200_OK)
      11. def put(self, request, id):
      12. user = self.get_object()
      13. serializer = self.get_serializer(instance=user, data=request.data)
      14. serializer.is_valid(raise_exception=True)
      15. serializer.save()
      16. return Response(serializer.data, status=status.HTTP_201_CREATED)
      17. def delete(self, request, id):
      18. self.get_object().delete()
      19. return Response(status=status.HTTP_204_NO_CONTENT)