Testing custom admin actions in django

2019-03-23 13:46发布

问题:

I'm new to django and I'm having trouble testing custom actions(e.g actions=['mark_as_read']) that are in the drop down on the app_model_changelist, it's the same dropdown with the standard "delete selected". The custom actions work in the admin view, but I just dont know how to call it in my mock request, I know I need to post data but how to say I want "mark_as_read" action to be done on the data I posted?

I want to reverse the changelist url and post the queryset so the "mark_as_read" action function will process the data I posted.

change_url = urlresolvers.reverse('admin:app_model_changelist')
response = client.post(change_url, <QuerySet>)

回答1:

Just pass the parameter action with the action name.

response = client.post(change_url, {'action': 'mark_as_read', ...})

Checked items are passed as _selected_action parameter. So code will be like this:

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)


回答2:

This is what I do:

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)

A few notes on that, comparing to the accepted answer:

  • We can use values_list instead of list comprehension to obtain the ids.
  • We need to specify follow=True because it is expected that a successfull post will lead to a redirect
  • Optionally assert for a successful message
  • Check that the changes indeed are reflected on the db.


回答3:

Here is how you do it with login and everything, a complete test case:

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)

Just modify to use your model and custom action and run your test.

UPDATE: If you get a 302, you may need to use follow=True in self.client.post().