一、概述
- 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
def get(self, request):# users = self.querysetusers = self.get_queryset()# serializer = self.serializer_classserializer = self.get_serializer(instance=users, many=True)return Response(serializer.data, status=status.HTTP_200_OK)
<a name="N0Mb5"></a>#### (二)、post向数据库中创建一条数据```pythonfrom rest_framework import statusfrom .models import UserProfilefrom .serializers import UserProfileSerializersclass UserListGenericView(GenericAPIView):""" 二级视图列表详情 """queryset = UserProfile.objects.all()serializer_class = UserProfileSerializersdef post(self, request):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)
三、GenericAPIView实现详情视图
- 在方法前边写上queryset,queryset=模型名.objects.all(),注意这里必须是all()
- 在方法中调用的时候需要使用self.get_object()方法,方法内不需要传入任何参数,就可以通过id/pk创建单条数据对象
(一)、获取某一条数据
from rest_framework.generics import GenericAPIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom .models import UserProfilefrom .serializers import UserProfileSerializersclass UserDetailGenericView(GenericAPIView):""" 详情视图 """queryset = UserProfile.objects.all()serializer_class = UserProfileSerializersdef get(self, request, pk):user = self.get_object()serializer = self.get_serializer(instance=user)return Response(serializer.data, status=status.HTTP_200_OK)
(二)、更新某一条数据
from rest_framework.generics import GenericAPIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom .models import UserProfilefrom .serializers import UserProfileSerializersclass UserDetailGenericView(GenericAPIView):""" 详情视图 """queryset = UserProfile.objects.all()serializer_class = UserProfileSerializersdef put(self, request, pk):user = self.get_object()serializer = self.get_serializer(instance=user, data=request.data)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)
(三)、删除某一条数据
from rest_framework.generics import GenericAPIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom .models import UserProfilefrom .serializers import UserProfileSerializersclass UserDetailGenericView(GenericAPIView):""" 详情视图 """queryset = UserProfile.objects.all()serializer_class = UserProfileSerializersdef delete(self, request, pk):self.get_object().delete()return Response(status=status.HTTP_204_NO_CONTENT)
(四)、lookup_filed和lookup_url_kwarg属性
在使用GenericAPIView时,如果通过url传递参数,参数名默认时pk,如果写id会报如下的错误:
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为对应的参数名
####源码分析class GenericAPIView(views.APIView):"""Base class for all other generic views."""queryset = Noneserializer_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' ------->默认值为pklookup_url_kwarg = None# The filter backend classes to use for queryset filteringfilter_backends = api_settings.DEFAULT_FILTER_BACKENDS# The style to use for queryset pagination.pagination_class = api_settings.DEFAULT_PAGINATION_CLASSdef get_object(self):queryset = self.filter_queryset(self.get_queryset())# Perform the lookup filtering.lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field ---->如果lookup_url_kwarg不是None,而是id作为参数名,如果为None,则取self.lookup_fieldassert 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 deniedself.check_object_permissions(self.request, obj)return obj
解决办法:
- 方法一:设定lookup_url_kwarg=”id”,直接取lookup_url_kwarg
方法二:设定lookup_field=”id”,覆盖源码中的pk
class UserDetailGenericView(GenericAPIView):""" 详情视图 """queryset = UserProfile.objects.all()serializer_class = UserProfileSerializers# lookup_url_kwarg = 'id'lookup_field = 'id'def get(self, request, id):user = self.get_object()serializer = self.get_serializer(instance=user)return Response(serializer.data, status=status.HTTP_200_OK)def put(self, request, id):user = self.get_object()serializer = self.get_serializer(instance=user, data=request.data)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)def delete(self, request, id):self.get_object().delete()return Response(status=status.HTTP_204_NO_CONTENT)
