Django单元测试:如何用APIClient上传CSV文件并解决报错
解决DRF文件上传单元测试的"Missing filename"报错
我来帮你分析问题并给出修复方案:
问题背景
你在为Django REST Framework的ChartOfAccounts视图编写单元测试,用于验证CSV文件上传功能,使用了自定义的_file_upload辅助方法,但遇到了如下报错:
Missing filename. Request should include a Content-Disposition header with a filename parameter.
你的测试辅助方法代码:
@staticmethod def _file_upload(client, string, args, file_name): base_path = os.path.dirname(os.path.realpath(__file__)) with open(base_path + file_name, 'rb') as data: data = { 'file': data } response = client.post(reverse(string, args=[args]), data, format = "multipart") return response.status_code, response.data
待测试的视图代码:
class ChartOfAccounts(views.APIView): parser_classes = (JSONParser, FileUploadParser) def post(self, request, pk, *args, **kwargs): request.FILES['file'].seek(0) csv_data = CSVUtils.format_request_csv(request.FILES['file']) try: coa_data = CSVUtils.process_chart_of_accounts_csv(company, csv_data) serializer = CoASerializer(coa_data, many=True) if len(serializer.data) > 0: return Utils.dispatch_success(request, serializer.data) except Exception as e: error = ["%s" % e] return Utils.dispatch_failure(request, 'DATA_PARSING_ISSUE', error)
错误原因
你的视图配置了FileUploadParser,这个解析器要求上传的文件必须携带包含filename参数的Content-Disposition请求头。但你当前的测试代码只是直接将打开的文件对象放入data字典,Django测试客户端不会自动为该文件对象添加符合要求的请求头,因此触发了解析器的报错。
解决方案
最简便的修复方式是使用Django提供的SimpleUploadedFile构造上传文件对象,它会自动帮你处理文件名及对应的请求头信息。修改你的测试方法如下:
from django.core.files.uploadedfile import SimpleUploadedFile import os @staticmethod def _file_upload(client, string, args, file_name): base_path = os.path.dirname(os.path.realpath(__file__)) # 用os.path.join拼接路径更安全,避免不同系统的路径分隔符问题 file_path = os.path.join(base_path, file_name) with open(file_path, 'rb') as f: # 构造包含文件名、文件内容和MIME类型的上传对象 uploaded_file = SimpleUploadedFile( name=file_name, content=f.read(), content_type='text/csv' ) data = {'file': uploaded_file} response = client.post( reverse(string, args=[args]), data, format='multipart' ) return response.status_code, response.data
额外提示
顺便注意:你的视图post方法中用到了company变量,但代码里没有看到它的定义逻辑,比如是否应该通过pk参数查询获取?例如:
from django.shortcuts import get_object_or_404 # 在post方法开头添加 company = get_object_or_404(Company, pk=pk)
如果遗漏这一步,后续运行时会抛出NameError,记得补上。
内容的提问来源于stack exchange,提问作者Muthu Kumar
相关产品推荐
相关产品推荐

