django 3.2.13
在进行下面的操作之前切记在setting.py里面注册rest_framework
一、视图
重点:请先认真读完下面的内容再进行深入学习,或者先跳过当有不懂的时候,回头再看看下面的话
视图包括下面一会介绍的视图集知识点,都是由繁琐到简单,最后只需几行就可实现复杂功能(此类功能大多为死板的增删改查,不够灵活),重点就在互相之间的继承,通过前面学习繁琐的代码就能逐步知其然知其所以然,并且利于自己实现特别的需求
RESTful接口规范:为什么要先说这个呢?因为Django REST基于RESTful接口规范来实现的功能。RESTful接口规范指出,要根据不同的需求对应不同的请求方式,比如查询使用GET,删除使用DELETE,增加使用POST。
固定模式(Django rest也会用到):
GET 127.0.0.1/products :将返回所有产品清单
GET 127.0.0.1/products/4 :将获取产品 pk值=4
POST 127.0.0.1/products :将产品新建到集合
PUT 127.0.0.1/products/4 :将更新产品 pk值=4
DELETE 127.0.0.1/products/4 :将删除 pk值=4的产品
特别的需求:
PUT 127.0.0.1/products/4/news :这个与上面不同就是4后面加了个news,这个news就属于自己定义的,其意思可以为将 pk值为4的商品的某项功能更新(与上面不同就是这里"更新"属于自己特殊需求写的代码)pycharm debug:为了方便了解继承关系
1.APIView
Request与HttpRequeset区别:Request的request.data属性即可获取表单类型数据或者JSON数据,无需HttpRequeset这么麻烦;Request的request.query_params等同于HttpRequeset里面的request.GET
注意:使用APIView与SessionAuthentication会产生csrf的问题,为了解决此问题,注释掉'django.middleware.csrf.CsrfViewMiddleware',
没有效果,需要写入下面的代码
from rest_framework.authentication import SessionAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return
class MyView(APIView):
authentication_classes = (CsrfExemptSessionAuthentication,)
导入:from rest_framework.views import APIView
介绍:APIView是REST framework提供的所有视图的基类,故其并不常用,了解它的用法便于对后面内容的理解,继承自Django的View父类,其大体与View用法一样,但有些不同下面马上会介绍。
不同:
- 传入到视图方法中的是REST framework封装好的Request对象,而不是Django的HttpRequeset对象(前言里面介绍了他们的一点区别)
- 视图方法可以返回REST framework的Response对象,不使用之前文章的类似HttpResponse等,直接用一个Response对象就能适合的返回前端需要的数据
- 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
关系图谱:
urls.py
urlpatterns = [
path("teacher", views.TestAPIView.as_view())
]
views.py
from rest_framework.views import APIView
from .models import Student, Teacher
from .serializers import StudentSerializer
from rest_framework.response import Response
class TestAPIView(APIView):
# get请求会这个
def get(self, request):
data = Student.objects.all()
serializer = StudentSerializer(instance=data, many=True)
return Response(serializer.data)
2.GenericAPIView
导入:from rest_framework.generics import GenericAPIView
介绍:继承自APIVIew,其与APIVIew一样属于基础类,并不常用,常常配合下面的扩展使用,增加了对于列表视图(就是获取表单全部数据)和详情视图(表单具体数据)可能用到的通用支持方法。通常使用时,可搭配一个或多个Mixin扩展类
关系图谱:
代码分析:
- 获取全部
path("teachers", views.TestGenericAPIView.as_view())
class TestGenericAPIView(GenericAPIView):
queryset = Student.objects.all()
'''
GenericAPIView里面设置了queryset ,
其会在GenericAPIView的get_queryset()函数里面调用
'''
serializer_class = StudentSerializer
'''
GenericAPIView里面设置了serializer_class ,
其会在GenericAPIView的get_queryset()函数里面调用
'''
def get(self, request):
book = self.get_queryset()
'''
get_queryset属于父类GenericAPIView里面的函数
其用法比较简单,含义≈data = Student.objects.all()
注意重点起到校验检查的作用
'''
serializer = self.get_serializer(book, many=True)
'''
get_serializer属于父类GenericAPIView里面的函数
其主要是为serializer添加了一个context属性request、format、view
这三个数据对象可以在定义序列化器时使用
效果≈serializer = StudentSerializer(instance=data, many=True,context=)
'''
return Response(serializer.data)
- 获取单个
path("teachers/<pk>", views.TestGenericAPIView.as_view()) #pk表示主键如果其它字段设置可名就可以
class TestGenericAPIView(GenericAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
def get(self, request, pk):
book = self.get_object()
'''
注意:get(self, request, pk)中参数pk是必填的必须这样写的,其在GenericAPIView被写死
get_object()起初通过源码"queryset = self.filter_queryset(self.get_queryset())",
获取验证并获取A=Student.objects.all()对象,但不要以为它向服务器发送获取全部数据的请求,
因为下面"obj = get_object_or_404(queryset, **filter_kwargs)"会发送类似A.get(id=pk)
的请求(A是Student.objects.all()),django会发送最终的请求(即不用不发)
'''
serializer = self.get_serializer(book)
return Response(serializer.data)
二、扩展类
这几个扩展类都是基于GenericAPIView的扩展
关系图谱:
1. ListModelMixin
导入:from rest_framework.mixins import ListModelMixin
介绍:属于获取全部的简写,其依赖于继承GenericAPIView(必须与其一起被其它程序继承),其属于是一个整合,没有实际的基础代码。
代码分析:
path("teachers", views.TestGenericAPIView.as_view())
class TestGenericAPIView(ListModelMixin,GenericAPIView):
queryset = Teacher.objects.all()
serializer_class = TeacherSerializer
def get(self, request):
return self.list(request)
# ListModelMixin里面的一个函数叫做list(),其实现功能与我刚刚上面才单继承GenericAPIView写的大同小异
2. RetrieveModelMixin
导入:from rest_framework.mixins import RetrieveModelMixin
介绍:属于获取单个的简写,其属于是一个整合
代码:
path("teachers/<pk>", views.TestGenericAPIView.as_view()) #pk表示主键如果其它字段设置可名就可以
class TestGenericAPIView(RetrieveModelMixin, GenericAPIView):
queryset = Teacher.objects.all()
serializer_class = TeacherSerializer
def get(self, request, pk):
return self.retrieve(request)
3. CreateModelMixin
导入:from rest_framework.mixins import CreateModelMixin
介绍:属于创建的简写,其属于是一个整合
代码分析:
path("teachers/<pk>", views.TestGenericAPIView.as_view())
class TestGenericAPIView(CreateModelMixin, GenericAPIView):
queryset = Teacher.objects.all()
serializer_class = TeacherSerializer
def post(self, request, pk):
return self.create(request)
# 来自CreateModelMixin的create(),里面使用上一篇文章序列化里面新增的知识
4. UpdateModelMixin
导入:from rest_framework.mixins import UpdateModelMixin
介绍:属于创建的简写,其属于是一个整合
代码分析:
path("teachers", views.TestGenericAPIView.as_view())
path("teachers/<pk>", views.TestGenericAPIView.as_view())
class TestGenericAPIView(RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
def get(self, request, pk):
return self.retrieve(request)
# def put(self, request, pk):
# return self.update(request) # 全部更新
# 使用update时,如果在序列化时没有专门设置,名称属性required=False,默认就需要提供全部数据才能进行更新
def put(self, request, pk):
return self.partial_update(request) # 局部更新
# 使用partial_update时,如果在序列化时没有专门设置,名称属性required=False,也可以提供部分值就能成功更新数据,原理是:使用partial_update在UpdateModelMixin里面partial的参数为true;而update是false
5. DestroyModelMixin
导入:from rest_framework.mixins import DestroyModelMixin
介绍:属于删除的简写,其属于是一个整合
代码:
path("teachers", views.TestGenericAPIView.as_view())
path("teachers/<pk>", views.TestGenericAPIView.as_view())
class TestGenericAPIView(RetrieveModelMixin, DestroyModelMixin, GenericAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
def get(self, request, pk):
return self.retrieve(request)
def delete(self, request, pk):
return self.destroy(request)
三、扩展类的子类
同二、三一样,只是相当于对它们的简写,继承简写,也无需写get、post之类
1.CreateAPIView
导入:from rest_framework.generics import CreateAPIView
解释:用来创建,继承+post,其继承GenericAPIView, CreateModelMixin
class TestGenericAPIView(CreateAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 这样就实现了上面介绍CreateModelMixind的功能
2.ListAPIView
导入:from rest_framework.generics import ListAPIView
解释:用来查全部,继承+get,其继承GenericAPIView、ListModelMixin
class TestGenericAPIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 这样就实现了上面介绍ListModelMixin的功能
3.RetrieveAPIView
导入:from rest_framework.generics import RetrieveAPIView
解释:用来查单个,继承+get,其继承GenericAPIView、RetrieveModelMixin
class TestGenericAPIView(RetrieveAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 这样就实现了上面介绍RetrieveModelMixin的功能
4.DestroyAPIView
导入:from rest_framework.generics import DestroyAPIView
解释:用来删除单个,继承+delete ,其继承GenericAPIView、DestroyModelMixin
class TestGenericAPIView(DestroyAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 这样就实现了上面介绍DestoryModelMixin的功能
5.UpdateAPIView
导入:from rest_framework.generics import UpdateAPIView
解释:用来修改,继承+put(改全部)+patch(改单个) ,其继承GenericAPIView、UpdateModelMixin
class TestGenericAPIView(UpdateAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 这样就实现了上面介绍UpdateModelMixin的功能
6. RetrieveUpdateAPIView
解释:提供 get、put、patch方法
7. RetrieveUpdateDestroyAPIView
解释:提供 get、put、patch、delete方法
四、视图集
解释:视图集提供下面五种方式,具体能用什么,看你继承什么,与需要,配合url填入
- list() 提供一组数据
- retrieve() 提供单个数据
- create() 创建数据
- update() 保存数据
- destroy() 删除数据
1. ViewSet
导入:from rest_framework.viewsets import ViewSet
说明:其先继承了ViewSetMixin再继承APIView,ViewSetMixin相当于重写的APIView的as_view分发请求(其可以把请求与自己定义的函数名结合起来),其为基础类
path("teachers", views.TestGenericAPIView.as_view({'get':'list'})),
path("teachers/<pk>", views.TestGenericAPIView.as_view({'get':'retrieve'}))
class TestGenericAPIView(ViewSet):
'''
其不使用get(),post()方法
但是它通过ViewSetMixin的as_view()提供的参数(在ViewSetMixin为actions),根据对应关系创建了get,put,delete等请求
然后其发送给APIView的dispatch去类似于扩展类一样去分发给get、post、delete等等
'''
def list(self, request):
data = Student.objects.all()
serializer = StudentSerializer(instance=data,many=True)
return Response(serializer.data)
def retrieve(self, request, pk):
data = Student.objects.all().get(id=pk)
serializer = StudentSerializer(instance=data)
return Response(serializer.data)
2. GenericViewSet
导入:from rest_framework.viewsets import GenericViewSet
说明:其先继承了ViewSetMixin再继承GenericAPIView,重点提供get_object、get_queryset等属性与方法,所以较为基础类
path("teachers", views.TestGenericAPIView.as_view({'get':'list'})),
path("teachers/<pk>", views.TestGenericAPIView.as_view({'get':'retrieve'}))
class TestGenericAPIView(GenericViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
def list(self, request):
data = self.get_queryset()
serializer = self.get_serializer(data,many=True)
return Response(serializer.data)
def retrieve(self, request, pk):
data = self.get_object()
serializer = self.get_serializer(data)
return Response(serializer.data)
3.ModelViewSet
导入:from rest_framework.viewsets import ModelViewSet
说明:继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin
path("teachers", views.TestGenericAPIView.as_view({'get':'list'})),
path("teachers/<pk>", views.TestGenericAPIView.as_view({'get':'retrieve', 'delete':'destroy'}))
class TestGenericAPIView(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
4.ReadOnlyModelViewSet
导入:from rest_framework.viewsets import ReadOnlyModelViewSet
说明:继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin,用来获取数据
path("teachers", views.TestGenericAPIView.as_view({'get':'list'})),
path("teachers/<pk>", views.TestGenericAPIView.as_view({'get':'retrieve'})) #pk表示主键如果其它字段设置可名就可以
class TestGenericAPIView(ReadOnlyModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 只读只剩下list()和retrieve()方法了
5. 自定义
path("teachers/lastsome", views.TestGenericAPIView.as_view({'get':'lastsome'})),
class TestGenericAPIView(ReadOnlyModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
def lastsome(self, request):
data = Student.objects.get(id=7)
serializer = StudentSerializer(instance=data)
a = serializer.data
a.pop('time')
return Response(a)