Django Rest Framework APIRequestFactory请求对象没有属性'query_params'

Jam*_*Lin 9 django django-rest-framework

可以说我有这个APIView

class Dummy(APIView):
    def get(self, request):
        return Response(data=request.query_params.get('uuid'))
Run Code Online (Sandbox Code Playgroud)

为了测试它,我需要创建一个请求对象来传递给get函数

def test_dummy(self):
    from rest_framework.test import APIRequestFactory
    factory = APIRequestFactory()
    request = factory.get('/?uuid=abcd')
    DummyView().get(request)
Run Code Online (Sandbox Code Playgroud)

它抱怨 AttributeError: 'WSGIRequest' object has no attribute 'query_params'

仔细观察,工厂创建一个WSGIRequest实例而不是DRF版本<class 'rest_framework.request.Request'>.

>>> from rest_framework.test import APIRequestFactory
>>> factory = APIRequestFactory()
>>> request = factory.get('/')
>>> request.__class__
<class 'django.core.handlers.wsgi.WSGIRequest'>
Run Code Online (Sandbox Code Playgroud)

ZZY*_*ZZY 15

参考Tom的解决方案,DummyView()(request)会引发错误:

TypeError: 'DummyView' object is not callable
Run Code Online (Sandbox Code Playgroud)

相反,应该as_view像你在做的那样使用urls.py:

DummyView.as_view()(request)
Run Code Online (Sandbox Code Playgroud)

DRF as_view使用方法initialize_request将Django Request对象转换为DRF版本.您可以尝试:

from rest_framework.views import APIView
APIView().initialize_request(request)
>>> <rest_framework.request.Request object at 0xad9850c>
Run Code Online (Sandbox Code Playgroud)

您也可以使用APIClient来运行测试.它还测试URL调度.

from rest_framework.test import APIClient
client = APIClient()
client.post('/notes/', {'title': 'new idea'}, format='json')
Run Code Online (Sandbox Code Playgroud)

  • 虽然我接受了Tom的答案,因为它直接回答了我的问题,但是`initialize_request`提示实际上有很多帮助. (8认同)

Tom*_*tie 11

那就对了.此时APIRequestFactory返回一个HttpRequest对象,该对象只有在到达Request视图层后才会升级到REST框架对象.

这反映了,你会在实际的要求看,以及它的行为确实做的是处理如.呈现JSON,XML或您为测试请求配置的任何其他内容类型.

但是我同意这是令人惊讶的行为,并且在某些时候它可能会返回一个Request对象,而REST框架视图将确保它只Request对请求实例进行升级HttpRequest.

在你的情况下你需要做的是实际调用视图,而不是调用.get()方法...

factory = APIRequestFactory()
request = factory.get('/?uuid=abcd')
view = DummyView.as_view()
response = view(request)  # Calling the view, not calling `.get()`
Run Code Online (Sandbox Code Playgroud)