drf之2个视图基类,5个视图扩展类,9个视图子类,视图集,自动生成路由
一、视图之两个视图基类
Generic知识总结:
视图类:
-APIView:之前用过
-GenericAPIView:GenericAPIView继承了APIView
GenericAPIView
-类属性:
queryset:要序列化的所有数据
serializer_class:序列化类
lookup_field = 'pk' :查询单条时的key值
-方法:
-get_queryset():获取所有要序列化的数据【后期可以重写】
-get_serializer : 返回序列化类
-get_object :获取单个对象
总结:以后继承GenericAPIView写接口
1 必须配置类属性
queryset
serializer_class
2 想获取要序列化的所有数据
get_queryset()
3 想使用序列化类:
get_serializer
4 想拿单条
get_object
5.1 使用APIView+序列化类+Response写接口
from rest_framework.views import APIView
from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book
class BookView(APIView):
def get(self,request):
qs = Book.objects.all()
ser = BookSerialzier(qs, many=True)
return Response({'code': 100,
'msg': '成功',
'results': ser.data})
def post(self,request):
ser = BookSerialzier(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100,
'msg': '成功'})
else:
return Response({'code': 100,
'msg': ser.errors})
class BookSerializer(APIView):
def get(self, request, pk):
book = Book.objects.all().get(pk=pk)
ser = BookSerialzier(book)
return Response({'code':100,
'msg': '成功',
'results': ser.data})
def put(self,request, pk):
book = Book.objects.all().get(pk=pk)
ser = BookSerialzier(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100,
'msg': '更新成功'})
else:
return Response({'code': 100,'msg':ser.errors})
使用GenericAPIView+序列化类+Response写接口
# 咱们写的
# class GenericAPIView(APIView):
# query_set=None
# serialzier_class=None
# def get_queryset(self):
# return self.query_set
# def get_serializer(self):
# return self.serialzier_class
# def get_object(self):
# return self.query_set.filter(pk=pk)
人家写的
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
qs = self.get_queryset()
ser = self.get_serializer(qs, many=True)
return Response({'code': 100,
'msg': '成功',
'results': ser.data})
def post(self,request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100,
'msg': '成功'})
else:
return Response({'code': 100,
'msg': ser.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects()
serializer_class = BookSerializer
def get(self, request, pk):
book = self.get_object()
ser = self.get_serializer(book)
return Response({'code': 100,
'msg': '成功',
'results': ser.data})
5.2 使用GenericAPIView+序列化类+Response写接口
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
def get(self, request):
qs = self.get_queryset()
ser = self.get_serializer(qs, many=True)
return Response({'code': 100, 'msg': '成功', 'results': ser.data})
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '成功'})
else:
return Response({'code': 100, 'msg': ser.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
def get(self, request, pk):
book = self.get_object()
ser = self.get_serializer(book)
return Response({'code': 100, 'msg': '成功', 'results': ser.data})
def put(self, request, pk):
book = self.get_object()
ser = self.get_serializer(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '更新成功'})
else:
return Response({'code': 100, 'msg': ser.errors})
二、5个视图扩展类
继承GenericAPIView+5个视图扩展类+序列化类+Response写接口
5个方法:对应
-查询所有 :ListModelMixin--->list方法
-新增一条:CreateModelMixin--->create方法
-查询单条:RetrieveModelMixin--->retrieve方法
-修改一条:UpdateModelMixin--->update方法
-删除一条:DestroyModelMixin--->destroy方法
写5个类(不叫视图类,视图扩展类,需要配合GenericAPIView一起用),每个类有一个方法,以后想写哪个接口,就继承哪个类即可
自己写的
# 需要继承GenericAPIView类
from rest_framework.response import Response
class ListModelMixin:
def list(self, request, *args, **kwargs):
qs = self.get_queryset()
ser = self.get_serializer(qs, many=True)
return Response({'code': 100, 'msg': '成功', 'results': ser.data})
class CreateModelMixin:
def create(self, request, *args, **kwargs):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '成功'})
else:
return Response({'code': 100, 'msg': ser.errors})
class RetrieveModelMixin:
def retrieve(self, request, *args, **kwargs):
book = self.get_object()
ser = self.get_serializer(book)
return Response({'code': 100, 'msg': '成功', 'results': ser.data})
# DestroyModelMixin,UpdateModelMixin
class DestroyModelMixin:
def destroy(self, request, *args, **kwargs):
self.get_object().delete()
return Response({'code': 100, 'msg': '删除成功'})
class UpdateModelMixin:
def update(self, request, *args, **kwargs):
book = self.get_object()
ser = self.get_serializer(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '更新成功'})
else:
return Response({'code': 100, 'msg': ser.errors})
用框架自带的
from .models import Book
from .serializer import BookSerialzier
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \
RetrieveModelMixin
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerialzier
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerialzier
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
5 个视图扩展类--->不是视图类---》必须配合GenericAPIView及其子类使用---》不能配合APIView使用
5个视图扩展类,每一个类中只有一个方法,完成5个接口中的其中一个,想写多个接口,就要继承多个
三、基于视图子类写接口:9个视图子类--->视图类
自己写的
**#### 自己写的---开始######
class ListAPIView(GenericAPIView, ListModelMixin):
def get(self, request):
return self.list(request)
class CreateAPIView(GenericAPIView, CreateModelMixin):
def post(self, request):
return self.create(request)
class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
def post(self, request):
return self.create(request)
def get(self, request):
return self.list(request)
#### 自己写的---结束######
使用框架
from rest_framework.generics import ListAPIView, CreateAPIView, UpdateAPIView, DestroyAPIView, RetrieveAPIView
from rest_framework.generics import ListCreateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView
from rest_framework.generics import RetrieveUpdateAPIView
from rest_framework.generics import RetrieveDestroyAPIView
# from rest_framework.generics import UpdateDestroyAPIView # 这个没有
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
四、终极封装:视图集
ModelViewSet:
-继承它后,只需要在视图类中写两行
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerialzier
继续扩展
def list(self, request, *args, **kwargs):
res = super().list(request, *args, **kwargs)
return Response({'code': 100, 'msg': '成功', 'data': res.data})
def create(self, request, *args, **kwargs):
res = super().create(request, *args, **kwargs)
print('发送邮件。。。')
return Response({'code': 100, 'msg': '新增成功'})
def perform_create(self, serializer):
# 在新增值,加入逻辑
print('发送邮件。。。。')
super(BookView, self).perform_create(serializer)
-配置路由,5个接口都有了
path('books/', BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>/', BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
ModelViewSet 源码分析
-继承了:
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin
GenericViewSet
-ViewSetMixin :没有见过,重写了 as_view
-GenericAPIView
-只要继承了ModelViewSet,路由写法变了,谁控制它变的:ViewSetMixi
ViewSetMixin 如何控制路由写法变了?
-BookView.as_view 是在执行,其实是ViewSetMixin的as_view
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
#我们传入的 actions={'get': 'list', 'post': 'create'}
def view(request, *args, **kwargs):
self = cls(**initkwargs)
for method, action in actions.items():
# method:get
# action:list
# 通过反射,self是BookView的对象,取BookView对象中反射list
handler = getattr(self, action)
# 通过反射:setattr(BookView的对象,'get',list方法)
setattr(self, method, handler)
# APIViwe的dispatch
return self.dispatch(request, *args, **kwargs)
return csrf_exempt(view)
总结:
'''
1 只要继承了ViewSetMixin及其子类,路由写法就变了,必须传actions参数
2 变成映射关系了:
path('books/', BookView.as_view({'get': 'list', 'post': 'create'})),
3 以后,只要是books路由匹配成功,的get请求,就会执行视图类BookView的list方法
4 以后视图类中的方法名,可以随意命名
5 这个类,必须配合视图类使用(APIView,GenericAPIView,9个视图子类),必须放在视图类之前
'''
大总结
-
2个视图基类
-APIView
-GenericAPIView -
5个视图扩展类(不是视图类,需要配合GenericAPIView及其子类使用)
-
9个视图子类
-
视图集:
ModelViewSet:5个接口的
ReadOnlyModelViewSet:两个接口,list和retrieve
ViewSetMixin:魔法,不能单独使用,必须配合视图类用,路由写法变了
ViewSet:ViewSetMixin+APIView,以后想继承APIView,但是想路由写法变化,视图类中方法可以任意命名
GenericViewSet:ViewSetMixin+GenericAPIView,以后想继承GenericAPIView,但是想路由写法变化,视图类中方法可以任意命名
ReadOnlyModelViewSet,ViewSet,GenericViewSet
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSetMixin,ViewSet,GenericViewSet
from rest_framework.views import APIView
# ViewSetMixin+APIView=ViewSet
# ViewSetMixin+GenericAPIView=GenericViewSet
# ReadOnlyModelViewSet:只读视图类---》只有两个,查询所有和查询单台哦
class SmsView(ViewSet):
def lqz(self, request):
return Response('你好')
五、drf之路由
路由写法有多种
-原始写法
-映射的写法:path('books/', BookView.as_view({'get': 'list', 'post': 'create'}))
-自动生成路由
自动生成路由
-必须要继承ViewSetMixin及其子类的视图类,才能用
-继承了 5个视图扩展类+ViewSetMixin的视图类,能自动生成路由
-跟咱们写的这个是一样的
-path('books/', BookView.as_view({'get': 'list', 'post': 'create'})),
-path('books/<int:pk>/', BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
-自己写的视图类的方法,如何映射
-映射的方式我们会
-自动生成的方式
自动生成路由
1 继承了 5个视图扩展类+ViewSetMixin的视图类,能自动生成路由(get:list,get:retrieve..)
2 我们自己命名的: 方法名:login send_sms,需要使用装饰器来做
# 视图类:
class SMSView(ViewSet):
@action(methods=['GET'], detail=False, url_path='lqz', url_name='lqz')
def lqz(self, request):
# 路由
router.register('lqz',SMSView,'lqz')
# 路径是:http://127.0.0.1:8000/api/v1/lqz/lqz/
3 action装饰器的参数
methods:请求方式
detail:一个True,一个False,用True,表示生成详情的路径 <int:pk>
# True,books/1/方法名/
# False,books/方法名/
url_path:路径名字,需要加上前面的路径一起,如果不加,默认以函数名作为路径名
url_name:反向解析使用的名字(用的不多)
路由类,有两个,用法完全一致,区别是DefaultRouter生成的路径多
SimpleRouter :用的最多
DefaultRouter
# DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
视图层代码
# 自动生成路由
from rest_framework.viewsets import ModelViewSet, ViewSet, ViewSetMixin
from rest_framework.views import APIView
# 使用装饰器---》做映射
from rest_framework.decorators import action
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerialzier
@action(methods=['GET'], detail=False)
def login(self,request):
# print(pk)
return Response('登录成功')
# 参数:methods=None, detail=None, url_path=None, url_name=None
# class SMSView(ViewSetMixin,APIView): 前面两个相加等于Viewset
class SMSView(ViewSet):
@action(methods=['GET'], detail=True, url_name='lqz')
def lqz(self, request):
return Response('你好')
路由层代码
from django.contrib import admin
from django.urls import path, include
# from app01.views import BookView
# from app01.views import BookView, BookDetailView
from app01.views import BookView, SMSView
# 第一步:导入一个路由类
from rest_framework.routers import SimpleRouter,DefaultRouter
# 第二步:实例化得到对象
router = DefaultRouter()
# 第三步:注册路由(视图类)
router.register('books', BookView, 'books')
# router.register('publish',PublishView,'publish')
# http://127.0.0.1:8000/api/v1/lqz//lqz/
router.register('lqz',SMSView,'lqz')
# 第四步:加入到中路由中
# 4,1 方式一
# urlpatterns+=router.urls
# 4.2 使用include
path('api/v1/', include(router.urls)),
urlpatterns = [
path('admin/', admin.site.urls),
# path('lqz/', SmsView.as_view({'get':'lqz'})),
path('api/v1/', include(router.urls)),
# path('lqz/', SMSView.as_view({'get': 'lqz'})), # 我们都会,使用自动生成,如何做
]
思维导图and笼统记忆
APIView:
这是DRF中最基础的视图类,提供了处理HTTP请求的基本功能。开发者需要继承该类,并在子类中实现相应的HTTP方法(如get()、post()、put()等)来处理请求。
GenericAPIView:
这是一个更高级的通用视图类,结合了APIView和mixins模块的功能。GenericAPIView提供了一些通用的方法和属性,例如get_object()、get_queryset()等,用于简化开发过程。
ViewSet:
这是DRF中更高级的视图类,结合了GenericAPIView和mixins模块的功能,并提供了更多的功能和灵活性。ViewSet可以处理常见的CRUD操作,包括list()、create()、retrieve()、update()和destroy()等,通过路由器进行注册和映射。
ModelViewSet:
这是一个特殊的ViewSet,专门用于处理与数据库模型相关的操作。ModelViewSet结合了GenericAPIView和ModelMixin的功能,提供了一套完整的CRUD操作,包括列表、创建、检索、更新和删除等。