2

I'm using Django 3.2b1 and pytest 6.2.2.

I'm trying to use pytest to write a test to make sure admins are able to delete objects using the delete_selected action. My test looks like this:

def test_delete_mymodel_action(admin_client):
    objs_to_delete = [
        MyModel.objects.create(),
        MyModel.objects.create(),
    ]
    MyModel.objects.create() # Don't delete this obj

    data = {
        "action": "delete_selected",
        "_selected_action": [str(f.pk) for f in objs_to_delete],
        "post": "yes",  # Skip the confirmation page
    }
    change_url = reverse("admin:myapp_mymodel_changelist")
    admin_client.post(change_url, data)

    assert MyModel.objects.count() == 1

The code works and ends in a 302 redirect back to the changelist, but the objects don't get deleted. The response is:

test_delete_mymodel_action - assert 3 == 1

The reason I'm testing this is that certain code can cause the delete_selected action to fail. For example, if you override get_queryset() in the ModelAdmin and return a queryset that uses distinct(), the delete_selected action will fail.

Here the code from a delete confirmation page in Django Admin:

<form method="post">
    <input type="hidden" name="csrfmiddlewaretoken" value="VCR7vjVYcb2xuMdPUknotrealViwj92wgZrT21k6RbqGxXNlQnCORU1Fp6NzKhn64">
    <div>
        <input type="hidden" name="_selected_action" value="31418">
        <input type="hidden" name="_selected_action" value="31412">
        <input type="hidden" name="action" value="delete_selected">
        <input type="hidden" name="post" value="yes">
        <input type="submit" value="Yes, I’m sure">
        <a href="#" class="button cancel-link">No, take me back</a>
    </div>
</form>

Some helpful references:

  1. Django's delete_selected() method.
  2. Testing custom admin actions in django SO Answer
Webucator
  • 2,397
  • 24
  • 39

1 Answers1

0

I just run into the same problem. I noticed I was logged in with the wrong user.

My thought process:

  • 302 doesn't indicate there's anything wrong, there was no content in the response either (b'')
  • I added follow=True to self.client.post. The response was 200 and there were no objects, so I assumed it worked correctly but it failed on assertion
  • I put breakpoint in delete_selected of django.contrib.admin.actions and n = queryset.count() was 0.
  • If it's not listed after but there's nothing to delete (n = 0), let's see if there was something to be deleted before.
    response = self.client.get(reverse("admin:myapp_mymodel_changelist"))
    self.assertContains(response, obj.id)

nope!

So the problem with your test is that these objects can't be deleted because they can't be retrieved, probably due to some filtering.

Note, Django admin won't raise 404 if the object has not been found.

Tom Wojcik
  • 5,471
  • 4
  • 32
  • 44