04-drf视图层详细
drf的request请求
这里的request请求是基于APIView的,也就是新的request
正常情况下,request请求分为:urlcoded、json、form-data,可以控制只接受哪一个请求
导入模块
from rest_framework.parsers import JSONParser, MultiPartParser, FormParser
模块 | 描述 | 请求 |
---|---|---|
JSONParser | 用于解析 JSON 请求内容。request.data 将被填充为一个数据字典。 |
application/json |
FormParser | 用于解析 HTML 表单内容。request.data 将被填充为一个数据 QueryDict。通常与 MultiPartParser 一起使用以完全支持 HTML 表单数据。 |
application/x-www-form-urlencoded |
MultiPartParser | 用于解析多部分 HTML 表单内容,支持文件上传。request.data 和 request.FILES 将分别被填充为一个 QueryDict 和 MultiValueDict。通常与 FormParser 一起使用以完全支持 HTML 表单数据。 |
multipart/form-data |
1)局部使用 视图层中 放在视图类属性中,不要放在方法中
from rest_framework.parsers import JSONParser, MultiPartParser, FormParser
class HeroView(APIView):
# 放在视图类中 列表里面就是允许的请求
parser_classes = [JSONParser]
def get(self, request):
pass
def post(self, request):
pass
2) 全局使用 settings里面设置
这个文件在哪里,在rest_framework.settings.py里面,自己扣出来该就行了。
后续drf要配置的东西,全部都放到这里即可
- 如果三个全部都使用(默认就是)
- 如果要限制某个使用,局部导入就行
- 局部优先级高于全局,也就是说,如果全局注释了 JSONParser, 局部允许了 JSONParser 那么还是会允许JSONParser的,其他一样的道理。
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
],
}
关于request.data文件对象
- 能正常接受文件对象
- 不建议,通过request.data取文件对象,正常建议从request.FILES中去取文件数据。
- 为什么?
- 规范
def post(self, request):
serializer = HeroSerializer(data=request.data)
from_data = request.data
from_files = request.FILES
print("从requet.data中", from_data)
print("从request.FILES中", from_files)
"""
从requet.data中 <QueryDict: {'age': ['4'], 'name': ['大乔'], 'addr': ['召唤师峡谷'], 'myfile': [<InMemoryUploadedFile: BB外键关系.png (image/png)>]}>
从request.FILES中 <MultiValueDict: {'myfile': [<InMemoryUploadedFile: BB外键关系.png (image/png)>]}>
"""
drf的response响应
# Response的源码
class Response(SimpleTemplateResponse):
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
data 返回到响应体中
data的类型可以是:
- Python字典(
dict
)- 列表(
list
)- 序列化后的数据对象
- 查询集(
QuerySet
)的序列化结果- 自定义的序列化结果
status 返回HTTP状态码
导入模块
from rest_framework import status
使用
# ...
from rest_framework import status
class HeroView(APIView):
def post(self, request):
# ...
return Response(data={"code": 201, "msg": "创建成功!"}, status=status.HTTP_201_CREATED)
template_name (了解)
在DRF中,template_name
参数是用于指定视图返回的HTML模板的名称。它通常用于基于类的视图中的APIView
或ViewSet
,用于指定渲染HTML响应时要使用的模板文件。
例如,如果你有一个基于类的视图,你可以像这样设置template_name
参数:
from rest_framework.views import APIView
from rest_framework.response import Response
class MyAPIView(APIView):
template_name = 'my_template.html'
def get(self, request):
# 一些逻辑处理
return Response({'key': 'value'})
在这个例子中,当MyAPIView
处理GET请求时,它会渲染名为my_template.html
的模板,并将数据作为上下文传递给模板。
headers 响应头 可以自己定制
def get(self, request):
# ...
headers = {"name": "Ava", "age": 3}
# 这是一个没有意义的响应头,只是做演示而已
return Response({"code": 100, "msg": "成功", "results": serializer.data}, headers=headers)
exception 异常 需要设置为布尔值 (了解)
exception
参数是用于指示响应是否代表一个异常情况的布尔值。默认情况下,它是False
,表示响应不是一个异常。当设置为True
时,它表示响应代表一个异常情况。
在实际使用中,如果你的视图处理了一个异常,并且你想要返回一个异常响应,你可以创建一个Response
对象,并将exception
参数设置为True
。这样,客户端在接收到这个响应时就会知道这是一个异常情况。
例如,在视图中处理一个异常并返回一个异常响应的示例:
from rest_framework.response import Response
def my_view(request):
try:
# 这里是你的视图逻辑
result = do_something()
return Response(result)
except Exception as e:
# 如果发生异常,返回一个异常响应
return Response(status=500, exception=True)
在这个示例中,如果do_something()
函数抛出了一个异常,视图将返回一个带有500状态码的异常响应。通过将exception
参数设置为True
,客户端就会知道这是一个异常情况,而不是正常的成功响应。
举例说明
# ...
class HeroView(APIView):
# ...
def post(self, request):
try:
int("a")
if serializer.is_valid():
serializer.save()
return Response(data={"code": 201, "msg": "创建成功!"}, status=status.HTTP_201_CREATED)
except Exception as e:
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True, headers={"Error": e})
响应格式
drf接口会根据客户端类型返回对应的格式,浏览器返回HTML格式,其他客户端返回json格式
注意:如果是返回的json格式,一般是建议指定 JSONOpenAPIRenderer 这样体验会好一些。
导入模块
from rest_framework.renderers import JSONOpenAPIRenderer, BrowsableAPIRenderer
# JSONOpenAPIRenderer 用于按照 OpenAPI 规范将响应内容呈现为 JSON 格式。
# BrowsableAPIRenderer 用于将响应内容呈现为 HTML,用于可浏览的 API,提供了一个用户友好的界面,方便与 API 进行交互。
局部使用 视图层的类属性里面 不要放在方法里面
from rest_framework.renderers import JSONOpenAPIRenderer, BrowsableAPIRenderer
class HeroView(APIView):
# 放在类属性中,通过 render_classes = [类型指定即可]
renderer_classes = [JSONOpenAPIRenderer]
def get(self, request):
..
# 其他请求...
全局使用 settings里面设置
- 如果不做任何设置,默认是根据客户端关系返回
- 如果指定,那么浏览器和非浏览器都会按照指定格式(比如让浏览器返回json格式,而不是自带的drf api)
- 局部权重高于全局,也就是全局设置了返回BrowsableAPIRenderer,局部设置了JSONOpenAPIRenderer,一样按JSONOpenAPIRenderer去返回
- 一般局部设置即可
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.TemplateHTMLRenderer',
]
}
2个视图基类 APIView和GenericAPIView
导入模块
from rest_framework.generics import GenericAPIView
from rest_framework.views import APIView
基于APIView + Response + 序列化类 写接口
class HeroDetailView(APIView):
def get(self, request, pk):
hero_instance = Hero.objects.get(pk=pk)
serializer = HeroSerializer(instance=hero_instance)
return Response({"code": 200, "msg": "ok", "result": serializer.data})
def put(self, request, pk):
hero_instance = Hero.objects.get(pk=pk)
serializer = HeroSerializer(instance=hero_instance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"code": 200, "msg": "ok", "result": serializer.data})
else:
return Response({"code": 100, "msg": serializer.errors})
def delete(self, request, pk):
instance = get_object_or_404(Hero, pk=pk)
instance.delete()
return Response({"code": 100, "msg": "删除成功!"}, status=status.HTTP_204_NO_CONTENT)
基于GenericAPIView + Response + 序列化类 写接口
- 拿类属性通过方法去获取,而不要通过之前的方法。
- 如果要写其他模型的5个接口(有关联关系),所有代码不变,只需要改两个类属性即可
属性
# 查询所有对象
queryset = Hero.objects.all()
# 获取序列化类
serializer_class = HeroSerializer
方法
# 获取全部数据
hero_instance = self.get_queryset()
# 获取单个对象
hero_instance = self.queryset.filter(pk=pk).first() # 很low 不建议
hero_instance = self.get_object() # 推荐的写法
# 使用序列化类
serializer = self.get_serializer(instance=hero_instance, many=True)
GenericAPIView 的前端界面长这样
# 基于GenericAPIView去写
class HeroDetailView(GenericAPIView):
# 两个类属性
queryset = Hero.objects.all() # 全部
serializer_class = HeroSerializer # 序列化类
def get(self, request, pk):
# hero_instance = self.queryset.filter(pk=pk).first() 不要这样写
hero_instance = self.get_object()
serializer = self.get_serializer(instance=hero_instance)
return Response({"code": 200, "msg": "ok", "result": serializer.data})
def put(self, request, pk):
hero_instance = Hero.objects.get(pk=pk)
serializer = HeroSerializer(instance=hero_instance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"code": 200, "msg": "ok", "result": serializer.data})
else:
return Response({"code": 100, "msg": serializer.errors})
def delete(self, request, pk):
self.get_object().delete()
有什么问题?代码重复
# 有部分重复的代码,应该可以尝试继续优化掉
hero_instance = self.get_object()
serializer = self.get_serializer(instance=hero_instance)
5个视图扩展类 *ModelMixin
导入模块
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin
扩展类 | 对应方法 | 说明 |
---|---|---|
CreateModelMixin | post | 创建单个实例,返回创建后的实例。 |
UpdateModelMixin | put/patch | 更新单个实例,返回修改后的实例。 |
DestroyModelMixin | delete | 删除单个实例,返回的结果为空。 |
ListModelMixin | get | 获取全部,返回一个queryset列表。 |
RetrieveModelMixin | get/<int:pk>/ |
获取单个,返回一个具体的实例。 |
通过5个视图扩展类 + GenericAPIView + 序列化类写接口
# 源码
class CreateModelMixin:
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) # 校验数据
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save() # 和我们之前使用APIView的save() 一样 所以不需要我们写保存了,它内部调用了 perform_create 完成创建。
# 这里是校验字段的方法
# 如果包含了数据库中不存在的字段,DRF 默认会忽略这些字段,不会引发错误。
# 这是因为 DRF 默认情况下会忽略未知的字段,只处理已定义的字段。
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
代码
# ================ 五个视图扩展类
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin
class HeroView(GenericAPIView, CreateModelMixin, ListModelMixin):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
""" 注释的是之前写的代码 现在可以不用写了
hero_instance = self.get_queryset()
serializer = self.get_serializer(instance=hero_instance, many=True)
"""
def get(self, request):
return super().list(request)
def post(self, request):
return super().create(request)
# 基于五个视图扩展类去写
class HeroDetailView(GenericAPIView, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin):
# 两个类属性
queryset = Hero.objects.all() # 全部
serializer_class = HeroSerializer # 序列化类
def get(self, request, pk):
return super().retrieve(request)
def put(self, request, pk):
return super().update(request)
def delete(self, request, pk):
return super().destroy(request)
关于return时候的super
方法 | return的时候,需要返回父类的哪一个方法 |
---|---|
get | list |
post | create |
get/int:pk/ | retrieve |
put | update |
delete | destroy |
有什么问题?代码重复
return super().list(request)
return super().create(request)
return super().retrieve(request)
return super().update(request)
return super().destroy(request)
9个视图子类 *APIView
思考?为什么要有9个视图子类
- GenericAPIView + 对应的5个视图扩展类
- 5个
- GenericAPIView + CreateModelMixin + ListModelMixin
- 即创建一个和查询全部
- ListCreateAPIView
- 1个
- GenericAPIView + RetrieveModelMixin+ DestroyModelMixin
- 查询单条,删除单条
- RetrieveDestroyAPIView
- 1个
- GenericAPIView + RetrieveModelMixin + UpdateModelMixin
- 查询单条,修改单条
- RetrieveUpdateAPIView
- 1个
- GenericAPIView + RetrieveModelMixin + DestroyModelMixin
- 查询单条,既修改又删除
- GenericAPIView + RetrieveModelMixin + UpdateModelMixin + DestroyModelMixin
- RetrieveUpdateDestroyAPIView
- 1个
思考:为什么没有更新和删除的组合?
因为更新和删除通常不会结合在一起使用,它们通常被认为是不同的操作,分别用于修改和删除资源。因此,DRF没有提供一个默认的视图类来结合这两个操作。
自己写一个Mixin
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin
class CreatListAPIView(GenericAPIView, CreateModelMixin, ListModelMixin):
def get(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
class HeroView(CreatListAPIView):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
用模板写好的,我们直接使用
导入模块
from rest_framework.generics import CreateAPIView, ListAPIView, UpdateAPIView, DestroyAPIView, RetrieveAPIView
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView
五个方法
from rest_framework.generics import CreateAPIView, ListAPIView, UpdateAPIView, DestroyAPIView, RetrieveAPIView
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView
# 查询所有 新增一条
class HeroView(ListCreateAPIView):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
# 查询 修改 删除 1条
class HeroDetailView(RetrieveUpdateDestroyAPIView):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
视图集
- 如果要用视图集,一定要去修改路由,因为需要有映射关系。
- action是一个字典,字典的key是请求方式,字典的value是执行的方法。
- 我们可以自己定制映射关系,比如{"post": "login"},这样当发送post请求的时候,就执行login方法,不过需要继承 ViewSetMixin
通过视图集继续优化代码
# 视图层
from .serialinzer import HeroSerializer
from rest_framework.response import Response
from .models import Hero
from rest_framework.viewsets import ModelViewSet
class HeroView(ModelViewSet):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
class HeroDetailView(ModelViewSet):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
# 路由层
from django.urls import path
from .views import HeroView, HeroDetailView
urlpatterns = [
path("heros/", HeroView.as_view({"get": "list", "post": "create"})),
path("heros/<int:pk>/", HeroDetailView.as_view({"put":"retrieve", "get": "update", "delete": "destroy"}))
]
视图集源码分析
# 1 视图类:继承了APIView----》GenericAPIView
# 2 有5个方法---》继承了5个视图扩展类:
CreateModelMixin
RetrieveModelMixin
DestroyModelMixin
ListModelMixin
UpdateModelMixin
# 3 写没写 get put post delete--》使用映射
get---》list
get---》retrieve
put---》update
delete--》destroy
post-->create
# 4 继承了5个视图扩展类和 GenericViewSet 【不是GenericAPIView】
# 5 GenericViewSet:ViewSetMixin+GenericAPIView
# 6 ViewSetMixin 核心---》只要继承它--》路由写法就变了--》必须加action--》
-action是请求方式和视图类中方法的映射关系
# 7 以后只要继承ViewSetMixin的视图类
1 as_view 必须加action做映射
2 视图类中,可以写任意名的方法,只要做好映射,就能执行
# 8 ViewSetMixin源码分析--》通过重写as_view使得路由写法变了
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
# 0 跟APIView的as_view差不多
# 1 actions must not be empty,如果为空抛异常
# 2 通过反射把请求方式同名的方法放到了视图类中--》对应咱们的映射
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# actions 咱们传入的字典--》映射关系
# {'get': 'list', 'post': 'create'}
for method, action in actions.items():
# method=get action=list
# method=post action=create
# 视图类对象中反射:list 字符串--》返回了 list方法
# handler就是list方法
handler = getattr(self, action)
# 把handler:list方法 通过反射--》放到了视图类的对象中、
# method:get
# 视图类的对象中有个get--》本质是list
setattr(self, method, handler)
return self.dispatch(request, *args, **kwargs) # APIView的dispatch
return csrf_exempt(view)
继承ViewSetMixin,定制映射关系
注意,ViewSetMixin需要是直接父类,也就是要写在括号的左边,因为它重写了as_view,如果放在右边,能找到as_view,就无法执行action而触发报错。
# 常规写法
from rest_framework.viewsets import ViewSetMixin
from rest_framework.generics import GenericAPIView
class Game(ViewSetMixin, GenericAPIView):
def login(self, request):
return Response({"code": 100, "msg": "登录成功!"})
"""
(<class 'app01.views.Game'>,
<class 'rest_framework.viewsets.ViewSetMixin'>,
<class 'rest_framework.generics.GenericAPIView'>,
<class 'rest_framework.views.APIView'>,
<class 'django.views.generic.base.View'>,
<class 'object'>)
"""
# 查看源码
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
"""
pass
ViewSet = ViewSetMixin, GenericAPIView
# 更新写法
from rest_framework.viewsets import ViewSet
class Game(ViewSet):
def login(self, request):
return Response({"code": 100, "msg": "登录成功!"})
视图集下常用的类
# 五个接口
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# 查询1条,查询全部 get/<int:pk>/ get
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# 定制映射关系,路由写法要修改 --> action= {"post": "login"}
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
"""
pass
# 路由写法要修改
# 继承自 GenericAPIView 与 ViewSetMixin,在实现了调用 as_view() 时传入字典(如 {'get':'list'})的映射处理工作的同时
# 还提供了 GenericAPIView 提供的基础方法,可以直接搭配 Mixin 扩展类使用。
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
"""
pass
重写
查询部分数据,重写GenericAPIView.get_queryset
class HeroView(ListCreateAPIView):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
def get_queryset(self):
# 对get_queryset进行重写,查询id大于20小于40的结果
queryset = self.queryset.filter(id__gt="20", id__lt="40")
return queryset
根据请求执行不同序列化类,重写GenericAPIView.get_serializer_class
方案1
def get_serializer_class(self):
if self.request.method == "GET":
return ASerializer # 替换 "a序列化类" 为实际的序列化类
elif self.request.method == "POST":
return BSerializer # 替换 "b序列化类" 为实际的序列化类
方案2(推荐)
class UserView(ModelViewSet):
queryset = UserInfo.objects.all()
serializer_class = UserSarizliner
def get_serializer_class(self):
if self.action == "list":
return self.serializer_class
elif self.action == "retrieve":
return SingleSarializer
新增数据后,返回指定消息给客户端 重写 CreateModelMixin.create
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({"code": 201, "msg": "新增成功!", "result": serializer.data})
控制只能发送某一个请求
class HeroDetailView(RetrieveUpdateDestroyAPIView):
# 通过这个指定,里面填写允许的请求方式, 在views里面
http_method_names = [
"get",
]
queryset = Hero.objects.all()
serializer_class = HeroSerializer
# HeroDetailView.__mro__
(<class 'app01.views.HeroDetailView'>,
<class 'rest_framework.generics.RetrieveUpdateDestroyAPIView'>,
<class 'rest_framework.mixins.RetrieveModelMixin'>,
<class 'rest_framework.mixins.UpdateModelMixin'>,
<class 'rest_framework.mixins.DestroyModelMixin'>,
<class 'rest_framework.generics.GenericAPIView'>,
<class 'rest_framework.views.APIView'>,
<class 'django.views.generic.base.View'>,
<class 'object'>)
路由
自动生成路由SimpleRouter
from django.urls import path
from .views import HeroView
# 1 导入模块
from rest_framework.routers import SimpleRouter
# 实例化得到对象
router = SimpleRouter()
# 调用对象的方法
router.register("heros", HeroView, basename="HeroView")
urlpatterns = [
]
# 把生成的路由放进去路径里面
urlpatterns += router.urls
自动生成路由DefaultRouter
和SimpleRouter用法一样,只是会多一个api-root,后面路径多了看到的效果会更加明显。
admin/
app01/ ^heros/$ [name='HeroView-list']
app01/ ^heros\.(?P<format>[a-z0-9]+)/?$ [name='HeroView-list']
app01/ ^heros/(?P<pk>[^/.]+)/$ [name='HeroView-detail']
app01/ ^heros/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='HeroView-detail']
app01/ [name='api-root']
app01/ <drf_format_suffix:format> [name='api-root']
# 访问app01路径,之前会报错,现在会返回一个json
{
"heros": "http://127.0.0.1:8000/app01/heros/"
}
自动生成路由导入urlpattrens的方式2 include
from django.urls import path, include
from rest_framework.routers import SimpleRouter, DefaultRouter
from .views import UserView
router = DefaultRouter()
router.register("v1", UserView, "v1")
urlpatterns = [
# 写法2
# http://127.0.0.1:8000/user/v1/
# path("", include(router.urls))
# http://127.0.0.1:8000/user/zh/v1/
# 如果使用include的写法,path第一个参数的字段会拼在 router.register()的第一个参数的地址前面
# 一定要加 / 不然会报错
path("zh/", include(router.urls))
]
使用action定制详细路由
导入模块
from rest_framework.decorators import action
代码
# 视图层
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
class Game(ViewSetMixin, GenericAPIView):
@action(methods=['POST'], detail=False)
def login(self, request):
return Response({"code": 100, "msg": "登录成功!"})
# 路由层
from django.urls import path
from .views import HeroView, HeroDetailView, Game
from rest_framework.routers import SimpleRouter, DefaultRouter
router = DefaultRouter()
router.register("heros", HeroView, basename="HeroView")
reouter1 = SimpleRouter()
reouter1.register("game", Game, basename="Game")
urlpatterns = [
]
urlpatterns += router.urls
urlpatterns += reouter1.urls
自动生成的路由,不建议重写5个方法
class UserView(ViewSet):
# 自动生成的路由 会执行到create吗? 会 当post请求的时候
# 不过,后续如果是自动生成的路由,就不建议重写5个方法了 list retrieve create destroy update
# 其他方法同理
def create(self, request):
return Response("post ok")
action装饰器参数
# methods 请求方式:get put ... 如何使用 ——> method=["POST"]
# detail 默认为True 执行类似--> /users/1/login/ 如果设置为False --> /users/login/ 如果指定了为True,那么需要指定*args和**kwargs
# url_path:指定给前端地址的路径 如果不指定默认按函数名 一般不指定
# url_name=None
@action(methods=['请求方式,比如POST'], detail=布尔值,如果, url_path=None, url_name=None)
def login(self, request):
...
# 127.0.0.0:8000/system/1/login
@action(methods=['POST'], detail=True)
def login(self, request, *args, **kwargs):
return Response([args, kwargs, "ok"])
获取请求方法对应的函数 self.action
使用了此方法,类属性中的serializer_class=序列化器就失效了
class BooksView(ModelViewSet):
queryset = Book.objects.all()
# serializer_class = HeroSerializer 会失效
def get_serializer_class(self):
if self.action == 'login':
return LoginSerializer
elif self.action == 'register':
return RegisterSerializer
@action(methods=['GET'], detail=False)
def login(self, request):
pass
本文作者:小满三岁啦
本文链接:https://www.cnblogs.com/ccsvip/p/18137226
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。