Django-Rest-Framework:我可以使用两个具有相同url_path但请求方法不同的方法来创建视图集吗?

时间:2018-12-20 21:12:44

标签: python django django-rest-framework

这是视图集

class MobileDeviceViewset(ModelViewSet):
    @action(
        methods=['post', 'put', 'patch'],
        url_path='token',
        detail=True,
    )
    def update_token(self, request, *args, **kwargs) -> Response:
        ...

    @action(
        methods=['get'],
        url_path='token',
        detail=True,
    )
    def get_token(self, request, *args, **kwargs) -> Response:
        ...

所以我想在这里做一个端点/token/,应用程序将发送一个GET请求来检查是否有令牌,如果有则获取令牌。我还想使用相同的/token/端点向其发送更新的令牌。当前发生的是,我收到一条错误消息,告诉我该端点上不允许使用POST / PATCH / PUT方法,因此它似乎只能识别get_token方法。这里的令牌对象实际上是一个名为MobileDeviceUser的ManyToMany贯穿模型,因此我不只是尝试更新MobileDevice对象上的字段。

2 个答案:

答案 0 :(得分:1)

由于两种情况下您的url_pathdetail相同,所以为什么要在视图中使用两种独立的方法?
无论如何,我会推荐这种方式,

class MobileDeviceViewset(ModelViewSet):
    # your code

    @action(methods=['get', 'post', 'put', 'patch'], url_path='token', detail=True, )
    def my_action(self, request, *args, **kwargs):
        if request.method == 'GET':
            return self.get_token(request, *args, **kwargs)
        else:
            return self.update_token(request, *args, **kwargs)

    def update_token(self, request, *args, **kwargs):
        return Response("update token response--{}".format(request.method))

    def get_token(self, request, *args, **kwargs):
        return Response("update token response--{}".format(request.method))

然后,您必须在URL配置中进行一些更改,

from django.urls import path
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('mysample', MobileDeviceViewset, base_name='mobile-device')
actions = {
    "get": "my_action",
    "post": "my_action",
    "put": "my_action",
    "patch": "my_action"
}
urlpatterns = [
                  path('mysample/<pk>/token/', MobileDeviceViewset.as_view(actions=actions))

              ] + router.urls

因此,您的URL将类似于 ..../mysample/3/token/

注意
此解决方案在Python 3.6Django==2.1DRF==3.8.2下进行了测试


UPDATE

为什么 Method Not Allowed 错误?

当请求到达Django时,它会在URL配置中搜索模式,如果发生匹配,则将请求发送到相应的视图。
在您的情况下,您已经定义了两个具有相同URL(如下所示)的视图(是的,虽然它是动作)。

actions = {
    "post": "update_token",
    "put": "update_token",
    "patch": "update_token"
}

urlpatterns = [
                  path('mysample/<pk>/token/', MobileDeviceViewset.as_view(actions={"get": "get_token"})),
                  path('mysample/<pk>/token/', MobileDeviceViewset.as_view(actions=actions))

              ] + router.urls


在这种情况下,将发出一个请求(将其作为 HTTP POST ),并且URL调度程序将重定向到满足URL路径的第一个视图。因此,POST请求进入了 get_token 方法,但是,仅允许 GET 方法


可能的解决方案是什么?

方法1:
如我在顶部所述,请使用常见操作并区分 HTTP方法并调用适当的方法
方法2:
为这两个操作使用不同的URL路径,例如

actions = {
    "post": "my_action",
    "put": "my_action",
    "patch": "my_action"
}
urlpatterns = [
                  path('mysample/<pk>/get-token/', MobileDeviceViewset.as_view(actions={"get": "get_token"})),
                  path('mysample/<pk>/update-token/', MobileDeviceViewset.as_view(actions=actions))

              ] + router.urls

答案 1 :(得分:0)

您可以通过:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Spawn : MonoBehaviour {

public Spawn04[] pest;
public GameObject plantPest;





void Start () {
}

[System.Obsolete]
void Update () {
if(plantPest.active)
{
    SpawnObjects();
}


}
void SpawnObjects()
{
    int i = Random.Range(0, 100);

    for(int j = 0; j < pest.Length; j++)
    {
        if(i >= pest[j].minProbabilityRange && i <= pest[j].maxProbabilityRange)
        {
            Instantiate(pest[j].spawnObject, transform.position, transform.rotation);
            break;
        }
        if(pest[j].pestCount >= pest[j].maxNumber)
        {
            Destroy(this.gameObject);
        }
    }
  }
}

[System.Serializable]
public class Spawn04
{
public GameObject spawnObject;
public int minProbabilityRange = 0;
public int maxProbabilityRange = 0;
public int maxNumber = 1;
public int pestCount = 0;
}

https://www.django-rest-framework.org/api-guide/viewsets/#routing-additional-http-methods-for-extra-actions