视图组件
写一个出版社的增删查改resful接口
models.py
class Book(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField() category = models.IntegerField(choices=((0, '文学类'), (1, '情感类')), default=1, null=True) publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, null=True) authors = models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() class Publish(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField()
myser.py
from rest_framework import serializers from app01 import models class PublishSerializers(serializers.ModelSerializer): class Meta: model = models.Publish fields = '__all__'
urls.py
url(r'^publish/$', views.Publish.as_view()), url(r'^publish/(?P<pk>\d+)$', views.PublishDetail.as_view()),
一、基本使用
views.py
from rest_framework.views import APIView from app01.myser import PublishSerializers from app01 import models from rest_framework.response import Response class Publish(APIView): def get(self, request): publish_list = models.Publish.objects.all() bs = PublishSerializers(publish_list, many=True) # 序列化数据 return Response(bs.data) def post(self, request): # 添加一条数据 print(request.data) bs = PublishSerializers(data=request.data) if bs.is_valid(): bs.save() # 生成记录 return Response(bs.data) else: return Response(bs.errors) class PublishDetail(APIView): def get(self, request, pk): publish_obj = models.Publish.objects.filter(pk=pk).first() bs = PublishSerializers(publish_obj, many=False) return Response(bs.data) def put(self, request, pk): publish_obj = models.Publish.objects.filter(pk=pk).first() bs = PublishSerializers(data=request.data, instance=publish_obj) if bs.is_valid(): bs.save() # update return Response(bs.data) else: return Response(bs.errors) def delete(self, request, pk): models.Publish.objects.filter(pk=pk).delete() return Response()
二、基于mixins,generics 封装的视图
views.py
# 新增 查找 查取一条 修改 删除 from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin # GenricAPIView:继承自APIView,提供as_view()等,获取当前视图类中queryset和serializer_class , # 用于给ListModelMixin和CreateModelMixin使用。 from rest_framework.generics import GenericAPIView class Publish(CreateModelMixin, ListModelMixin, GenericAPIView): # 指定要序列化的数据 queryset = models.Publish.objects.all() # 这里的all可以不写,会走源码里面的all, 但一般情况下都会写 # 序列化的对象 serializer_class = PublishSerializers 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 PublishDetail(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers 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)
三、使用generics 类下 ListCreateAPIView,RetrieveUpdateDestroyAPIView
views.py
# 查所有、新增 查一条、修改、删除 from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView class Publish(ListCreateAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers class PublishDetail(RetrieveUpdateDestroyAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers
源码分析:
①ListCreateAPIView是继承了CreateModelMixin, ListModelMixin以及GenericAPIView,在里面封装了get所有与post方法
②RetrieveUpdateDestroyAPIView继承了RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin以及
GenericAPIView,在里面封装了get单条、put/patch方法和delete方法
四、使用viewsets :五个接口写在一个类中
urls.py
url(r'^publish/$', views.Publish.as_view({'get':'list','post':'create'})), url(r'^publish/(?P<pk>\d+)/$', views.Publish.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
views.py
from rest_framework.viewsets import ModelViewSet class PublishView(ModelViewSet): queryset=models.Publish.objects.all() serializer_class=PublishSerializers
源码分析:
ModelViewSet继承了增查改删的所有方法
然后点进GenericViewSet里面去看一下这个类的源码
继承了ViewSetMixin与generics.GenericAPIView,然后我们点进去看一下ViewSetMixin
这里面翻译出来:
''这就是魔法。重写`.as_View()`以便它使用执行,将HTTP方法绑定到资源上的操作。例如,要创建绑定“get”和“post”方法的具体视图到“list”和“create”操作…,view=myviewset.as_view('get':'list'、'post':'create')''
然后往下翻发现重写了as_view方法
这里的as_views方法比原来的方法中多了一个actions参数,那么这个actions参数是用来接收哪个值呢?分析一下,我们去写的路由里看一下![](https://img2018.cnblogs.com/blog/1635143/201907/1635143-20190704190152664-1224813470.png)
这个actions就是路由配置的字典{'get': 'list', 'post': 'create'},一旦继承了ViewSetMixin,在路由配置的时候必须把这个字典传过去,如果不传会抛异常
然后继续往下看发现一个view方法,原来有一个view,而这个view是重写的,是最核心的代码,来看一下
这个method与action分别指的是字典里的key与value
把method与action取出来,通过getattr去找list,再通过setattr把值赋给了get,所以当我们执行get请求,源码里面执行的是list方法
所以当我们发不同的请求时,能够执行映射关系相对应的方法。
分析:ViewSetMixin重写了as_view方法
from rest_framework.viewsets import ViewSetMixin from rest_framework.views import APIView # 因为ViewSetMixin里面没有继承APIView,所有要导入 class Publish(ViewSetMixin, APIView): # ViewSetMixin这个类必须要写在APIView的前面 def a(self, request): return Response()
url(r'^a/$', views.Publish.as_view({'get': 'a'}))
请求get会执行a方法