04-drf檢視層詳細

小满三岁啦發表於2024-04-16

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. 區域性權重高於全域性,也就是全域性設定了返回JSONRenderer,區域性設定了TemplateHTMLRenderer,一樣按TemplateHTMLRenderer去返回
  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個檢視擴充套件類

匯入模組

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個檢視子類

思考?為什麼要有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

def get_serializer_class(self):
    if self.request.method == "GET":
        return ASerializer  # 替換 "a序列化類" 為實際的序列化類
    elif self.request.method == "POST":
        return BSerializer  # 替換 "b序列化類" 為實際的序列化類

新增資料後,返回指定訊息給客戶端 重寫 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/"
}

使用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

img

相關文章