5个视图扩展类
自己写的
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():
print(ser.validated_data)
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})
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})
class DestroyModelMixin:
def destroy(self,request,*args,**kwargs):
self.get_object().delete()
return Response({'code': 100, 'msg': '删除成功'})
from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book
from rest_framework.generics import GenericAPIView
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)
rest_framework.mixins中的
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book
from rest_framework.generics import GenericAPIView
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)
总结
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
1. 5个视图扩展类,不是视图类,必须配合GenericAPIView及其子类使用,不能配合APIView使用
2. 5个视图扩展类,每一个类中只有一个方法,完成5个接口中的其中一个,想写多个接口,就要继承多个
3.5个视图扩展类
1.ListModelMixin:列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
2.CreateModelMixin:创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
3.RetrieveModelMixin:详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
4.UpdateModelMixin:更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
5.DestroyModelMixin:删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
9个视图子类
自己写的
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():
print(ser.validated_data)
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})
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})
class DestroyModelMixin:
def destroy(self,request,*args,**kwargs):
self.get_object().delete()
return Response({'code': 100, 'msg': '删除成功'})
from rest_framework.generics import GenericAPIView
class ListAPIView(ListModelMixin,GenericAPIView):
def get(self,request,*args,**kwargs):
return self.list(request,*args,**kwargs)
class CreateAPIView(CreateModelMixin,GenericAPIView):
def post(self,request,*args,**kwargs):
return self.create(request,*args,**kwargs)
class RetrieveAPIView(RetrieveModelMixin,GenericAPIView):
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
class UpdateAPIView(UpdateModelMixin,GenericAPIView):
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
class DestroyAPIView(DestroyModelMixin,GenericAPIView):
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class ListCreateAPIView(ListModelMixin,CreateModelMixin,GenericAPIView):
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 RetrieveDestroyAPIView(RetrieveModelMixin,DestroyModelMixin,GenericAPIView):
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class RetrieveUpdateAPIView(RetrieveModelMixin,UpdateModelMixin,GenericAPIView):
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
class RetrieveUpdateDestroyAPIView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
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)
from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
class BookDetailView(RetrieveUpdateDestroyAPIView):
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)
rest_framework.generics中的
from rest_framework.generics import ListAPIView,CreateAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView
from rest_framework.generics import ListCreateAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerialzier
class BookDetailView(RetrieveUpdateDestroyAPIView):
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)
总结
from rest_framework.generics import ListAPIView,CreateAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView
from rest_framework.generics import ListCreateAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView
1.CreateAPIView:提供 post 方法
继承自: GenericAPIView、CreateModelMixin
2.ListAPIView:提供 get 方法
继承自:GenericAPIView、ListModelMixin
3.RetrieveAPIView:提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
4.DestoryAPIView:提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
5.UpdateAPIView:提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
6.RetrieveUpdateAPIView:提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
7.RetrieveUpdateDestoryAPIView:提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
8.ListCreateAPIView:提供get、create方法
继承自:GenericAPIView、ListModelMixin,CreateModelMixin
9.RetrieveDestroyAPIView: 提供get、delete方法
继承自:GenericAPIView、RetrieveModelMixin,DestroyModelMixin
视图集
案例
views.py
from rest_framework.viewsets import 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})
urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view({'get':'list','post':'create'})),
path('books/<int:pk>/', BookView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
]
用法
ModelViewSet:from rest_framework.viewsets import ModelViewSet
1.继承ModelViewSet后,只需要在视图类中写两行
queryset = Book.objects.all()
serializer_class = BookSerialzier
2.配置路由,5个接口都有了
path('books/', BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>/', BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
ModelViewSet 源码分析
1.ModelViewSet继承了:mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
ps:GenericViewSet 继承了:ViewSetMixin(重写了as_view),GenericAPIView
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
2.入口:path('books/', BookView.as_view({'get': 'list', 'post': 'create'}))
3.只要继承了ModelViewSet,路由写法变了,谁控制它变的:ViewSetMixin
4.ViewSetMixin如何控制路由写法变了?
BookView.as_viewde的执行,其实是ViewSetMixin的as_view
1.鼠标点进:BookView.as_view({'get': 'list', 'post': 'create'})
# 进入到了ViewSetMixin的as_view()方法
class ViewSetMixin:
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`")
def view(request, *args, **kwargs):
self = cls(**initkwargs) # 是BookView的对象
for method, action in actions.items(): # actions = {'get': 'list', 'post': 'create'}-->method='get' action='list'
handler = getattr(self, action) # 反射,取BookView的对象中反射list
setattr(self, method, handler) # setattr(self, 'get', list方法)
return self.dispatch(request, *args, **kwargs) # APIview的dispatch
return csrf_exempt(view) # 避免了csrf认证
总结
1.只要继承了ViewSetMixin及其子类,路由写法就变了,必须传actions参数
2.变成映射关系了:
path('books/', BookView.as_view({'get': 'list', 'post': 'create'})),
3.以后,只要是books路由匹配成功,如果是get请求,就会执行视图类BookView的list方法
4.以后视图类中的方法名,可以随意命名
eg:
class SmsView(ViewSet):
def ln(self,request):
return Response('hello')
from app01.views import BookView,SmsView
urlpatterns = [
path('ln/', SmsView.as_view({'get': 'ln'})),
]
5 ViewSetMixin,必须配合视图类使用(APIView,GenericAPIView,9个视图子类),必须放在视图类之前
7.ViewSetMixin+APIView=ViewSet:之前继承APIView的,但是现在想路由写法变了(自动生成路由)
8.GenericAPIView+ViewSetMixin=GenericViewSet 之前继承GenericAPIView的,但是现在想路由写法变了(自动生成路由)
9.ReadOnlyModelViewSet:获取所有和获取单条
10.ModelViewSet:5个接口,加路由变了
viewset中的类
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,GenericViewSet,ViewSet,ViewSetMixin
class ViewSet(ViewSetMixin, views.APIView):
pass
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
#只读视图类---> 只有两个,查询所有和查询单条
pass
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
"""
ViewSet --->ViewSetMixin + views.APIView
GenericViewSet --->ViewSetMixin + generics.GenericAPIView
ReadOnlyModelViewSet ---> mixins.RetrieveModelMixin+mixins.ListModelMixin+GenericViewSet
ModelViewSet --->mixins.CreateModelMixin+mixins.RetrieveModelMixin+mixins.UpdateModelMixin+mixins.DestroyModelMixin+mixins.ListModelMixin+GenericViewSet
"""
归纳
1. 两个视图基类
1.APIView
2.GenericAPIView
2. 5个视图扩展类(不是视图类,需要配合GenericAPIView及其子类使用)
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
3. 9个视图子类
from rest_framework.generics import ListAPIView,CreateAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView
from rest_framework.generics import ListCreateAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView
4.视图集:
1.ModelViewSet:5个接口+GenericViewSet
2.ReadOnlyModelViewSet:两个接口(list+retrieve)+GenericViewSet l
3.ViewSetMixin:魔法,不能单独使用,必须配合视图类用,路由写法变了
4.ViewSet:ViewSetMixin+APIView,以后想继承APIView,但是想路由写法变化,视图类中方法可以任意命名
5.GenericViewSet:ViewSetMixin+GenericAPIView,以后想继承GenericAPIView,但是想路由写法变化,视图类中方法可以任意命名
drf之路由
1.路由写法
1.原始写法
2.映射的写法:
path('books/', BookView.as_view({'get': 'list', 'post': 'create'}))
3.自动生成路由
自动生成路由
方法
方式一
from django.contrib import admin
from django.urls import path
from app01.views import BookView
1.第一步:导入一个路由类
from rest_framework.routers import SimpleRouter
2.第二步:实力化得到对象
router = SimpleRouter()
3.第三步:注册路由
# register(self, prefix, viewset, basename=None)
router.register('books',BookView,'books')
4.第四步:加入到路由中
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls
方式二:利用include
from django.contrib import admin
from django.urls import path,include
from app01.views import BookView,SmsView
1.第一步:导入一个路由类
from rest_framework.routers import SimpleRouter
2.第二步:实力化得到对象
router = SimpleRouter()
3.第三步:注册路由
# register(self, prefix, viewset, basename=None)
router.register('books',BookView,'books')
4.第四步:加入到路由中
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/',include(router.urls))
]
api/v1/ ^books/$ [name='books-list']
api/v1/ ^books/(?P<pk>[^/.]+)/$ [name='books-detail']
自动生成路由
1.继承了 5个视图扩展类+ViewSetMixin的视图类,能自动生成路由(get:list,get:retrieve..)
2.我们自己命名的:方法名:login send_sms,需要使用装饰器来做
eg:
# views.py
from rest_framework.decorators import action
class SmsView(ViewSet):
@action(methods=["GET"],detail=False)
def ln(self,request):
return Response('hello')
# urls.py
from django.contrib import admin
from django.urls import path,include
from app01.views import SmsView
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('ln',SmsView,'ln')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/',include(router.urls))
]
"""
admin/
api/v1/ ^ln/ln/$ [name='ln-ln']
"""
eg:
# views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerialzier
@action(methods=['GET'],detail=True)
def login(self,request):
return Response('登陆成功')
# urls.py
from django.contrib import admin
from django.urls import path,include
from app01.views import BookView,SmsView
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books',BookView,'books')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/',include(router.urls))
]
"""
api/v1/ ^books/$ [name='books-list']
api/v1/ ^books/(?P<pk>[^/.]+)/$ [name='books-detail']
api/v1/ ^books/(?P<pk>[^/.]+)/login/$ [name='books-login']
"""
3 action装饰器的参数
action(methods=None, detail=None, url_path=None, url_name=None, **kwargs)
1.methods:请求方式
2.detail:一个True,一个False,用True,表示生成详情的路径 <int:pk>
True,books/1/方法名/
False,books/方法名/
3.url_path:路径名字,需要加上前面的路径一起,如果不加,默认以函数名作为路径名
4.url_name:反向解析使用的名字(用的不多)
4.路由类,有两个,用法完全一致,区别是DefaultRouter生成的路径多
from rest_framework.routers import SimpleRouter,DefaultRouter
1.SimpleRouter :用的最多
2.DefaultRouter
ps:DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
"""
{"books":"http://127.0.0.1:8081/api/v1/books/"}
"""
补充
1.序列化类
1.之前咱么用的
if serializer.is_valid():
校验通过去保存
2.源码中这样用(这个如果是False,直接抛异常)
serializer.is_valid(raise_exception=True)
ps:源码:* 表示只是占位,不接受参数,表示从它往后的参数,都必须用关键字传参
is_valid(self, *, raise_exception=False)
作业
写个login接口,自动生成路由,post请求,携带数据,能够实现登录
# views.py
from rest_framework.decorators import action
from .serializer import UserSerialzer
from .models import User
class UserView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerialzer
@action(methods=['POST'],detail=False)
def login(self,request):
print(request.data) # {'username': 'xiao', 'password': '123'}
res = self.get_queryset().filter(username = request.data.get('username'),password = request.data.get('password')).first()
if not res:
return Response({'code':101,'msg':'用户名或密码错误'})
return Response({'code':100,'msg':'登陆成功'})
# serializer.py
from .models import User
class UserSerialzer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username','password']
extra_kwargs={
'password':{'write_only':True}
}
# urls.py
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('users',UserView,'users')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/',include(router.urls))
]