我有一个GET
端点,我尝试使用APIRequestFactory
进行测试,遵循此SO帖子中描述的方法:https://stackoverflow.com/a/28429089
首先,我知道这个端点有效,因为当我通过cURL发送GET
请求时,我得到预期的行为。
curl -X GET -H "Content-Type: application/json" -i -d "{\"cardinal_key\":12XXXX3, \"cardinal_type\":\"Npis\", \"terminal_type\":\"Deas\", \"candidate_count\":2}" http://127.0.0.1:8000/v1/ranked_results/
HTTP/1.0 200 OK
Date: Mon, 28 Mar 2016 22:29:29 GMT
Server: WSGIServer/0.2 CPython/3.4.3
X-Frame-Options: SAMEORIGIN
Allow: GET, HEAD, OPTIONS
Vary: Accept, Cookie
Content-Type: application/json
{"npi":"12XXXX3","first_name":"XXXXXX","middle_name":null,"last_name":"XXXXXX","full_name":"XXXXX, XXXX XXXXX","link_candidates":{"FXXXXX9":0.9900022451986468,"BXXXXXXX3":0.8483023431385707}}
然而,当我尝试使用工厂模拟此请求时,我得到ValueError
例外(下面的完整描述):
from rest_framework.test import APIRequestFactory
from linker.views import RankedResults
factory = APIRequestFactory()
options = {"cardinal_key":12XXXX3, "cardinal_type":"Npis", "terminal_type":"Deas", "candidate_count":2}
request = factory.get('/v1/ranked_results/', json.dumps(options), content_type='application/json')
view = RankedResults.as_view()
response = view(request)
ValueError: need more than 1 value to unpack
我的下一个想法是,因为我试图将请求作为JSON发送,所以有些东西无效,所以我尝试在没有JSON的情况下发出请求,然后我得到了MultiValueDictKeyError
:
from rest_framework.test import APIRequestFactory
from linker.views import RankedResults
factory = APIRequestFactory()
options = {"cardinal_key":12XXXX3, "cardinal_type":"Npis", "terminal_type":"Deas", "candidate_count":2}
request = factory.get('/v1/ranked_results/', options)
view = RankedResults.as_view()
response = view(request)
MultiValueDictKeyError: "'cardinal_type'"
我对MultiValueDictKeyError
异常的理解是当密钥不在字典中时会发生。此外,文档说MultiValueDict
用于具有相同键的多个值的情况 - 我不知道为什么我看到这个,因为这不是请求的情况我是试图创造。
我在这里不知所措 - 我错过了什么?
视图:
class RankedResults(APIView):
def get(self, request):
cardinal_instance = apps.get_model('warehouse', request.data['cardinal_type']).objects.get(reference_key=request.data['cardinal_key'])
serializer = LinkModelSerializer(cardinal_instance, context=request.data)
return Response(serializer.data)
串行器:
class LinkModelSerializer(serializers.ModelSerializer):
link_candidates = serializers.SerializerMethodField('get_candidate_links')
def get_candidate_links(self, obj):
terminal = apps.get_model('warehouse', self.context['terminal_type'])
n = self.context['candidate_count']
return dict(obj.top_n_candidates(terminal, n))
class Meta:
model = warehouse.Npis
fields = ('npi', 'first_name', 'middle_name', 'last_name', 'full_name', 'link_candidates')
read_only_fields = ('link_candidates')
跟踪我尝试发送JSON请求的情况:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-20-6b10ed2040c0> in <module>()
2 factory = APIRequestFactory()
3 options = {"cardinal_key":12XXXX3, "cardinal_type":"Npis", "terminal_type":"Deas", "candidate_count":2}
----> 4 request = factory.get('/v1/ranked_results/', json.dumps(options), content_type='application/json')
5 view = RankedResults.as_view()
6 response = view(request)
~/lib/python3.4/site-packages/rest_framework/test.py in get(self, path, data, **extra)
79 def get(self, path, data=None, **extra):
80 r = {
---> 81 'QUERY_STRING': urlencode(data or {}, doseq=True),
82 }
83 # Fix to support old behavior where you have the arguments in the url
~/lib/python3.4/site-packages/django/utils/http.py in urlencode(query, doseq)
94 [(force_str(k),
95 [force_str(i) for i in v] if isinstance(v, (list, tuple)) else force_str(v))
---> 96 for k, v in query],
97 doseq)
98
~/lib/python3.4/site-packages/django/utils/http.py in <listcomp>(.0)
94 [(force_str(k),
95 [force_str(i) for i in v] if isinstance(v, (list, tuple)) else force_str(v))
---> 96 for k, v in query],
97 doseq)
98
ValueError: need more than 1 value to unpack
...最后是我在没有JSON请求时尝试的跟踪:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
~/lib/python3.4/site-packages/django/utils/datastructures.py in __getitem__(self, key)
82 try:
---> 83 list_ = super(MultiValueDict, self).__getitem__(key)
84 except KeyError:
KeyError: 'cardinal_type'
During handling of the above exception, another exception occurred:
MultiValueDictKeyError Traceback (most recent call last)
<ipython-input-17-559ee170e692> in <module>()
4 request = factory.get('/v1/ranked_results/', options)
5 view = RankedResults.as_view()
----> 6 response = view(request)
~/lib/python3.4/site-packages/django/views/decorators/csrf.py in wrapped_view(*args, **kwargs)
56 # function.
57 def wrapped_view(*args, **kwargs):
---> 58 return view_func(*args, **kwargs)
59 wrapped_view.csrf_exempt = True
60 return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
~/lib/python3.4/site-packages/django/views/generic/base.py in view(request, *args, **kwargs)
66 self.args = args
67 self.kwargs = kwargs
---> 68 return self.dispatch(request, *args, **kwargs)
69 view.view_class = cls
70 view.view_initkwargs = initkwargs
~/lib/python3.4/site-packages/rest_framework/views.py in dispatch(self, request, *args, **kwargs)
464
465 except Exception as exc:
--> 466 response = self.handle_exception(exc)
467
468 self.response = self.finalize_response(request, response, *args, **kwargs)
~/lib/python3.4/site-packages/rest_framework/views.py in dispatch(self, request, *args, **kwargs)
461 handler = self.http_method_not_allowed
462
--> 463 response = handler(request, *args, **kwargs)
464
465 except Exception as exc:
~/views.py in get(self, request)
36 class RankedResults(APIView):
37 def get(self, request):
---> 38 cardinal_instance = apps.get_model('warehouse', request.data['cardinal_type']).objects.get(reference_key=request.data['cardinal_key'])
39 serializer = LinkModelSerializer(cardinal_instance, context=request.data)
40 return Response(serializer.data)
~/lib/python3.4/site-packages/django/utils/datastructures.py in __getitem__(self, key)
83 list_ = super(MultiValueDict, self).__getitem__(key)
84 except KeyError:
---> 85 raise MultiValueDictKeyError(repr(key))
86 try:
87 return list_[-1]
MultiValueDictKeyError: "'cardinal_type'"
答案 0 :(得分:0)
来自request.data
的文档:
request.data
返回请求正文的已解析内容。这类似于标准request.POST
和request.FILES
属性...
因此,request.data
仅在您在POST
,PUT
或PATCH
请求中传递请求正文中的内容时才可用。
但您正在提出GET
请求:
request = factory.get('/v1/ranked_results/', json.dumps(options),
content_type='application/json')
对于GET
请求,获取查询字符串的正确方法是使用request.query_params
:
request.query_params
是request.GET
的更正确命名的同义词。为了清晰显示代码,我们建议使用
request.query_params
代替Django的标准request.GET
。这样做有助于保持代码库更加正确和明显 - 任何HTTP方法类型都可能包含查询参数,而不仅仅是GET
个请求。
因此,您将能够访问您想要的内容:
cardinal_type = request.query_params['cardinal_type']
# and similarly others