Python Django请求数据返回str而不是list
我正在用Django和REST框架开发RESTAPI。我有一个端点,它使用这种json接收POST请求:Python Django请求数据返回str而不是list,python,django,django-rest-framework,Python,Django,Django Rest Framework,我正在用Django和REST框架开发RESTAPI。我有一个端点,它使用这种json接收POST请求: { "pipeline": ["Bayes"], "material": [ "Rakastan iloisuutta!", "Autojen kanssa pitää olla varovainen.", "Paska kesä taas. Kylmää ja sataa"
{
"pipeline": ["Bayes"],
"material": [
"Rakastan iloisuutta!",
"Autojen kanssa pitää olla varovainen.",
"Paska kesä taas. Kylmää ja sataa"
]
}
这是一个机器学习分析api,json告诉我们使用贝叶斯分类器来提供字符串并返回结果。当我通过post请求手动测试它时,它工作得很好。然而,当我试图编写单元测试时,它就崩溃了。我有以下测试:
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)
测试每次都失败,因为后一个断言给出“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.")
在本例中,给出我请求中列表的最后一个条目
“Paska kesätaas.Kylmäja sataa”
然而,当我检查request.data的内容时,它显示了一个querydict,其中列出了请求中的管道和材料。为什么在调用request.data[“material”]时获取字符串而不是物料列表?是否有什么我忘记了,我必须指定某种序列化程序?为什么它在正常执行期间工作,但在测试中不工作
我在Python3中使用Django 1.8。此外,我没有将视图绑定到任何特定的模型
最后,当我将断点放入视图时,我的调试器显示了以下内容:
请求.数据:
QueryDict: {'material': ['Rakastan iloisuutta!', 'Autojen kanssa pitää olla varovainen.', 'Paska kesä taas. Kylmää ja sataa'], 'pipeline': ['Bayes']}
asd=请求。数据[“物料”]:
在测试中尝试这样做:
import json
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'),
json.dumps({
"pipeline": ["Bayes"],
"material": [
"Rakastan iloisuutta!",
"Autojen kanssa pitää olla varovainen.",
"Paska kesä taas. Kylmää ja sataa",
]
}),
content_type='application/json'
)
self.assertTrue(status.is_success(response.status_code))
self.assertEqual(response.data[0], 1)
如果您将数据作为json发送,它可能会工作。这是因为QueryDict在
\uuuu getitem\uuuu
中返回列表的最后一个值:
QueryDict.getitem(键)
返回给定键的值。如果键有多个值,getitem()返回最后一个值。如果键不存在,则引发django.utils.datastructures.MultiValue DictKeyError。(这是Python标准KeyError的一个子类,因此您可以坚持捕获KeyError。)
如果发布一个表单,其中键映射到列表:
d = {"a": 123, "b": [1,2,3]}
requests.post("http://127.0.0.1:6666", data=d)
这是您在请求正文中得到的内容:
a=123&b=1&b=2&b=3
由于测试方法将数据作为表单发布,因此从request.data获得的是QueryDict(与request.post相同),因此在获取request.data时,您将获得列表中的最后一个值
要获得预期的行为,请将数据作为JSON发布到请求正文中(如@Vladir Parrado Cruz的回答) 默认情况下,在执行
getitem
调用(或通过方括号进行访问,如您在request.data['material']
中所做的操作)时,QueryDict将从列表中返回单个项
您可以使用getlist
方法返回键的所有值:class ClassifyText(APIView):
"""
将文本片段作为参数并返回分析结果。
"""
身份验证\类=(authentication.TokenAuthentication,)
权限\类=(permissions.AllowAny,)
解析器\类=(JSONParser,)
def post(自我、请求、格式=无):
尝试:
自我验证发布数据(request.data)
打印(“juttu”,请求。数据[“材料”])
打印(“juttu”,request.data.getlist(“material”]))
#从请求创建管道
管道=管道()
对于request.data[“pipeline”]中的组件名称:
管道。添加组件(组件名称)
response=pipeline.execute_pipeline(request.data.getlist('material'))
状态代码=status.HTTP\u 200\u正常
例外情况除外,如e:
响应={“消息”:“请提供正确的数据。”,
“错误”:str(e)}
status\u code=status.HTTP\u 400\u错误请求
返回响应(响应,状态=状态\代码)
定义验证后数据(自身、数据):
如果“管道”不在数据中:
raise InvalidRequest(“缺少管道字段。应为分析中使用的组件数组。可在/api/classifiers处找到组件”)
如果len(数据[“管道])<1:
raise InvalidRequest(“管道数组为空”)
如果“材料”不在数据中:
raise InvalidRequest(“缺少要分析的材料。请提供字符串数组。”)
如果len(数据[“材料])<1:
raise InvalidRequest(“缺少要分析的材料,数组为空。请提供字符串数组。”)
Pipeline.execute\u Pipeline做什么?它处理材料。然而,我相当确定问题是在这之前,因为调试程序向我显示,在测试期间,execute_管道实际上获取字符串而不是列表(它应该获取列表)。另外,如果我创建了一个类似asd=request.data[“material”]的表达式,那么根据调试器,asd包含列表的最后一个条目(字符串)。如果手动测试,它不会得到它吗?当这两个示例(打印)行位于彼此下方时,调试器输出是什么?感谢您的解释。看起来昨天晚上我浏览文档时太累了。我最终使用了@Vladir Parrado Cruz的答案。
d = {"a": 123, "b": [1,2,3]}
requests.post("http://127.0.0.1:6666", data=d)
a=123&b=1&b=2&b=3
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.")