两个视图基类
APIView
GenericAPIView
# 导入
from rest_framework.generics import GenericAPIView
类GenericView 继承了APIView,
class GenericAPIView(views.APIView):
# 这里面定义了两个参数
queryset = None
serializer_class = None
# 记住3个方法
def get_queryset(self) # 获取所有数据,查询所有需要用到
def get_object(self): # 查询单个对象,需要用到
def get_serializer(self, *args, **kwargs)
...
return serializer_class(*args, **kwargs)# 使用这个方法得到序列化类的对象,可以传selif.get_serializer(instance,data,many)
def get_serializer_class(self)
...
return self.serializer_class
继承了GenericAPIView类的视图层类如下:
class BookGeneric(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
# 查询所有
def get(self,request,*args, **kwargs):
obj_list = self.get_queryset()
ser = self.get_serializer(obj_list, many=True)
return Response(ser.data)
def post(self,request,*args, **kwargs):
pass
class BookDetailGeneric(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
# 修改某一个
def put(self, request, pk):
obj = self.get_object().filter(pk=pk).first()
ser = self.get_serializer(obj, data=request.data)
return Response(ser.data)
def get(self, request, pk):
pass
def delete(self, request,pk):
pass
五个视图扩展类(没有继承其他类)
# 导入5个视图扩展类
# mixins.py
from rest_framework.mixins import CreateModelMixin,ListModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# 查询所有,ListModelMixin,
# 新增 CreateModelMixin,
# 查询单个 RetrieveModelMixin
# 更新某个 UpdateModelMixin
# 删除某个 DestoryModelMixin
继承GenericAPIView类 和视图扩展类的视图类
# 当有了上面5个视图扩展类以后,就可以在我们自己写的视图类中*组合的继承他们,实现不同的接口功能
# 记得这里写了一个小作业,继承GenericAPIView和一个自己写的类,在新建视图类中只配置那两个参数,即可实现5个接口
# 如下,为一个查询所有和新增的方法
class BookGenericList(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
9个视图子类
现在,改写一下上述视图类,编写视图类继承视图子类实现同样的功能,并且实现了代码少量书写;
# 导入视图子类
# rest_framework.generics
from rest_framework.generics import ListAPIView,CreateAPIView,UpdateAPIView,DestroyAPIView,RetrieveAPIView
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView
视图类
# 此时我们只需要在自己写的视图类中继承视图子类ListCreateAPIView,就可以实现对数据的查询所有,和增加一条
class BookListCreate(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
# 删除一条数据
class BookDestory(DestoryAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
视图集
可以看到视图类继承视图子类之后的视图类写法变简洁了,但是可以看见,上面两个视图类除了类名和继承的类不一样,下面的代码主体一样。使用视图集以后,能否将5个接口写在一个视图类中。请看下边
# 导入视图集类
from rest_framework.viewsets import ModelViewSet,GenericViewSet,ViewSetMixin,ReadOnlyModelViewSet,ViewSet
路由
# 使用视图集的视图类的url
path('bookviewset', views.BookViewSet.as_view({'get': 'list', 'post': 'create'})),
path('bookdetailviewset/<int:pk>', views.BookViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
实现5个接口的视图类
# 只继承了一个视图集ModelViewSet类就实现了5个接口的功能
class BookViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
有点绕的东西
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
from rest_framework.generics
class GenericViewSet(ViewSetMixin, GenericAPIView):
pass
# 还是要抓住那个cls,以及cls实例化出来的对象
class ViewSetMixin:
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
"""
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
cls.suffix = None
cls.detail = None
cls.basename = None
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`")
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)
setattr(self, method, handler)
self.request = request
self.args = args
self.kwargs = kwargs
# And continue as usual
return self.dispatch(request, *args, **kwargs)
# 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)
...
drf自动生成路由
# 导自动生成路由的类
from rest_framework.routers import Simplerouter
# 实例化得到对象
router = Simplerouter()
# 注册路由
router.register('路径',对应的自己写的视图类)
# 路由地址的列表
router.urls
# 与路由层的urlpatterns 进行拼接
urlpatterns += router.urls
还有一种写法
from django.urls import path,include
urlpatterns = [
path('', include(router.urls)),
# 也可以拼接路径
path('api/v1/', include(router.urls)),
]