03视图基类,视图集,视图扩展类....
1:两个视图基类
1.1:APIView视图类
Django REST framwork 提供的视图的主要作用:
- 控制序列化器的执行(检验、保存、转换数据)
- 控制数据库查询的执行
1.1.1:APIView:继承了原生Django的View
1.1.2:示例
1.1.2.1:models.py
from django.db import models
# Create your models here.
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32, null=True)
price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
publish = models.CharField(max_length=32, null=True)
1.1.2.2:urls.py
from django.urls import path
from learn import views
urlpatterns = [
path('books/', views.Book.as_view()),
path('book/<int:pk>/', views.BookDetail.as_view()),
]
1.1.2.3:views.py
from rest_framework.views import APIView
from . import models
from . import serializer
from . util import APIResponse
# Create your views here.
class Book(APIView):
def get(self, request, *args, **kwargs):
book_list = models.Book.objects.all()
ser = serializer.BookModelSerializer(instance=book_list, many=True)
return APIResponse(ser.data)
def post(self,request,*args,**kwargs):
ser =serializer.BookModelSerializer(data=request.data)
if ser.is_valid():
ser.save()
return APIResponse(ser.data)
else:
return APIResponse(ser.errors,code=100)
class BookDetail(APIView):
def get(self, request,pk, *args, **kwargs):
book_obj = models.Book.objects.get(pk=pk)
ser = serializer.BookModelSerializer(instance=book_obj)
return APIResponse(ser.data)
def put(self,request,pk,*args,**kwargs):
book_obj = models.Book.objects.get(pk=pk)
ser =serializer.BookModelSerializer(instance=book_obj,data=request.data)
if ser.is_valid():
ser.save()
return APIResponse(ser.data)
else:
return APIResponse(ser.errors,code=100)
def delete(self,request,pk,*args,**kwargs):
models.Book.objects.filter(pk=pk).delete()
return APIResponse(msg='删除成功')
1.1.2.3:utils.py
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self, data=None, msg='successful', code=200, status=None
):
dic = {'data': data, 'msg': msg, 'code': code}
super(APIResponse, self).__init__(data=dic, status=status, template_name=None, headers=None,exception=False, content_type=None)
1.1.2.4:serializer
from rest_framework import serializers
from . import models
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
extra_kwargs = {
"id": {'required': False},
"title": {'required': True},
"price": {'required': True},
"publish": {'required': True},
}
1.2:GenericAPIView视图类
1.2.1:GenericAPIView:继承了APIView
- queryset = models.Book.objects.all()
- serializer_class = serializer.BookModelSerializer
- get_queryset:获取配置的queryset
- get_object:路由中的分组字段必须是pk
- get_serializer:获取配置的序列化类
1.2.2:示例
**views.py 其他和示例1.1.2示例差不多
class BookGenericAPIView(GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
def get(self, request, *args, **kwargs):
obj = self.get_queryset()
ser = self.get_serializer(obj, many=True)
return APIResponse(ser.data)
def post(self, request, *args, **kwargs):
ser=self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return APIResponse(ser.data,msg='successful')
class BookDetailGenericAPIView(GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
def get(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(obj)
return APIResponse(ser.data)
def put(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(obj, data=request.data)
if ser.is_valid():
ser.save()
return APIResponse('修改成功')
def delete(self, request, *args, **kwargs):
self.queryset.filter(id=kwargs.get('pk')).delete()
return APIResponse('删除成功')
1.3:总结
-
APIView:如果跟models没有关系(没有数据库相关操作),就继承它
-
GenericAPIView:有关数据库操作,queryset 和serializer_class
2: 五个视图扩展类
2.1:自定义视图扩展类
class ListView():
def list(self,request, *args, **kwargs):
obj = self.get_queryset()
ser = self.get_serializer(obj, many=True)
return Response(ser.data)
class CreateView():
def create(self,request, *args, **kwargs):
ser=self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response('成功')
2.2-1:示例
class BookGenericView(GenericAPIView,CreateView,ListView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
2.2-2示例
class BookDetailGenericAPIView(GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
def get(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(obj)
return Response(ser.data)
def put(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(obj, data=request.data)
if ser.is_valid():
ser.save()
return Response('修改成功')
def delete(self, request, *args, **kwargs):
self.queryset.filter(id=kwargs.get('pk')).delete()
return Response('删除成功')
2.2:扩展视图类(rest_framework.mixins)
2.2.1:五个
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条
2.2.2:扩展视图类源码
from rest_framework import status
from rest_framework.response import Response
from rest_framework.settings import api_settings
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class RetrieveModelMixin:
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class UpdateModelMixin:
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
class DestroyModelMixin:
"""
Destroy a model instance.
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
2.2.3示例
from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
UpdateModelMixin
class BookGenericView(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
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 BookDetailGenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
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)
3:子类视图
3.1九个子类视图(rest_framework.generics)
CreateAPIView:继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条
ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除
3.2示例
class CreateListGenericAPIView(GenericAPIView,CreateModelMixin,ListModelMixin):
def get(self,request,*args,**kwargs):
return self.list(request,*args,**kwargs)
def post(self,request,*args,**kwargs):
return self.create(request,*args,**kwargs)
from rest_framework.generics import CreateAPIView,ListAPIView,ListCreateAPIView
from rest_framework.generics import UpdateAPIView,RetrieveAPIView,DestroyAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView,RetrieveUpdateDestroyAPIView
# class BookGenericView(CreateAPIView):
# class BookGenericView(ListAPIView):
class BookGenericView(ListCreateAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
# class BookDetailGenericAPIView(RetrieveAPIView):
# class BookDetailGenericAPIView(RetrieveAPIView,UpdateAPIView):
class BookDetailGenericAPIView(RetrieveUpdateDestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
4 视图集
4.1:ViewSetMixin
ViewSetMixin:重写了as_view
ViewSet: 继承ViewSetMixin和APIView
GenericViewSet:继承ViewSetMixin, generics.GenericAPIView
ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet
4.2:示例一
urls.py
from django.contrib import admin
from django.urls import path
from learn import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookSetView.as_view(actions={'get':'list','post':"create"})),
path('book/<int:pk>/', views.BookSetView.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),
]
views.py
from rest_framework.viewsets import ModelViewSet
class BookSetView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
4.3:示例二
urls.py
from django.contrib import admin
from django.urls import path
from learn import views
urlpatterns = [
path('book11/', views.BookView.as_view({'get':'lqz'})),
path('book22/', views.BookView.as_view({'get':'egon'})),
]
views.py
# ViewSetMixin:视图类中的方法名,可以随便写,只需要映射对就可以
from rest_framework.viewsets import ViewSetMixin,ViewSet
from rest_framework.response import Response
class BookView(ViewSetMixin,APIView):
# class BookView(ViewSet):
def lqz(self,request,*args,**kwargs):
print(self.action)
return Response('lqz')
def egon(self,request,*args,**kwargs):
return Response('egon')
5 action的使用
# 只要继承了ViewSetMixin类
# 路由配置:path('books_mix/', views.BookView.as_view({'get':'lqz'}))
# 视图类的方法中就会有个action
class BookView(ViewSet):
def lqz(self,request,*args,**kwargs):
print(self.action)
return Response('lqz')
# ViewSetMixin以后只要继承它,路由的配置就发生变化了,只需要写映射即可
7 路由的使用
7.1:自动生成路由
# 自动生成路由
# SimpleRouter
# DefaultRouter
# 继承了ViewSetMixin的视图类,以后写路由,可以自动生成
from rest_framework import routers
# 实例化得到一个对象
router = routers.SimpleRouter()
# 注册进路由
router.register('books', views.BookSetView)
# 把自动生成的路由配置到urlpatterns中
-urlpatterns += router.urls
-re_path(r'v1/', include(router.urls))
7.2:原生路由配置
# 配置路由的方式
-最原始的
-path('books/', views.BookAPIView.as_view()),
-ViewSetMixin的视图类
-path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'}))
-ViewSetMixin的视图类
-自动生成,7.1
7.3:action路由自动配置
#action
-当自动生成路由的时候,由于视图类中还有其它方法,是无法自动生成路由的
-加action装饰器:
-methods:什么请求方式会触发被装饰函数的执行
-detail:是True是基于带id的路由生成的,如果是False,是基于不带id的路由生成的
-@action(methods=['get'], detail=True)
7.3.1示例
urls.py
from learn import views
from rest_framework.routers import SimpleRouter
route = SimpleRouter()
route.register('books',views.BookView,basename='books')
urlpatterns = [
]
urlpatterns += route.urls
views.py
from rest_framework.viewsets import ViewSetMixin, ViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
class BookView(ViewSetMixin, APIView):
@action(methods=['get'],detail=False)
def lqz(self, request, *args, **kwargs):
print(self.action, 11111)
return Response({'name':'lqz'})
@action(methods=['get'],detail=False)
def egon(self, request, *args, **kwargs):
print(self.action)
return Response({'name':'egon'})