四、drf视图组件
drf视图组件
一、基于APIView
-
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32)
-
ser.py(自定义序列化文件)
from app01 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
-
view.py
from app01 import models from app01.ser import BookSerializer from rest_framework.views import APIView from rest_framework.response import Response # 自定义一个Response对象 class MyResponse(): def __init__(self): self.status = '1000' self.msg = '成功' @property def get_dict(self): return self.__dict__ class BookView1(APIView): # 查询一条数据 def get(self,request,pk): response_msg = MyResponse() book_obj = models.Book.objects.filter(id=pk).first() book_ser = BookSerializer(instance=book_obj) response_msg.data = book_ser.data return Response(response_msg.get_dict) # 删除一条数据 def delete(self,request,pk): response_msg = MyResponse() models.Book.objects.filter(pk=pk).delete() response_msg.msg = '删除成功' return Response(response_msg.get_dict) # 修改一条数据 def put(self,request,pk): response_msg = MyResponse() book_obj = models.Book.objects.filter(pk=pk).first() book_ser = BookSerializer(instance=book_obj,data=request.data) if book_ser.is_valid(): book_ser.save() response_msg.data = book_ser.data else: response_msg.status = '1001' response_msg.msg = '校验失败,请稍后再试' response_msg.data = book_ser.errors return Response(response_msg.get_dict) class BooksView1(APIView): # 查询所有数据 def get(self,request): response_msg = MyResponse() books_obj = models.Book.objects.all() books_ser = BookSerializer(instance=books_obj,many=True) response_msg.data = books_ser.data return Response(response_msg.get_dict) # 新增一条数据 def post(self,request): response_msg = MyResponse() book_ser = BookSerializer(data=request.data) if book_ser.is_valid(): book_ser.save() response_msg.msg = '新增成功' response_msg.data = book_ser.data else: response_msg.status = '1001' response_msg.msg = '新增失败,情稍后再试' response_msg.data = book_ser.errors return Response(response_msg.get_dict)
-
urls.py
url(r'^book1/(?P<pk>\d+)', views.BookView1.as_view()), url(r'^books1/', views.BooksView1.as_view()),
-
总结
1. 继承关系: APIView继承View 2. APIView基于View的拓展: APIView重写了View的dispatch方法, 在该方法中实现了实现了一下功能: (1) 对来的原生请求对象request进行了封装. (2) 提供了对包装过后的请求对象的三段认证: 认证, 权限控制, 频率控制 (3) 重写了View中通过本次请求的方式动态的反射到自定义继承APIView类实例化的对象中定义的请求方法 (4) 使用异常处理处理2,3步骤中的异常 (5) 处理完毕异常以后使用drf的response对象对请求响应 3. 针对路由配置 路由中的有名分组必须指定pk, 视图中使用必须使用相同的关键字参数接受
二、基于GenericView
-
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32)
-
ser.py(自定义序列化文件)
# 最好使用ModelSerializer类,不用重写update和create方法 from app01 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
-
view.py
from rest_framework.generics import GenericAPIView class BookGenericView2(GenericAPIView): # queryset要传queryset对象,查询了所有的图书 # serializer_class使用哪个序列化类来序列化这堆数据 queryset = models.Book.objects serializer_class = BookSerializer # queryset=models.Book.objects.all() # 查询一条数据 def get(self,request,pk): response_msg = MyResponse() book_obj = self.get_object() book_ser = self.get_serializer(book_obj) response_msg.data = book_ser.data return Response(response_msg.get_dict) # 删除一条数据 def delete(self,request,pk): response_msg = MyResponse() self.get_object().delete() response_msg.msg = '删除成功' return Response(response_msg.get_dict) # 修改一条数据 def put(self,request,pk): response_msg = MyResponse() book_obj = self.get_object() book_ser = self.get_serializer(book_obj,request.data) if book_ser.is_valid(): book_ser.save() response_msg.data = book_ser.data else: response_msg.status = '1001' response_msg.msg = '校验失败,请稍后再试' response_msg.data = book_ser.errors return Response(response_msg.get_dict) class BooksGenericView2(GenericAPIView): # queryset要传queryset对象,查询了所有的图书 # serializer_class使用哪个序列化类来序列化这堆数据 queryset = models.Book.objects serializer_class = BookSerializer # queryset=models.Book.objects.all() # 查询所有数据 def get(self,request): response_msg = MyResponse() books_obj = self.get_queryset() books_ser = self.get_serializer(books_obj,many=True) response_msg.data = books_ser.data return Response(response_msg.get_dict) # 新增一条数据 def post(self,request): response_msg = MyResponse() book_ser = self.get_serializer(data=request.data) if book_ser.is_valid(): book_ser.save() response_msg.msg = '新增成功' response_msg.data = book_ser.data else: response_msg.status = '1001' response_msg.msg = '新增失败,情稍后再试' response_msg.data = book_ser.errors return Response(response_msg.get_dict)
-
urls.py
url(r'^bookG2/(?P<pk>\d+)',views.BookGenericView2.as_view()), url(r'^bookGs2/',views.BooksGenericView2.as_view()),
-
总结
1.GenericAPIView继承自APIView,它在APIView的功能上增加了两个功能: - 通用的模型类(传入需要序列化的模型数据) queryset = None; - 通用的序列化器(传入对应的序列化器对象) serializer_class = None - 通用的有名分组名 lookup_field = 'pk':好像不能改 lookup_url_kwarg = None:可以改,改成自己的有名分组名即可 2.三个常用方法 - get_queryset() # 获取queryset对象,用于查询多条数据 - get_object() # 获取一条对象数据 - get_serializer(*args, **kwargs) # 获取序列化器对象,该传什么参数就传什么参数 4.在写视图类时,模型表必须是queryset对象(加上objects),即queryset = Book.objects 5.
三、基于GenericView+5个视图拓展类
-
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32)
-
ser.py(自定义序列化文件)
# 最好使用ModelSerializer类,不用重写update和create方法 from app01 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
-
view.py
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin class BookGenericView3(GenericAPIView,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin): """ UpdateModelMixin:修改 DestroyModelMixin:删除 RetrieveModelMixin:查询一条数据 """ # queryset要传queryset对象,查询了所有的图书 # serializer_class使用哪个序列化类来序列化这堆数据 queryset = models.Book.objects serializer_class = BookSerializer # 查询一条数据 def get(self,request,pk): return self.retrieve(request,pk) # 删除一条数据 def delete(self,request,pk): return self.destroy(request,pk) # 修改一条数据 def put(self,request,pk): return self.update(request,pk) class BooksGenericView3(GenericAPIView,ListModelMixin,CreateModelMixin): """ ListModelMixin:查询所有 CreateModelMixin:创建一条数据 """ # queryset要传queryset对象,查询了所有的图书 # serializer_class使用哪个序列化类来序列化这堆数据 queryset = models.Book.objects serializer_class = BookSerializer # queryset=models.Book.objects.all() # 查询所有数据 def get(self,request): return self.list(request) # 新增一条数据 def post(self,request): return self.create(request)
-
urls.py
url(r'^bookG3/(?P<pk>\d+)',views.BookGenericView3.as_view()), url(r'^bookGs3/',views.BooksGenericView3.as_view()),
-
总结
1.使用GenericAPIView写不同类的接口,只是queryset参数和serializer_class参数的不同,其他的方法几乎完全一样 2.这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。 3.DestroyModelMixin、RetrieveModelMixin、UpdateModelMixin的路由中,必须使用pk # ListModelMixin 内部封装了list方法, 实现了查询所有数据 提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。 该Mixin的list方法会对数据进行过滤和分页。 # CreateModelMixin 内部封装了create方法, 实现了新增一条数据 提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。 如果序列化器对前端发送的数据验证失败,返回400错误。 # RetrieveModelMixin 内部封装了retrieve方法, 实现了查询一条数据 提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。 如果存在,返回200, 否则返回404。 # UpdateModelMixin 内部封装了update方法, 实现了更新一条数据 提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。 同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。 成功返回200,序列化器校验数据失败时,返回400错误。 # DestroyModelMixin 内部封装了destroy方法,实现了删除一条数据 提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。 成功返回204,不存在返回404。 4.在写视图类时,模型表必须是queryset对象(加上objects),即queryset = Book.objects
四、基于GenericView+九个拓展类
-
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32)
-
ser.py(自定义序列化文件)
# 最好使用ModelSerializer类,不用重写update和create方法 from app01 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
-
view.py
from rest_framework.generics import GenericAPIView, CreateAPIView, DestroyAPIView, UpdateAPIView, ListAPIView, RetrieveAPIView, ListCreateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView # 创建一个数据 class BookCreateAPIView(CreateAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 删除一个数据 class BookDestroyAPIView(DestroyAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 修改一个数据 class BookUpdateAPIView(UpdateAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 获取所有数据 class BookListAPIView(ListAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 获取一个数据 class BookRetrieveAPIView(RetrieveAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 获取所有数据和创造一个数据 class BookListCreateAPIView(ListCreateAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 获取一个数据和删除一个数据 class BookRetrieveDestroyAPIView(RetrieveDestroyAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 获取一个数据和修改一个数据 class BookRetrieveUpdateAPIView(RetrieveUpdateAPIView): queryset = Book.objects serializer_class = BookModelSerializer # 获取一个数据和修改一个数据和删除一个数据 class BookRetrieveUpdateDestroyAPIView(RetrieveUpdateDestroyAPIView): queryset = Book.objects serializer_class = BookModelSerializer
-
urls.py
url(r'^books/$', views.BookModelViewSet.as_view(), url(r'^books/(?P<pk>\d+)',views.BookModelViewSet.as_view(),
-
总结
1.不需要指定路由的actions参数,因为根本就没有 2.在写视图类时,模型表必须是queryset对象(加上objects),即queryset = Book.objects
五、基于ModelViewSet
-
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32)
-
ser.py(自定义序列化文件)
# 最好使用ModelSerializer类,不用重写update和create方法 from app01 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
-
view.py
from rest_framework.viewsets import ModelViewSet class BookGenericView4(ModelViewSet): """ 5个接口都有,但是路由有点问题 问?怎么区别那种请求触发该请求方式的方法 需要在路由中添加一个参数:actions={'get':'list','post':'create','get':'retrieve','delete':'destroy','put':'update'} """ queryset = models.Book.objects serializer_class = BookSerializer
-
urls.py
url(r'^bookG4/(?P<pk>\d+)', views.BookGenericView4.as_view(actions={'delete':'destroy','get':'retrieve','put':'update'})), # 这个路由中有删除一个、查询一个、修改一个的请求 url(r'^bookGs4/', views.BookGenericView4.as_view(actions={'get':'list','post':'create'})), # 这个路由中有查询所有、增添一个的请求
-
总结
1.路由处的as_view()中必须传一个action参数(字典),格式:action={'get':'list','post':'creat'} 2.在写视图类时,模型表必须是queryset对象(加上objects),即queryset = Book.objects
六、继承ViewSetMixin
-
models.py
from django.db import models class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32)
-
ser.py(自定义序列化文件)
# 最好使用ModelSerializer类,不用重写update和create方法 from app01 import models from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
-
view.py
from rest_framework.viewsets import ViewSetMixin class BookGenericView5(ViewSetMixin,GenericAPIView): queryset = models.Book.objects serializer_class = BookSerializer # 查询一条数据 def get_one_data(self,request,pk): response_msg = MyResponse() book_obj = self.get_object() book_ser = self.get_serializer(book_obj) response_msg.data = book_ser.data return Response(response_msg.get_dict) # 删除一条数据 def delete_one_data(self,request,pk): response_msg = MyResponse() self.get_object().delete() response_msg.msg = '删除成功' return Response(response_msg.get_dict) # 修改一条数据 def put_one_data(self,request,pk): response_msg = MyResponse() book_obj = self.get_object() book_ser = self.get_serializer(book_obj,request.data) if book_ser.is_valid(): book_ser.save() response_msg.data = book_ser.data else: response_msg.status = '1001' response_msg.msg = '校验失败,请稍后再试' response_msg.data = book_ser.errors return Response(response_msg.get_dict) class BooksGenericView5(ViewSetMixin,GenericAPIView): queryset = models.Book.objects serializer_class = BookSerializer # 查询所有数据 def get_all_data(self,request): response_msg = MyResponse() books_obj = self.get_queryset() books_ser = self.get_serializer(books_obj,many=True) response_msg.data = books_ser.data return Response(response_msg.get_dict) # 新增一条数据 def post_one_data(self,request): response_msg = MyResponse() book_ser = self.get_serializer(data=request.data) if book_ser.is_valid(): book_ser.save() response_msg.msg = '新增成功' response_msg.data = book_ser.data else: response_msg.status = '1001' response_msg.msg = '新增失败,情稍后再试' response_msg.data = book_ser.errors return Response(response_msg.get_dict)
-
urls.py
url(r'^bookG5/(?P<pk>\d+)', views.BookGenericView5.as_view(actions={'delete':'delete_one_data','get':'get_one_data','put':'put_one_data'})), # 这个路由中有删除一个、查询一个、修改一个的请求 url(r'^bookGs5/', views.BooksGenericView5.as_view(actions={'get':'get_all_data','post':'post_one_data'})), # 这个路由中有查询所有、增添一个的请求
-
总结
1.ViewSetMixin类一定要放在GenericAPIView类前面 2.ViewSetMixin类可以与APIView类使用,请求函数和使用APIView类时一样,只不过可以自定义自己的请求方式名 def get_all_data(,self,request): pass 3.自定义自己的请求方式函数时,需要在路由的as_view()中的action中设置好映射关系 url(r'^index/',view.Data.as_view(action={'get':'get_all_data'})) 4.在写视图类时,模型表必须是queryset对象(加上objects),即queryset = Book.objects