【问题标题】:How can I pass in url arguments to an APIRequestFactory put request?如何将 url 参数传递给 APIRequestFactory 放置请求?
【发布时间】:2021-01-27 04:08:13
【问题描述】:

我已经尝试了几个小时,但无法弄清楚如何通过 APIRequestFactory put 请求传递 url 参数。我在运行我的服务器时通过 Postman 尝试过,并且 url 变量传递得很好,但是当我在测试中运行它时它停止工作。

我的意思是,当我向“/litter/1/”发送 Postman PUT 请求时,它会成功地将 1 作为变量 litterId,因为我的网址是这样设置的

path('litter/', include('apps.litter.urls')),

path('<int:litterId>/', LitterView.as_view(), name='litter-with-id')

但是当我尝试向同一个 url 发送 APIRequestFactory put 请求时,由于某种原因,1 将不再作为 litterId。

一些相关的代码...

我的顶级 url.py

from rest_framework.authtoken import views

from apps.litter.views import LitterView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('auth/', include('apps.my_auth.urls')),
    path('litter/', include('apps.litter.urls')),
]

这是我的应用特定的 urls.py

from .views import LitterView

urlpatterns = [
    path('', LitterView.as_view(), name='standard-litter'),
    path('<int:litterId>/', LitterView.as_view(), name='litter-with-id'),
]

这是我的意见.py

import json
  
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.views.decorators.csrf import csrf_exempt
from rest_framework import authentication, permissions
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db import models

from .models import Litter
from .serializers import LitterSerializer


#@csrf_exempt
class LitterView(APIView):
    """ 
    View for litter related requests

    * Requres token auth
    """
    permission_classes = (IsAuthenticated,)
    authentication_classes = [authentication.TokenAuthentication]
    renderer_classes = [JSONRenderer]

    def put(self, request, litterId=0):
        """
        Updates an old litter
        """

        try:
            litterModel = Litter.objects.get(user=request.user, id=litterId)
        except Litter.DoesNotExist:
            returnData = {'status': 'fail',
                          'error': 'Could not find object with that id.'}
            return Response(returnData)

        serializer_class = LitterSerializer
        serialized = LitterSerializer(litterModel, data=request.data)

        if serialized.is_valid():
            litterModel = serialized.save()

            returnData = {'status': 'okay',
                          'litter': [serialized.data]}
            return Response(returnData)
        else:
            return Response(serialized.errors, status=400)

这是相关的测试。

def test_easy_successful_put_type(self):
        """
        Testing a simple put
        """

        user = UserFactory()
        amount = 40
        amountChange = 20
        litter = LitterFactory(user=user, amount=amount)

        data = {'typeOfLitter': litter.typeOfLitter,
                'amount': litter.amount + amountChange,
                'timeCollected': litter.timeCollected}

        url = '/litter/' + str(litter.id) + '/'
        request = self.factory.put(url, data, format='json') 
        force_authenticate(request, user=user)
        view = LitterView.as_view()
        response = view(request).render()
        responseData = json.loads(response.content)

无论我做什么,我都无法传入 int:litterId,put 函数的默认值始终为 0。任何帮助将不胜感激。

【问题讨论】:

    标签: python django rest testing


    【解决方案1】:

    你的问题在这里:

    response = view(request).render()
    

    您手动将请求传递给视图,也没有传递 kwarg litterId,而是使用 APIClient 并向 url 发出 put 请求。首先导入需要的模块:

    from django.urls import reverse
    from rest_framework.test import APIClient
    

    然后:

    user = UserFactory()
    amount = 40
    amountChange = 20
    litter = LitterFactory(user=user, amount=amount)
    data = {
                'typeOfLitter': litter.typeOfLitter,
                'amount': litter.amount + amountChange,
                'timeCollected': litter.timeCollected
           }
    
    url = reverse('litter-with-id', kwargs={'litterId': litter.id})
    client = APIClient()
    client.force_authenticate(user=user)
    response = client.put(url, data, format='json')
    

    【讨论】:

    • 天哪,非常感谢。我已经为此苦苦挣扎了一段时间。可以肯定的是,请求工厂无法做到这一点,因为它不会通过您传递的 url 传递任何数据?
    • @AdamBerard 您可以看到请求工厂只为您发出请求,您必须自己调用正确的视图等。您必须手动传递 response = view(request, litterId=litter.id).render() 之类的参数。
    • 再次感谢您的帮助。我总是对随机的陌生人在互联网上的帮助感到惊讶。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    • 2012-01-13
    相关资源
    最近更新 更多