drf-day7
九个视图子类
以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性
queryset = Publish.objects.all()
serializer_class = PublishSerialize
使用九个视图子类两个综合类来写五个接口
from rest_framework.generics import ListCreateAPIViewfrom rest_framework.generics import RetrieveUpdateDestroyAPIView class PublishView(ListCreateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer class PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer
使用九个视图子类中的五个单独类来写接口
from rest_framework.generics import ListAPIView, CreateAPIView from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView class PublishView(CreateAPIView, ListAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer class PublishDetailView(RetrieveAPIView,DestroyAPIView, UpdateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer
使用五个视图扩展类+genricapiview来写五个接口
from rest_framework.generics import GenericAPIView from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, \ UpdateModelMixin class AuthorView(GenericAPIView, CreateModelMixin, ListModelMixin): # parser_classes = [JSONParser] # renderer_classes = [JSONRenderer] queryset = Author.objects.all() serializer_class = AuthorSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request) class AuthorDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Author.objects.all() serializer_class = AuthorSerializer def get(self, request, pk): return self.retrieve(request, pk) def put(self, request, pk): return self.update(request, pk) def delete(self, request, pk): return self.destroy(request, pk)
路由
path('publish/', PublishView.as_view()), path('publish/<int:pk>', PublishView.as_view()),
视图集
只要视图类继承了它,路由写法改一下,5个接口都有,只需要写两个属性即可
from rest_framework.viewsets import ModelViewSet class PublishView(ModelViewSet): queryset = Publish.objects.all() serializer_class = PublishSerializer
路由写法
path('publish/', PublishView.as_view({'get':'list','post':'create'})), path('publish/<int:pk>', PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
modelviewset继承了五个视图扩展类和genericviewset,然后genericviewset中继承了viewsetmixin类;
viewsetmixin类重写as_view()方法。
path('publish/', PublishView.as_view({'get':'list','post':'create'})) path('publish/', PublishView.as_view({'get':'lqz'}))
源码分析
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):ViewSetMixin必须放前面,保证执行的as_view是ViewSetMixin的 路由匹配成功,执行viewsetmixin的as_view中的view(request) def view(request, *args, **kwargs): self = cls(**initkwargs) # 类实例化得到对象--》self是谁的对象?PublishView self.action_map = actions # {'get':'list','post':'create'} # method:get # action: list for method, action in actions.items(): # list 方法 handler = getattr(self, action) #PublishView对象中反射list,拿到了 # 反射设置值 #setattr(PublishView视图类的对象,get,list 方法) # PublishView视图类的对象中就会有一个get方法,就是list setattr(self, method, handler) return self.dispatch(request, *args, **kwargs)
总结:
路由中这样配置:PublishView.as_view({'get':'list','post':'create'})
以后get请求过来,本质执行的就是视图类中的list方法
ReadOnlyModelViewset
以后写的接口,只想有 获取单条和获取所有,继承它
# 1 两个视图基类 APIView和GenericAPIView APIView的执行流程:包装了新的 处理了csrfrequeset,执行了3大认证,处理全局异常 GenericAPIView:要做序列化,要跟数据库打交道,就直接继承它即可 queryset serializer_class get_object get_queryset get_serializer # 2 5个视图扩展类(不是视图类),需要GenericAPIView才能用 快速使用5个接口 某几个接口:查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView class PublishView(GenericAPIView,CreateModelMixin) queryset=Publish.objects.all() serializer_class=序列化类 def post(self,request) return self.create(request) class PublishDetailView(GenericAPIView,RetrieveModelMixin) queryset=Publish.objects.all() serializer_class=序列化类 def get(self,request) return self.retrieve(request) # 3 9个视图子类(继承GenericAPIView+5个视图扩展类的组合) ListAPIView, CreateAPIView ListCreateAPIView RetrieveAPIView, DestroyAPIView, UpdateAPIView RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView # 4 视图集 ModelViewSet: ViewSetMixin+GenericAPIView+5个视图扩展类 GenericViewSet+5个视图扩展类 ViewSetMixin源码:路由做映射的配置,以后视图类中方法可以随便命名 Viewset:ViewSetMixin+APIView---》不需要要序列化,路由写法变了 GenericViewSet:ViewSetMixin+GenericAPIView--》需要序列化,需要用数据库,路由写法变化 ReadOnlyModelViewSet:list和retrieve
drf之路由
之前路由的写法
path('books/', BookView.as_view())
继承viewsetmixin后
path('publish/',PublishView.as_view({'get': 'list', 'post': 'create'}))
继承viewsetmixin后,需要做映射,有一些麻烦,于是drf内部封装两个·路由类,可以帮助我们快速生成映射关系
两个路由类:
from rest_framework.routers import SimpleRouter from rest_framework.routers import DefaultRouter
自动生成路由:自动映射下面五种
{'get': 'list', 'post': 'create'} {'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}
除了这五种以外,想给其他方法做映射就需要使用装饰器
使用方式
前提:必须继承viewsetmixin+apiview及其子类才可以自动生成路由
url.py文件中
1 导入路由类 from rest_framework.routers import SimpleRouter, DefaultRouter 2 类实例化得到对象 router = SimpleRouter() 3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由 router.register('publish', PublishView, 'publish') # router.register('books', BookView, 'books') # 后期可以注册更多 router.register('user',UserView,'user') 4 把自动生成的路由,加到总路由中 urlpatterns = urlpatterns + router.urls # 两个列表直接相加
上述中的第四步还可以这样写
from django.urls import include path('api/v1/', include(router.urls))
register(prefix, viewset, base_name)
prefix 该视图集的路由前缀
viewset 视图集
base_name 路由别名的前缀
区别: 1.DefaultRouter生成的路径多一个根路径 api-root 2.DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据 3.以后就用SimpleRouter
from rest_framework.decorators import actio @action(methods=['POST'],detail=False) def register(self, request): return Response('register')
自动生成:
http://127.0.0.1:8008/user/register/,post请求就会执行register
action参数
methods:请求方式,可以写多个 detail:路由中是否带ID号 http://127.0.0.1:8008/user/register/ # detail=False # detail=False http://127.0.0.1:8008/user/4/register/ # detail=True # detail=True url_path:定义请求的URL的名称,默认是被装饰的方法名称
以后可能会重写list,create等方法
class PublishView(ModelViewSet): queryset = Publish.objects.all() serializer_class = PublishSerializer def list(self, request, *args, **kwargs): res=super().list(request, *args, **kwargs) return Response({'code':100,'msg':'成功','result':res.data})
重写get_serializer_class
是GenericAPIView类中的方法,返回什么,以后就以哪个序列化类继续操作 def get_serializer_class(self): print(self.action) if self.request.method=='POST': return WritePublishSerializer else: return self.serializer_class
重写perform_create
def perform_create(self, serializer): serializer.save() 根据self.action参数来决定使用哪一个序列化类来保存,排除不需要的保存的数据
不用action也可以,使用request.path,只是比较麻烦
1.视图类对象中的属性,action是本次请求执行的方法的名称 eg:def register: action就是register 2通过action属性可以限制视图类中的某个方法使用哪一个序列化类
importlib 模块
概念
用于动态地导入其他模块或包。它提供了一种灵活的方式来在运行时导入模块,这对于编写可扩展的代码或需要根据条件导入不同模块的情况非常有用。
用法
1.动态导入模块:
import importlib module_name = "math" # 模块名称 module = importlib.import_module(module_name) result = module.sqrt(25) # 动态调用模块中的函数 print(result)
2.重新加载模块:
import importlib module_name = "my_module" module = importlib.import_module(module_name) # 在对模块进行修改后,可以使用 reload 函数重新加载它 importlib.reload(module)
3.导入子模块或子包:
import importlib module_name = "my_package.my_module" module = importlib.import_module(module_name)
4.从字符串导入类:
import importlib module_name = "my_module" class_name = "MyClass" module = importlib.import_module(module_name) my_class = getattr(module, class_name) instance = my_class()
5.自定义导入路径:
import importlib.util module_name = "my_module" path_to_module = "/path/to/my_module.py" spec = importlib.util.spec_from_file_location(module_name, path_to_module) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module)
方法
importlib.import_module() 函数,它用于动态导入模块。
importlib.util.spec_from_file_location() 用于从文件位置创建一个模块规范对象。这对于从自定义路径加载模块非常有用。
importlib.util.module_from_spec() 用于从模块规范对象创建一个模块对象。这将允许你加载和执行模块代码。
importlib.reload(module) 用于重新加载一个已导入的模块,这在开发和调试过程中非常有用。它会重新执行模块的代码,以便更新任何已做的修改。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY