如何测试Django中ExportActionMixin生成的导出文件?
问题描述
我想测试Django后台中由import_export.admin.ExportActionMixin生成的导出文件,查看下载的文件内容,但测试时遇到问题:返回状态码是200,但Content-Type是text/html; charset=utf-8而非预期的text/csv,无法获取导出的文件内容。
我的Admin模型
@admin.register(MyModel) class MyModelAdmin(ExportActionMixin, admin.ModelAdmin): resource_class = MyResource
我的资源类
class MyResource(resources.ModelResource): class Meta: model = MyModel headers = ('User ID', 'name') fields = ('user__id', 'user__name') def get_export_order(self): return self.Meta.fields def get_export_headers(self): return self.Meta.headers def get_queryset(self): # 注意:此处super调用参数错误,需修正为MyResource queryset = super(MyResource, self).get_queryset() return queryset.select_related('user')
原测试代码
class MyTestCase(TestCase): def setUp(self): self.client = Client() user = User.objects.create(login="admin", email="admin@example.com", password="password") user.is_staff = True user.is_superuser = True user.save() self.client.login(username="admin", password="password") def test_import(self): url = reverse('/admin/project/mymodel') data = {'action': 'export_admin_action', 'file_format': 0, '_selected_action': 1} response = self.client.post(url, data=data, follow=True) self.assertEqual(200, response.status_code) self.assertEqual('text/csv', response['Content-Type']) self.assertTrue(response.has_header('Content-Disposition'))
问题分析与解决方案
错误原因
- Reverse用法错误:
reverse()需传入Django Admin的URL名称(格式为admin:<app_label>_<model_name>_changelist),而非直接路径字符串。 - 测试数据缺失:
_selected_action指定的ID=1不存在,需提前创建对应MyModel实例。 - Follow=True干扰响应:导出动作直接返回文件响应,
follow=True会让客户端跟随重定向,最终拿到HTML页面而非文件。 - 资源类super调用错误:原代码中
super(MyModel, self)参数错误,会触发类型异常。
修正后的测试代码
import csv from django.contrib.auth.models import User from django.test import TestCase, Client from django.urls import reverse from myapp.models import MyModel # 替换为你的实际模型路径 class MyTestCase(TestCase): def setUp(self): self.client = Client() # 创建管理员用户 self.admin_user = User.objects.create_user( username="admin", email="admin@example.com", password="password" ) self.admin_user.is_staff = True self.admin_user.is_superuser = True self.admin_user.save() self.client.login(username="admin", password="password") # 创建测试用实例 self.test_user = User.objects.create(username="testuser", id=100) self.test_model = MyModel.objects.create(user=self.test_user) def test_export_action(self): # 使用正确的Admin列表页URL url = reverse('admin:project_mymodel_changelist') # 替换为你的app_label和model_name # POST数据:_selected_action需为列表格式(支持多选) data = { 'action': 'export_admin_action', 'file_format': 0, # 0对应CSV格式 '_selected_action': [self.test_model.id], } # 不使用follow=True,直接获取原始文件响应 response = self.client.post(url, data=data) # 验证响应基本信息 self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-Type'], 'text/csv') self.assertTrue('attachment; filename=' in response['Content-Disposition']) # 解析并验证CSV内容 csv_content = response.content.decode('utf-8') reader = csv.reader(csv_content.splitlines()) rows = list(reader) # 验证表头 self.assertEqual(rows[0], ['User ID', 'name']) # 验证数据行 self.assertEqual(rows[1], [str(self.test_user.id), self.test_user.username])
关键说明
- URL名称规则:Admin页面的URL名称固定为
admin:<app_label>_<model_name>_changelist,需根据你的项目实际配置替换。 - _selected_action格式:必须传入列表(支持多选导出),不能直接传单个ID值。
- CSV内容解析:通过
response.content.decode('utf-8')将二进制响应转为字符串,再用csv.reader解析后验证表头和数据。
内容的提问来源于stack exchange,提问作者NSS
相关产品推荐
相关产品推荐

