1.DRF的视图
1.1APIView与View的区别
咱们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不一样呢~~~
urlpatterns = [
url(r'^book$', BookView.as_view()),
url(r'^book/(?P<id>\d+)$', BookEditView.as_view()),
]
咱们能够看到,无论是View仍是APIView最开始调用的都是as_view()方法~~那咱们走进源码看看~~

咱们能看到,APIView继承了View, 而且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。
那咱们看看View中的as_view()方法作了什么~

咱们看到了~在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法~~可是这里的dispatch方法应该是咱们APIView中的~~

咱们去initialize_request中看下把什么赋值给了request,而且赋值给了self.request, 也就是咱们在视图中用的request.xxx究竟是什么~~

咱们看到,这个方法返回的是Request这个类的实例对象~~咱们注意咱们看下这个Request类中的第一个参数request,是咱们走咱们django的时候的原来的request~

咱们看到了,这个Request类把原来的request赋值给了self._request, 也就是说之后_request是咱们老的request,新的request是咱们这个Request类~~
那咱们继承APIView以后请求来的数据都在哪呢~~

咱们用了rest_framework框架之后,咱们的request是从新封装的Request类~
request.query_params 存放的是咱们get请求的参数
request.data 存放的是咱们全部的数据,包括post请求的以及put,patch请求~~~
相比原来的django的request,咱们如今的request更加精简,清晰了~~~
如今咱们知道了APIView和View的一些区别~~固然还有~~后面咱们还会说~~
咱们写的视图可能对多个表进行增删改查,就致使咱们的视图特别多重复的代码~~
那么咱们尝试着来进行封装一下~~
1.2第一次封装
class BookView(APIView):
def get(self, request):
query_set = Book.objects.all()
book_ser = BookSerializer(query_set, many=True)
return Response(book_ser.data)
def post(self, request):
query_set = request.data
book_ser = BookSerializer(data=query_set)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors)
class BookEditView(APIView):
def get(self, request, id):
query_set = Book.objects.filter(id=id).first()
book_ser = BookSerializer(query_set)
return Response(book_ser.data)
def patch(self, request, id):
query_set = Book.objects.filter(id=id).first()
book_ser = BookSerializer(query_set, data=request.data, partial=True)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors)
def delete(self, request, id):
query_set = Book.objects.filter(id=id).first()
if query_set:
query_set.delete()
return Response("")
else:
return Response("删除的书籍不存在")
# 第一次封装
class GenericAPIView(APIView):
queryset = None
serializer_class = None
def get_queryset(self):
return self.queryset.all()
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
class ListModelMixin(object):
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class CreateModelMixin(object):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.validated_data)
else:
return Response(serializer.errors)
class RetrieveModelMixin(object):
def retrieve(self, request, id, *args, **kwargs):
book_obj = self.get_queryset().filter(pk=id).first()
book_ser = self.get_serializer(book_obj)
return Response(book_ser.data)
class UpdateModelMixin(object):
def update(self, request, id, *args, **kwargs):
book_obj = self.get_queryset().filter(pk=id).first()
book_ser = self.get_serializer(book_obj, data=request.data, partial=True)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors)
class DestroyModelMixin(object):
def destroy(self, request, id, *args, **kwargs):
queryset = self.get_queryset()
try:
queryset.get(pk=id).delete()
return Response("")
except Exception as e:
return Response("信息有误")
# 咱们把公共的部分抽出来 这样无论写多少表的增删改查都变的很简单
# 这样封装后咱们的视图会变成这样
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, id, *args, **kwargs):
return self.retrieve(request, id, *args, **kwargs)
def patch(self, request, id, *args, **kwargs):
return self.update(request, id, *args, **kwargs)
def destroy(self, request, id, *args, **kwargs):
return self.delete(request, id, *args, **kwargs)
咱们封装的GenericAPIView,包括封装每一个方法的类,其实框架都帮咱们封装好了~~
咱们能够直接继承这些类~~来实现上面的视图~~但是还有没有更简单的方法呢~咱们再次封装一下~~
1.3二次封装
# 上面咱们写的继承类太长了~~咱们再改改
class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
pass
class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
pass
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class BookEditView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, id, *args, **kwargs):
return self.retrieve(request, id, *args, **kwargs)
def patch(self, request, id, *args, **kwargs):
return self.update(request, id, *args, **kwargs)
def delete(self, request, id, *args, **kwargs):
return self.delete(request, id, *args, **kwargs)
此次咱们只是让继承变的简单了一点而已,好像并无什么大的进步~~
咱们可不能够把这两个视图合并成一个视图呢~~~框架给咱们提供了一个路由传参的方法~~
咱们看下ViewSetMixin

actions这个默认参数其实就是咱们路由能够进行传参了~~~
下面这个循环~能够看出~咱们要传的参数是一个字段~key应该是咱们的请求方式,value应该对应咱们处理的方法~
这样咱们每一个视图就不用在写函数了~由于已经和内部实现的函数相对应了~
1.4三次封装
#urls.py
urlpatterns = [
# url(r'^book$', BookView.as_view()),
# url(r'^book/(?P<id>\d+)$', BookEditView.as_view()),
url(r'^book$', BookView.as_view({"get": "list", "post": "create"})),
url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
]
from rest_framework.viewsets import ViewSetMixin
# class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
# queryset = Book.objects.all()
# serializer_class = BookSerializer
# 若是咱们再定义一个类
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
pass
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
咱们如今的视图就只要写两行就能够了~~~
其实咱们写的全部的视图~框架都帮咱们封装好了~
注意一点~~
用框架封装的视图~咱们url上的那个关键字参数要用pk~~系统默认的~~
奉献一张图来看下咱们的继承顺序~~~

2.DRF的路由
from django.contrib import admin
from django.urls import path,include
from app.views import BookView
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"book", BookView)
urlpatterns = [
path('admin/', admin.site.urls),
# path(r'book/', BookView.as_view({"get": "list", "post": "create"})),
# path('book/<int:pk>/', BookView.as_view({"get": "list", "put": "update", "delete": "destroy"})),
]
urlpatterns += router.urls
咱们能够看到~~经过框架咱们能够把路由视图都变的很是简单~~
可是须要自定制的时候仍是须要咱们本身用APIView写~~当不须要那么多路由的时候~也不要用这种路由注册~~
3.案例展现
#views.py
from app.models import Book, Publisher
from rest_framework.viewsets import ModelViewSet
from app.serializers import BookSerializer
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
#urls.py
from django.contrib import admin
from django.urls import path,include
from app.views import BookView
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"book", BookView)
urlpatterns = [
path('admin/', admin.site.urls),
# path(r'book/', BookView.as_view({"get": "list", "post": "create"})),
# path('book/<int:pk>/', BookView.as_view({"get": "list", "put": "update", "delete": "destroy"})),
]
urlpatterns += router.urls


#自定制的urls.py
默认的urls配置,暴露了过多的方法,有的时候,咱们不想暴露put或delete,就须要自定制url
from django.contrib import admin
from django.urls import path,include
from app.views import BookView
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
urlpatterns = [
path('admin/', admin.site.urls),
path(r'book/', BookView.as_view({"get": "list", "post": "create"})),
#注意get对应retrive,只获取一条数据
#不但愿有delete,就去掉delete便可。
path('book/<int:pk>/', BookView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

