django - 获取Typeerror:在django rest框架中编写测试用例以输入请求文件时,无法将str连接到字节?
问题描述
我正在做一个项目,我可以添加一个 csv 来将衬衫详细信息上传到数据库。
我编写了一个视图集,该视图集从 django rest 框架中的 request.data 获取衬衫 csv 文件输入,并且正在为此编写一个测试用例。虽然,在编写测试用例时,我没有创建单独的 csv 文件,而是从测试用例中的 pandas 数据帧创建了一个 csv,并将其转换为 TextIOWrapper 以作为请求数据传递。这样做会引发以下错误:
File "/Users/prasoon/projects/shirt_details/post_shirt_csv/tests/test_post_shirt_dataset.py", line 175, in test_shirt_dataset_post
response = self.api_client.post(reverse('post-shirt-csv-dataset', kwargs={'session_id': self.session.id}), {'csv_files': [fp1, fp2]})
File "/Users/prasoon/projects/venv/lib/python3.6/site-packages/rest_framework/test.py", line 300, in post
path, data=data, format=format, content_type=content_type, **extra)
File "/Users/prasoon/projects/venv/lib/python3.6/site-packages/rest_framework/test.py", line 212, in post
data, content_type = self._encode_data(data, format, content_type)
File "/Users/prasoon/projects/venv/lib/python3.6/site-packages/rest_framework/test.py", line 184, in _encode_data
ret = renderer.render(data)
File "/Users/prasoon/projects/venv/lib/python3.6/site-packages/rest_framework/renderers.py", line 920, in render
return encode_multipart(self.BOUNDARY, data)
File "/Users/prasoon/projects/venv/lib/python3.6/site-packages/django/test/client.py", line 198, in encode_multipart
lines.extend(encode_file(boundary, key, item))
File "/Users/prasoon/projects/venv/lib/python3.6/site-packages/django/test/client.py", line 247, in encode_file
to_bytes(file.read())
File "/Users/prasoon/projects/venv/bin/../lib/python3.6/codecs.py", line 320, in decode
data = self.buffer + input
TypeError: can't concat str to bytes
当我打开一个文件并传递它而不是创建字符串时,这个东西就起作用了。下面会更清楚:
测试文件是:
class TestPostNewDataset(TestCase):
@classmethod
def setUpTestData(cls):
cls.user = CurrentUserFactory()
cls.test_data1 = {"no":[1,2,3],"colour":["Red","Blue","Gray"],"Size":["XL","L","M"],"Brand":["Nike","Polo","Adidas"],"Price":[800,600,1000]}
cls.test_data2 = {"no":[1,2,3],"colour":["Black","Blue","Red"],"Size":["S","M","L"],"Brand":["Nike","Levis","Nike"],"Price":[2000,900,1000]}
cls.test_df1 = pd.DataFrame(cls.test_data1)
cls.test_df2 = pd.DataFrame(cls.test_data2)
cls.session = CurrentSessionFactory(user=cls.user)
def test_shirt_dataset_post(self):
"Test request to post shirt dataset"
fp1 = TextIOWrapper(StringIO(self.test_df1))
fp2 = TextIOWrapper(StringIO(self.test_df2))
response = self.api_client.post(reverse("post-shirt-csv-dataset", kwargs={'session_id':self.session.id}),{'csv_files':[fp1,fp2]})
self.assertEqual(response.status_code,status.HTTP_200_OK)
对应的视图文件为:
class CsvReadViewset(viewsets.ModelViewSet):
authentication_classes = (BasicAuthentication,)
permission_classes = (IsAuthenticated,)
serializer_class = ShirtSerializer
queryset = Shirt.objects.all()
def addShirt(self,request,*args,**kwargs):
csvs = request.data["csv_files"]
current_session = CurrentSession.objects.get(session_id=kwargs["session_id"])
for shirt_csv in csvs:
shirt_df = pd.read_csv(shirt_csv)
for index,row in short_df.iterrows():
s = Shirt(colour=row["colour"],
brand=row["Brand"],
size=row["Size"],
price=row["Price"],
created_in=current_session)
s.save()
return Response(status=status.HTTP_200_OK)
有趣的是,当测试用例将单独的文件作为输入时,它可以正常工作。也就是说,如果我将 test_shirt_dataset_post 替换为以下内容:
def test_shirt_dataset_post(self):
with open(os.path.join(os.path.abspath(__file__ + "/../"), 'shirtcsv1.csv')) as fp1, open(os.path.join(os.path.abspath(__file__ + "/../"), 'shirtcsv2.csv')) as fp2:
response = self.api_client.post(reverse("post-shirt-csv-dataset",kwargs={'session_id':self.session.id}),{'csv_files':[fp1,fp2]})
self.assertEqual(response.status_code,status.HTTP_200_OK)
预期的结果是工作的测试用例。但是,这里它会抛出一个错误,如图所示。添加TextIOWrapper的原因是因为fp in的类型with open(....) as fp
是'_io.TextIOWrapper'。但是,它会引发此错误。任何帮助将不胜感激。
解决方案
您可以使用 io.BytesIO 发送编码的字节流:
def test_shirt_dataset_post(self):
"Test request to post shirt dataset"
fp1 = BytesIO(self.test_df1.to_csv().encode('utf-8'))
fp2 = BytesIO(self.test_df2.to_csv().encode('utf-8'))
response = self.api_client.post(reverse("post-shirt-csv-dataset", kwargs={'session_id':self.session.id}),{'csv_files':[fp1,fp2]})
self.assertEqual(response.status_code,status.HTTP_200_OK)
推荐阅读
- github-api - GitHub-Actions: 创建 GitHub-Release 草稿时触发
- jquery - Datatables 服务器端在 localhost 上工作正常,但在 Godaddy 上托管后出现以下错误
- webpack - node-sass 未应用来自 node_modules 的样式
- php - 我还想在父类别中显示子类别的产品
- asp.net-core - AzureAD 客户端密码在 dotnetcore 应用程序中已过期 - 错误代码:AADSTS7000222 - 如何更新?
- c# - 在 asp.net 中授权角色
- ubuntu - 如何在 VSCode 中更改光标?
- javascript - 当您将鼠标悬停在甜甜圈的左/右上方时,Chart.js 甜甜圈图未显示工具提示
- ios - 在 iOS GCD 中调用 DispatchQueue.main.async 的成本
- opengl-es - glsl 可以支持的最大整数(无符号整数)值是多少?