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.datarequest.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要配置的东西,全部都放到这里即可

  1. 如果三个全部都使用(默认就是)
  2. 如果要限制某个使用,局部导入就行
  3. 局部优先级高于全局,也就是说,如果全局注释了 JSONParser, 局部允许了 JSONParser 那么还是会允许JSONParser的,其他一样的道理。
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],
}

关于request.data文件对象

  1. 能正常接受文件对象
  2. 不建议,通过request.data取文件对象,正常建议从request.FILES中去取文件数据。
    1. 为什么?
    2. 规范
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的类型可以是:

  1. Python字典(dict
  2. 列表(list
  3. 序列化后的数据对象
  4. 查询集(QuerySet)的序列化结果
  5. 自定义的序列化结果

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)

image-20240415155717863

template_name (了解)

在DRF中,template_name参数是用于指定视图返回的HTML模板的名称。它通常用于基于类的视图中的APIViewViewSet,用于指定渲染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)

image-20240415161058172

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})

image-20240415162232275

响应格式

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里面设置

  1. 如果不做任何设置,默认是根据客户端关系返回
  2. 如果指定,那么浏览器和非浏览器都会按照指定格式(比如让浏览器返回json格式,而不是自带的drf api)
  3. 局部权重高于全局,也就是全局设置了返回BrowsableAPIRenderer,局部设置了JSONOpenAPIRenderer,一样按JSONOpenAPIRenderer去返回
  4. 一般局部设置即可
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 + 序列化类 写接口

  1. 拿类属性通过方法去获取,而不要通过之前的方法。
  2. 如果要写其他模型的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 的前端界面长这样

image-20240415172651424

# 基于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 {}

image-20240415190602607

代码

# ================ 五个视图扩展类
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个视图子类

  1. GenericAPIView + 对应的5个视图扩展类
    1. 5个
  2. GenericAPIView + CreateModelMixin + ListModelMixin
    1. 即创建一个和查询全部
    2. ListCreateAPIView
    3. 1个
  3. GenericAPIView + RetrieveModelMixin+ DestroyModelMixin
    1. 查询单条,删除单条
    2. RetrieveDestroyAPIView
    3. 1个
  4. GenericAPIView + RetrieveModelMixin + UpdateModelMixin
    1. 查询单条,修改单条
    2. RetrieveUpdateAPIView
    3. 1个
  5. GenericAPIView + RetrieveModelMixin + DestroyModelMixin
    1. 查询单条,既修改又删除
    2. GenericAPIView + RetrieveModelMixin + UpdateModelMixin + DestroyModelMixin
    3. RetrieveUpdateDestroyAPIView
    4. 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

视图集

  1. 如果要用视图集,一定要去修改路由,因为需要有映射关系。
  2. action是一个字典,字典的key是请求方式,字典的value是执行的方法。
  3. 我们可以自己定制映射关系,比如{"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 中国大陆许可协议进行许可。

posted @   小满三岁啦  阅读(38)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 夜空中最亮的星 小果酱
夜空中最亮的星 - 小果酱
00:00 / 00:00
An audio error has occurred.