视图集/路由自动生成/action装饰器
9个视图子类
在此文件中 from rest_framework.generics 有九个视图子类 功能分别如下
9个视图子类---视图类,不需要额外继承GenericAPIView,只需要继承9个中其中某个,就会有某个或某几个接口
CreateAPIView 新增数据接口 post
ListAPIView 获取全部数据 get
RetrieveAPIView 获取单个数据 get
DestroyAPIView 删除单个数据 delete
UpdateAPIView 修改单个数据 put
ListCreateAPIView 获取全部和新增数据 get post
RetrieveUpdateAPIView 查询单个和修改单个 get put
RetrieveDestroyAPIView 查询单个和删除单个 get delete
RetrieveUpdateDestroyAPIView 查询、修改、删除
## 路由
urlpatterns = [
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookView.as_view()),
]
# 视图类
class BookView(ListCreateAPIView): # 查询所有,新增一个
queryset = Book.objects.all()
serializer_class = BookSerializer
# 新增一个,修改一个,删除一个
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
视图集
1.0版本 视图类ModelViewSet与路由层.as_view({'get': 'list'})搭配使用
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet): # 继承了这个以后就相当于拥有了5个功能
queryset = Book.objects.all()
serializer_class = BookSerializer
重点,一旦继承了ModelViewSet那路由写法就要改变为
path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
# 通过键值对来 判断 什么请求方式 执行 什么方法
ModelViewSet分析
这个类又继承了 5个视图扩展类 + GenericViewSet 这个类
GenericViewSet 这个类 又继承了GenericAPIView ViewSetMixin
所以 ModelViewSet 可以拥有 5个功能
但是导致我们更改url写法的是ViewSetMixin
ViewSetMixin分析
ViewSetMixin重写了as_view方法 所以 以后配置路由变为了
views.BookView.as_view({'get': 'list', 'post': 'create'})
这样当路由请求来的时候 其实是执行了ViewSetMixin的as_view方法
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
# 如果没有传actions,直接抛异常,路由写法变了后,as_view中不传字典,直接报错,actions就是路由里面填写的字典
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)
self.action_map = actions
for method, action in actions.items():
# 循环对我们传入的字典解压赋值
# method = get action = list
handler = getattr(self, action)
# 通过反射视图类中action对应的方法
# handler就是视图类中的list方法
setattr(self, method, handler)
# 反射修改,把method:get的请求方式变为了执行list方法
return self.dispatch(request, *args, **kwargs)
# 去除了csrf校验
return csrf_exempt(view)
# ViewSetMixin的as_view方法的本质是执行了 view方法
总结
'''
from rest_framework.viewsets下有这几个类
ModelViewSet:5个试图扩展类+ViewSetMixin+GenericAPIView
ReadOnlyModelViewSet::2个试图扩展类+ViewSetMixin+GenericAPIView 只读的两个
ViewSetMixin:魔法,重新了as_view,只要继承他,以后路由写法变成了映射方法
ViewSet:ViewSetMixin+ APIView
GenericViewSet:ViewSetMixin+ GenericAPIView
'''
只要是继承了ViewSetMixin的视图类,路由写法都变为了需要(重写了as_veiw)
actions就是我们传入的字典,通过反射来控制 访问方式执行不同的功能
以后视图类中的方法名,可以任意命名,只要在路由中做好映射即可
eg:
path('user/', views.UserView.as_view({'get': 'login', 'post': 'register'}))
class UserView(GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def login(self,request):
return Response({'code':'100','msg':'登录成功'})
def register(self,request):
pass
# 视图类中的方法名,可以任意命名,只要在路由中做好映射即可
# 如果是跟数据库无关的功能接口 例如 短信验证码 等 尽量使用ViewSet
path('msg/<int:pk>/', views.SendView.as_view({'post': 'send_sms'}))
from rest_framework.viewsets import ViewSet
class SendView(ViewSet):
def send_sms(self, request,pk):
print(pk)
phone = request.query_params.get('phone')
# 手机号,从哪去,假设get请求,携带了参数
print('发送成功,%s' % phone)
return Response({'code': 100, 'msg': '发送成功'})
# 以后,你想继承APIView,但是想变路由写法【视图类中方法名任意命名】,要继承ViewSet (跟数据库无关建议使用)
# 以后,你想继承GenericAPIView,但是想变路由写法【视图类中方法名任意命名】,要继承GenericViewSet (跟数据库有关建议使用)
路由系统 自动生成
# drf 由于继承ViewSetMinxin类,路由写法变了
-原生+drf,以后的路由写法,可能会有如下情况(三种情况)
-path('books/', views.BookView.as_view()
-path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'}))
-自动生成
如何自动生成路由 -------------------------------------------
#需要 继承ModelViewSet后,路由可以自动生成
from rest_framework.routers import SimpleRouter,DefaultRouter
routers = SimpleRouter()
# 1.通过导入的生成路由的类产生对象
routers.register('user', views.UserView, 'user')
# 2.向对象内注册一个路由 三个参数分别为 路由的地址 路由关联的视图类 路由别名
# 会自动生成 https//127.0.0.1:8000/user/ https//127.0.0.1:8000/user/<int:pk>
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns = urlpatterns + routers.urls
#3.将自动生成的路由添加到django路由中
SimpleRouter与DefaultRouter的区别是:DefaultRouter会多附带一个默认的api根视图 返回一个包含所有列表视图的超链接响应数据
一般都使用SimpleRouter
include写路由
from django.urls import path, include
# 导入该模块
from rest_framework.routers import SimpleRouter,DefaultRouter
routers = SimpleRouter()
routers.register('user', views.UserView, 'user')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),]
优点:可以自定义路径前缀 建议使用
底层实现:
-本质是自动做映射,能够自动成的前提是,视图类中要有 5个方法其中的某一个或者多个
get--->list
get---->retrieve
put---->update
post---->create
delete---->destory
所以需要搭配视图类继承-ModelViewSet或ReadOnlyModelViewSet或
viewsetMixin+9个视图子类/ViewSetMixin+GenericAPIView+5个试图扩展类
才可以自动生成
eg: class UserView(ViewSetMixin,ListAPIView,RetrieveAPIView):
# 该接口只能读数据
queryset = User.objects.all()
serializer_class = UserSerializer
action装饰器
原始方法:
from rest_framework.viewsets import ViewSet
class SendView(viewSet):
def send_msg(self,request):
phone = request.query_params.get('phone')
return Response({'msg':'发送成功'})
path('send/', view.SendView.as_view({'get':'send_msg'})),
from rest_framework.decorators import action
action装饰器:
class SendView(viewSet):
@action(methods=['GET'], detail=False)
# 设置当使用get请求访问该路由 执行该方法
def send_msg(self,request):
phone = request.query_params.get('phone')
return Response({'msg':'发送成功'})
路由自动生成:
routers = SimpleRouter()
routers.register('send', views.Send, 'send')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(routers.urls)),
]
当访问:http://127.0.0.1:8000/api/v1/send/send_msg 即可触发该方法
总结:
1.写在视图类方法上 -----
2.配置methods=['get']指定访问方式
配置detail=False(不带id的路径)send/send_msg
配置detail=True (带id的路径) send/2/send_msg
url_path:生成send后路径的名字,不填写默认以方法名命名
url_name:别名,反向解析使用,了解即可
class Send(ViewSet):
@action(methods=['GET'], detail=False)
def a01(self, request):
return Response({'msg': '1', })
# http://127.0.0.1:8000/api/v1/send/a01
@action(methods=['GET'], detail=False)
def a02(self, request):
return Response({'msg': '2'})
# http://127.0.0.1:8000/api/v1/send/a02
@action(methods=['GET'], detail=False)
def a03(self, request):
return Response({'msg': '3', })
# http://127.0.0.1:8000/api/v1/send/a03
通过action来进行使用序列化类区分
伪代码展示:
通过重写get_serializer方法 来判断执行的方法是哪个,从来用出不同的序列化类
class Send(GenericViewSet):
queryset = None
serializer_class = UserSerializer
def get_serializer(self,*args,**kwargs):
if self.action == 'a01':
return UserSerializer
else:
return BookSerializer
@action(methods=['GET'], detail=False)
def a01(self, request):
return Response({'msg': '1', })
@action(methods=['GET'], detail=False)
def a02(self, request):
return Response({'msg': '2'})
@action(methods=['GET'], detail=False)
def a03(self, request):
return Response({'msg': '3', })
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了