Python 学习笔记(十八)--Django REST Framework之GenericAPIView
Django REST framwork 提供的视图主要作用:
- 控制序列化器的执行(检验、保存、转换数据)
- 控制数据库模型的操作
Django REST framwork 提供了众多的通用视图基类与扩展类,以简化视图的编写。
1.基类
views.APIView 与 GenericsAPIView,后者继承前者。
class GenericAPIView(views.APIView): """ Base class for all other generic views. """
2.GenericAPIView的属性和方法
通用视图类主要作用就是把视图中的独特的代码抽取出来,让视图方法中的代码更加通用,方便把通用代码进行简写。
3. GenericAPIView 的属性queryset
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
在开发者编写的视图类中,可以直接为queryset 赋值。
例如:
queryset = XXX.objects.all() ---XXX代表某个model
serializer_class = XXXXX, --表示使用那个序列化类 来序列化 指定的数据。
4. GenericAPIView 的方法get_queryset
返回视图使用的查询集,主要用来提供给Minxin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回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.GenericAPIView 的方法get_serializer
对象集即多行数据时,需要传入参数many=True
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果在视图中想要获取序列化器对象,也可以直接调用此方法。
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)
子方法get_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
6.GenericAPIView 的方法get_object
返回详情视图所需的模型类数据对象,主要用来提供给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()) ###从这个代码可以看出,是对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
7.5个视图扩展类
from rest_framework.mixins importListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
作用
""" Basic building blocks for generic class based views. We don't bind behaviour to http method handlers yet, which allows mixin classes to be composed in interesting ways. """
8.GenericAPIView的视图子类
rest_framework的mixins 的子类 和 GenericAPIView 结合,创造了9个GenericAPIView的视图子类。
9.视图子类ListAPIView
class ListAPIView(mixins.ListModelMixin, GenericAPIView): """ Concrete view for listing a queryset. """ def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)
10. 继承多个子类,方法大集合
from rest_framework.viewsets import ModelViewSet
源码
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass
需要留意的是 ModelViewSet 继承的是GenericViewSet
class GenericViewSet(ViewSetMixin, generics.GenericAPIView): """ The GenericViewSet class does not provide any actions by default, but does include the base set of generic view behavior, such as the `get_object` and `get_queryset` methods. """ pass
还继承了ViewSetMixin
11. ViewSetMixin
class ViewSetMixin: """ This is the magic. Overrides `.as_view()` so that it takes an `actions` keyword that performs the binding of HTTP methods to actions on the Resource. For example, to create a concrete view binding the 'GET' and 'POST' methods to the 'list' and 'create' actions... view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) """
需要特比注意的是,类重写了as_view方法,【当调用时,actions参数必须赋值,否则报错。例如as_view({'get':'list','post':'create'}) 】
actions 对应的参数为字典类型。
即路由中(url)需要配置对应关系,例如{'get':'list'},表示当get请求到来,就会执行list方法。
@classonlymethod def as_view(cls, actions=None, **initkwargs): ##传入的参数与APIView的都不一样 """ Because of the way class based views create a closure around the instantiated view, we need to totally reimplement `.as_view`, and slightly modify the view function that is created and returned. """ # The name and description initkwargs may be explicitly overridden for # certain route configurations. eg, names of extra actions. cls.name = None cls.description = None # The suffix initkwarg is reserved for displaying the viewset type. # This initkwarg should have no effect if the name is provided. # eg. 'List' or 'Instance'. cls.suffix = None # The detail initkwarg is reserved for introspecting the viewset type. cls.detail = None # Setting a basename allows a view to reverse its action urls. This # value is provided by the router through the initkwargs. cls.basename = None # actions must not be empty if not actions: raise TypeError("The `actions` argument must be provided when " "calling `.as_view()` on a ViewSet. For example " "`.as_view({'get': 'list'})`") # sanitize keyword arguments for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r" % ( cls.__name__, key)) # name and suffix are mutually exclusive if 'name' in initkwargs and 'suffix' in initkwargs: raise TypeError("%s() received both `name` and `suffix`, which are " "mutually exclusive arguments." % (cls.__name__)) def view(request, *args, **kwargs): self = cls(**initkwargs) if 'get' in actions and 'head' not in actions: actions['head'] = actions['get'] # We also store the mapping of request methods to actions, # so that we can later set the action attribute. # eg. `self.action = 'list'` on an incoming GET request. self.action_map = actions # Bind methods to actions # This is the bit that's different to a standard view for method, action in actions.items(): handler = getattr(self, action) ##handler 就变成了action变量对应的内存地址了 setattr(self, method, handler) ##通过反射,handler 赋值给self.method ##经过上面的for循环,对象有了对象.get(对应的list)\对象.post(对应的create) ....这类方法。
self.request = request self.args = args self.kwargs = kwargs # And continue as usual return self.dispatch(request, *args, **kwargs) # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) # We need to set these on the view function, so that breadcrumb # generation can pick out these bits of information from a # resolved URL. view.cls = cls view.initkwargs = initkwargs view.actions = actions return csrf_exempt(view)
12 drf 默认配置文件查找顺序
(1)先从本视图类中查找;
(2)项目的setting配置文件中查找;
(3)drf默认的文件中查找(.../lib/site-packages/django/conf/global_settings.py)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库