在 Django 中测试自定义管理操作
Testing custom admin actions in django
我是 django 的新手,我在测试 app_model_changelist 下拉菜单中的自定义操作(例如 actions=['mark_as_read'])时遇到了问题,这是同一个下拉菜单与标准 "delete selected"。自定义操作在管理视图中工作,但我只是不知道如何在我的模拟请求中调用它,我知道我需要 post 数据但怎么说我想要 "mark_as_read" 操作完成我 posted?
的数据
我想反转变更列表 url 和 post 查询集,这样 "mark_as_read" 操作函数将处理我 post 编辑的数据。
change_url = urlresolvers.reverse('admin:app_model_changelist')
response = client.post(change_url, <QuerySet>)
只需将参数 action
与操作名称一起传递即可。
response = client.post(change_url, {'action': 'mark_as_read', ...})
选中的项目作为 _selected_action
参数传递。所以代码将是这样的:
fixtures = [MyModel.objects.create(read=False),
MyModel.objects.create(read=True)]
should_be_untouched = MyModel.objects.create(read=False)
#note the unicode() call below
data = {'action': 'mark_as_read',
'_selected_action': [unicode(f.pk) for f in fixtures]}
response = client.post(change_url, data)
我就是这样做的:
data = {'action': 'mark_as_read', '_selected_action': Node.objects.filter(...).values_list('pk', flat=True)}
response = self.client.post(reverse(change_url), data, follow=True)
self.assertContains(response, "blah blah...")
self.assertEqual(Node.objects.filter(field_to_check=..., pk__in=data['_selected_action']).count(), 0)
关于此的一些注意事项,与已接受的答案相比:
- 我们可以使用
values_list
而不是列表理解来获取 ID。
- 我们需要指定
follow=True
因为预计成功 post 将导致重定向
- 可选择断言成功消息
- 检查更改是否确实反映在数据库中。
这里是你如何使用登录和一切,一个完整的测试用例:
from django.test import TestCase
from django.urls import reverse
from content_app.models import Content
class ContentModelAdminTests(TestCase):
def setUp(self):
# Create some object to perform the action on
self.content = Content.objects.create(titles='{"main": "test tile", "seo": "test seo"}')
# Create auth user for views using api request factory
self.username = 'content_tester'
self.password = 'goldenstandard'
self.user = User.objects.create_superuser(self.username, 'test@example.com', self.password)
def shortDescription(self):
return None
def test_actions1(self):
"""
Testing export_as_json action
App is content_app, model is content
modify as per your app/model
"""
data = {'action': 'export_as_json',
'_selected_action': [self.content._id, ]}
change_url = reverse('admin:content_app_content_changelist')
self.client.login(username=self.username, password=self.password)
response = self.client.post(change_url, data)
self.client.logout()
self.assertEqual(response.status_code, 200)
只需修改以使用您的模型和自定义操作以及 运行 您的测试。
更新:如果您收到 302,您可能需要在 self.client.post()
中使用 follow=True
。
请注意,即使 POST 成功,您仍然需要测试您的操作是否成功执行了预期的操作。
这是另一种直接从管理员测试操作的方法class:
from django.contrib.auth.models import User
from django.contrib.admin.sites import AdminSite
from django.shortcuts import reverse
from django.test import RequestFactory, TestCase
from django.contrib.messages.storage.fallback import FallbackStorage
from myapp.models import MyModel
from myapp.admin import MyModelAdmin
class MyAdminTestCase(TestCase):
def setUp(self) -> None:
self.site = AdminSite()
self.factory = RequestFactory()
self.superuser = User.objects.create_superuser(username="superuser", is_staff=True)
def test_admin_action(self):
ma = MyModelAdmin(MyModel, self.site)
url = reverse("admin:myapp_mymodel_changelist")
superuser_request = self.factory.get(url)
superuser_request.user = self.superuser
# if using 'messages' in your actions
setattr(superuser_request, 'session', 'session')
messages = FallbackStorage(superuser_request)
setattr(superuser_request, '_messages', messages)
qs = MyModel.objects.all()
ma.mymodeladminaction(superuser_request, queryset=qs)
# check that your action performed the operations intended
...
我是 django 的新手,我在测试 app_model_changelist 下拉菜单中的自定义操作(例如 actions=['mark_as_read'])时遇到了问题,这是同一个下拉菜单与标准 "delete selected"。自定义操作在管理视图中工作,但我只是不知道如何在我的模拟请求中调用它,我知道我需要 post 数据但怎么说我想要 "mark_as_read" 操作完成我 posted?
的数据我想反转变更列表 url 和 post 查询集,这样 "mark_as_read" 操作函数将处理我 post 编辑的数据。
change_url = urlresolvers.reverse('admin:app_model_changelist')
response = client.post(change_url, <QuerySet>)
只需将参数 action
与操作名称一起传递即可。
response = client.post(change_url, {'action': 'mark_as_read', ...})
选中的项目作为 _selected_action
参数传递。所以代码将是这样的:
fixtures = [MyModel.objects.create(read=False),
MyModel.objects.create(read=True)]
should_be_untouched = MyModel.objects.create(read=False)
#note the unicode() call below
data = {'action': 'mark_as_read',
'_selected_action': [unicode(f.pk) for f in fixtures]}
response = client.post(change_url, data)
我就是这样做的:
data = {'action': 'mark_as_read', '_selected_action': Node.objects.filter(...).values_list('pk', flat=True)}
response = self.client.post(reverse(change_url), data, follow=True)
self.assertContains(response, "blah blah...")
self.assertEqual(Node.objects.filter(field_to_check=..., pk__in=data['_selected_action']).count(), 0)
关于此的一些注意事项,与已接受的答案相比:
- 我们可以使用
values_list
而不是列表理解来获取 ID。 - 我们需要指定
follow=True
因为预计成功 post 将导致重定向 - 可选择断言成功消息
- 检查更改是否确实反映在数据库中。
这里是你如何使用登录和一切,一个完整的测试用例:
from django.test import TestCase
from django.urls import reverse
from content_app.models import Content
class ContentModelAdminTests(TestCase):
def setUp(self):
# Create some object to perform the action on
self.content = Content.objects.create(titles='{"main": "test tile", "seo": "test seo"}')
# Create auth user for views using api request factory
self.username = 'content_tester'
self.password = 'goldenstandard'
self.user = User.objects.create_superuser(self.username, 'test@example.com', self.password)
def shortDescription(self):
return None
def test_actions1(self):
"""
Testing export_as_json action
App is content_app, model is content
modify as per your app/model
"""
data = {'action': 'export_as_json',
'_selected_action': [self.content._id, ]}
change_url = reverse('admin:content_app_content_changelist')
self.client.login(username=self.username, password=self.password)
response = self.client.post(change_url, data)
self.client.logout()
self.assertEqual(response.status_code, 200)
只需修改以使用您的模型和自定义操作以及 运行 您的测试。
更新:如果您收到 302,您可能需要在 self.client.post()
中使用 follow=True
。
请注意,即使 POST 成功,您仍然需要测试您的操作是否成功执行了预期的操作。
这是另一种直接从管理员测试操作的方法class:
from django.contrib.auth.models import User
from django.contrib.admin.sites import AdminSite
from django.shortcuts import reverse
from django.test import RequestFactory, TestCase
from django.contrib.messages.storage.fallback import FallbackStorage
from myapp.models import MyModel
from myapp.admin import MyModelAdmin
class MyAdminTestCase(TestCase):
def setUp(self) -> None:
self.site = AdminSite()
self.factory = RequestFactory()
self.superuser = User.objects.create_superuser(username="superuser", is_staff=True)
def test_admin_action(self):
ma = MyModelAdmin(MyModel, self.site)
url = reverse("admin:myapp_mymodel_changelist")
superuser_request = self.factory.get(url)
superuser_request.user = self.superuser
# if using 'messages' in your actions
setattr(superuser_request, 'session', 'session')
messages = FallbackStorage(superuser_request)
setattr(superuser_request, '_messages', messages)
qs = MyModel.objects.all()
ma.mymodeladminaction(superuser_request, queryset=qs)
# check that your action performed the operations intended
...