Django请求数据返回str而不是list

Tum*_*tsu 2 python django django-rest-framework

我正在使用Django和REST-framework开发REST API。我有端点接受带有这种json的POST请求:

{
        "pipeline": ["Bayes"],
        "material": [
            "Rakastan iloisuutta!",
            "Autojen kanssa pitää olla varovainen.",
            "Paska kesä taas. Kylmää ja sataa"
        ]
    }
Run Code Online (Sandbox Code Playgroud)

它是一种机器学习分析api,并且json告诉您使用贝叶斯分类器来提供字符串并返回结果。当我通过发布请求手动测试时,此方法工作正常。但是,当我尝试编写单元测试时,它崩溃了。我有以下测试:

class ClassifyTextAPITests(APITestCase):
    fixtures = ['fixtures/analyzerfixtures.json'] #suboptimal fixture since requires bayes.pkl in /assets/classifiers folder

    def test_classification(self):
        """ Make sure that the API will respond correctly when required url params are 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)
Run Code Online (Sandbox Code Playgroud)

每次测试失败,因为后者断言给出了“ AssertionError:'P'!= 1”

这是我的查看代码:

class ClassifyText(APIView):
    """
    Takes text snippet as a parameter and 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 from request
            pipeline = Pipeline()
            for 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 as e:
            response = {"message": "Please provide a 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 is missing. Should be array of components used in analysis. Available components at /api/classifiers")

        if len(data["pipeline"]) < 1:
            raise InvalidRequest("Pipeline array is empty.")

        if "material" not in data:
            raise InvalidRequest("Material to be analyzed is missing. Please provide an array of strings.")

        if len(data["material"]) < 1:
            raise InvalidRequest("Material to be analyzed is missing, array is empty. Please provide an array of strings.")
Run Code Online (Sandbox Code Playgroud)

真正有趣的部分是当我解雇调试器以检查此处发生的情况时。原来那条线

request.data['material']
Run Code Online (Sandbox Code Playgroud)

在我的请求中给出列表的最后一个条目,在这种情况下

“ Paskakesätaas。Kylmääja sataa”

但是,当我检查request.data的内容时,它显示了一个querydict,其中列出了请求中的管道和材料。为什么在调用request.data [“ material”]时得到字符串而不是材料列表?有什么我忘记的东西,我必须指定某种串行器吗?以及为什么它在正常执行期间有效但在测试中无效?

我将Django 1.8与Python 3配合使用。此外,我并未将视图绑定到任何特定模型。

最后,这是当我将断点放入视图中时调试器显示的内容:request.data:

QueryDict: {'material': ['Rakastan iloisuutta!', 'Autojen kanssa pitää olla varovainen.', 'Paska kesä taas. Kylmää ja sataa'], 'pipeline': ['Bayes']}
Run Code Online (Sandbox Code Playgroud)

asd = request.data [“ material”]:

'Paska kesä taas. Kylmää ja sataa'
Run Code Online (Sandbox Code Playgroud)

Ane*_*pic 6

默认情况下,QueryDict 将在进行getitem调用时从列表中返回单个项目(或通过方括号访问,例如您在 中所做的request.data['material']

您可以改为使用该getlist方法返回键的所有值:https :
//docs.djangoproject.com/en/1.8/ref/request-response/#django.http.QueryDict.getlist

class ClassifyText(APIView):
    """
    Takes text snippet as a parameter and 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"])
            print("juttu", request.data.getlist("material"]))
            #create pipeline from request
            pipeline = Pipeline()
            for component_name in request.data["pipeline"]:
                pipeline.add_component(component_name)

            response = pipeline.execute_pipeline(request.data.getlist('material'))
            status_code = status.HTTP_200_OK

        except Exception as e:
            response = {"message": "Please provide a 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 is missing. Should be array of components used in analysis. Available components at /api/classifiers")

        if len(data["pipeline"]) < 1:
            raise InvalidRequest("Pipeline array is empty.")

        if "material" not in data:
            raise InvalidRequest("Material to be analyzed is missing. Please provide an array of strings.")

        if len(data["material"]) < 1:
            raise InvalidRequest("Material to be analyzed is missing, array is empty. Please provide an array of strings.")
Run Code Online (Sandbox Code Playgroud)


Neo*_*ang 5

这是因为QueryDict返回以下列表的最后一个值__getitem__

QueryDict。getitem(密钥)

返回给定键的值。如果键具有多个值,则getitem()返回最后一个值。如果键不存在,则引发django.utils.datastructures.MultiValueDictKeyError。(这是Python标准KeyError的子类,因此您可以继续捕捉KeyError。)

https://docs.djangoproject.com/zh-CN/1.8/ref/request-response/#django.http.QueryDict。getitem

如果您发布一个表单,其中一个键映射到一个列表:

d = {"a": 123, "b": [1,2,3]}
requests.post("http://127.0.0.1:6666", data=d)
Run Code Online (Sandbox Code Playgroud)

这是您在请求正文中得到的:

a=123&b=1&b=2&b=3
Run Code Online (Sandbox Code Playgroud)

由于测试方法将数据以表单形式发布,因此从request.data获得的内容是QueryDict(与request.POST相同),因此在获取request.data时将获得列表中的最后一个值。

为了获得预期的行为,请将数据以JSON格式发布到请求正文中(如@Vladir Parrado Cruz的回答)。