学习原因:
关于GenericAPIView,这应该也是一个写接口的东西,我们知道,之前我们一直用APIview来写接口,但是我们会发现,当我们写很多接口的时候,很多代码会重复,说白了,就改个别地方,我来举个例子来帮助理解,我们在学习这种继承类的时候,他会保留原来的功能,增加新的功能,但是这种高集成的类有好处也有坏处。
好处:写代码更加便捷,不会有很多的冗余代码
坏处:你写代码的灵活度更低了,没有那么的灵活多变了
先把代码展示一下.....
class Bookview(GenericAPIView):
queryset = UserInfo.objects.all()
serializer_class=UserinfoSerializers
def get(self,request):
serializers = self.get_serializer(instance=self.get_queryset(), many=True)
return Response(serializers.data)
def post(self, request):
serializers=self.get_serializer(data=request.data)
# 校验数据
if serializers.is_valid():
serializers.save()
return Response(serializers.data)
else:
return Response(serializers.errors)
解释: 首先,我们定义了两个变量,queryset,serializer,一个是获取我们的数据,也就是Queryset对象,然后和序列化器,接着我们看到在get方法的时候,我们通过self.get_serializer(参数) 的形式来获取数据,post方法就不多说了,那我们来了看看他的实现原理 我们进入到GenericApiview
def get_queryset(self):
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
该函数是一个视图类中的方法,用于获取此视图的项目列表。它首先检查类是否包含一个非空的queryset属性,如果包含则返回该属性,否则会调用queryset属性的getter方法来获取queryset。如果queryset是一个QuerySet实例,则重新计算它,以确保在每次请求时都会重新计算。最终返回queryset。这个函数应该被重写而不是直接访问self.queryset,因为self.queryset只会被计算一次,并且结果将被缓存以供后续请求使用
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
该函数返回一个序列化类,作为序列化操作的基准。如果在当前类中定义了serializer_class属性,则返回该属性值;否则,返回None。如果未定义serializer_class属性且未重写get_serializer_class()方法,则抛出异常。
我们要注意,一个是获取示例对象,一个是获取序列化器这个类,两者是不一样的
UserinfoSerializers(instance=self.get_queryset(), many=True)
self.get_serializer(instance=self.get_queryset(), many=True)
self.get_serializerc_class()(instance=self.get_queryset(), many=True)
上面三者是一致的
代码写到这里,那么我们可以发现,只要我们把一开始的queryset变量换一下并且serializer_class这个变量换一下,那么代码的其他地方就不用改了,帮助我们增加开发的效率
接着我们看另外的关于单个查询的代码
class BookDetailView(GenericAPIView):
queryset = UserInfo.objects.all()
serializer_class = UserinfoSerializers
def get(self,request,pk):
# 序列化传参是instance,反序列化是data
serializer=self.get_serializer(instance=self.get_object(),many=False)
return Response(serializer.data)
def put(self,request,pk):
serializers=self.get_serializer(instance=self.get_object(),data=request.data)
if serializers.is_valid():
# 更新逻辑
# UserInfo.objects.filter(id=id).update(**serializers.validated_data)
serializers.save()
return Response(serializers.validated_data)
else:
return Response(serializers.errors)
def delete(self,request,pk):
self.get_object().delete()
return Response("删除成功")
我们这里的第6行用到了self.get_object这个函数,那这个作用是什么呢
def get_object(self):
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
该函数是一个视图类中的方法,用于返回所显示的对象。首先使用filter_queryset方法获取查询集,然后根据URL中的关键字参数进行查找过滤。最后,检查权限并返回对象
我们之前用self.get_queryset他调用的是queryset.all()也就是查询了所有,但是我们这里的单个查询,可以是id=???某个值,我们这相当于就是过滤条件,但是这里他是一个有名传参,我们需要在url中设置变量名,而且传入的时候也要是pk,那么就可以查询到数据了,当然要改也是可以的,因为源码中用到pk是因为lookup_field这个参数是pk,而后面的代码依这两个参数进行查询,所以我们可以改变这个值,来改变我们希望的变量名