具有ModelViewSet和ModelSerializer 405的Django POST

时间:2018-07-25 19:18:33

标签: python django django-rest-framework

如何使ModelViewSet接受POST方法来创建对象?当我尝试呼叫端点时,我得到405 'Method "POST" not allowed.'

在views.py内:

class AccountViewSet(viewsets.ModelViewSet):
    """An Account ModelViewSet."""

    model = Account
    serializer_class = AccountSerializer
    queryset = Account.objects.all().order_by('name')

在serializers.py中:

class AccountSerializer(serializers.ModelSerializer):
    name = serializers.CharField(required=False)
    active_until = serializers.DateTimeField()

    class Meta:
        model = Account
        fields = [
            'name',
            'active_until',
        ]

    def create(self, validated_data):
        with transaction.atomic():
            Account.objects.create(**validated_data)

在urls.py中:

from rest_framework import routers

router = routers.SimpleRouter()
router.register(
    prefix=r'v1/auth/accounts',
    viewset=AccountViewSet,
    base_name='accounts',
)

我需要创建一个特定的@action吗?我的尝试尚未成功。如果是这种情况,我可以从测试中调用url = reverse('app:accounts-<NAME>')是什么?我还没有找到完整的示例(urls.py,views.py,serializers.py和测试等)。

3 个答案:

答案 0 :(得分:0)

从文档中

ViewSet类只是基于类的View的一种,它不提供任何方法处理程序,例如.get()或.post(),而是提供诸如.list()和.create()的操作。

这是受支持的操作的列表:

def list(self, request):
    pass

def create(self, request):
    pass

def retrieve(self, request, pk=None):
    pass

def update(self, request, pk=None):
    pass

def partial_update(self, request, pk=None):
    pass

def destroy(self, request, pk=None):
    pass

因此,不直接支持任何帖子,但不支持创建。 因此,当使用路由器而不是v1 / auth / accounts / post时,您的终点将是v1 / auth / accounts / create。

老实说,我更喜欢在使用DRF时使用基于类或基于函数的视图。它与django的常规视图更为相似,与我合作时更有意义。您将非常像常规的Django URL和视图那样编写视图和URL。

答案 1 :(得分:0)

您的代码似乎正常。我认为您正在尝试在另一个端点上创建一个新实例。也就是说,您可能会尝试使用v1/auth/accounts/id方法请求 HTTP POST 端点,这是不允许的。

因此,将HTTP POST请求发送到该端点 v1/auth/accounts/

在此处DRF simplerouter Doc

了解更多信息

答案 2 :(得分:0)

我发现了问题所在,路线有冲突。在AccountViewSet之前注册了一个更高级别的终结点。

router.register(
    prefix=r'v1/auth',
    viewset=UserViewSet,
    base_name='users',
)

router.register(
    prefix=r'v1/auth/accounts',
    viewset=AccountViewSet,
    base_name='accounts',
)

Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL.。我应该这样被命令的:

router.register(
    prefix=r'v1/auth/accounts',
    viewset=AccountViewSet,
    base_name='accounts',
)

router.register(
    prefix=r'v1/auth',
    viewset=UserViewSet,
    base_name='users',
)

尽管reverse('appname:acccounts-list')可以正常工作,但底层URL路由器仍然认为我正在调用UserViewSet。