python - Django request data returns str instead of list -
i'm developing rest api django , rest-framework. have endpoint takes post request kind of json:
{ "pipeline": ["bayes"], "material": [ "rakastan iloisuutta!", "autojen kanssa pitää olla varovainen.", "paska kesä taas. kylmää ja sataa" ] }
it machine-learning analysis api , json tells use bayes classifier provided strings , return results. works fine when test manually doing post requests. however, breaks down when try write unit test. have following test:
class classifytextapitests(apitestcase): fixtures = ['fixtures/analyzerfixtures.json'] #suboptimal fixture since requires bayes.pkl in /assets/classifiers folder def test_classification(self): """ make sure api respond correctly when required url params supplied. """ response = self.client.post(reverse('analyzer_api:classifytext'), { "pipeline": ["bayes"], "material": [ "rakastan iloisuutta!", "autojen kanssa pitää olla varovainen.", "paska kesä taas. kylmää ja sataa", ] }) self.asserttrue(status.is_success(response.status_code)) self.assertequal(response.data[0], 1)
test fails everytime because of latter assert gives "assertionerror: 'p' != 1"
here view code:
class classifytext(apiview): """ takes text snippet parameter , returns analyzed result. """ authentication_classes = (authentication.tokenauthentication,) permission_classes = (permissions.allowany,) parser_classes = (jsonparser,) def post(self, request, format=none): try: self._validate_post_data(request.data) print("juttu", request.data["material"]) #create pipeline request pipeline = pipeline() component_name in request.data["pipeline"]: pipeline.add_component(component_name) response = pipeline.execute_pipeline(request.data['material']) status_code = status.http_200_ok except exception e: response = {"message": "please provide proper data.", "error": str(e) } status_code = status.http_400_bad_request return response(response, status=status_code) def _validate_post_data(self, data): if "pipeline" not in data: raise invalidrequest("pipeline field missing. should array of components used in analysis. available components @ /api/classifiers") if len(data["pipeline"]) < 1: raise invalidrequest("pipeline array empty.") if "material" not in data: raise invalidrequest("material analyzed missing. please provide array of strings.") if len(data["material"]) < 1: raise invalidrequest("material analyzed missing, array empty. please provide array of strings.")
the interesting part when fired debugger check happens here. turns out line
request.data['material']
gives last entry of list in in request, in case
"paska kesä taas. kylmää ja sataa"
however, while inspect contents of request.data, shows querydict lists pipeline , material in request. why string instead of material list when call request.data["material"] ? there have forgotten , have specify kind of serializer? , why works during normal execution not tests?
i'm using django 1.8 python 3. also, i'm not tying view specific model.
finally here debugger shows when put break points view: request.data:
querydict: {'material': ['rakastan iloisuutta!', 'autojen kanssa pitää olla varovainen.', 'paska kesä taas. kylmää ja sataa'], 'pipeline': ['bayes']}
asd = request.data["material"]:
'paska kesä taas. kylmää ja sataa'
this because querydict returns last value of list in __getitem__
:
querydict.getitem(key)
returns value given key. if key has more 1 value, getitem() returns last value. raises django.utils.datastructures.multivaluedictkeyerror if key not exist. (this subclass of python’s standard keyerror, can stick catching keyerror.)
https://docs.djangoproject.com/en/1.8/ref/request-response/#django.http.querydict.getitem
if post form, in key maps list:
d = {"a": 123, "b": [1,2,3]} requests.post("http://127.0.0.1:6666", data=d)
this in request body:
a=123&b=1&b=2&b=3
since test method post data form, request.data querydict (the same request.post), hence last value in list when getting request.data.
to expected behavior, post data json in request body (as in @vladir parrado cruz's answer).
Comments
Post a Comment