Search code examples
djangodjango-modelsdjango-tests

Django test deleteview for model with overwritten 'delete' method


I am writting tests for a django application that contains multiple deleteviews. I test all deleteviews with variations of the following code:

#Object exists to begin with
response = self.client.get(reverse('roldelete', kwargs={'pk': self.role.pk}))
self.assertEqual(response.status_code, 200)

#Object Can be deleted can be posted
response = self.client.post(reverse('roldelete', kwargs={'pk': self.role.pk}))
self.assertEqual(response.status_code, 302)

#Object is actually deleted
response = self.client.get(reverse('roldelete', kwargs={'pk': self.role.pk}))
self.assertEqual(response.status_code, 404)

#Query returns an empty result
self.assertFalse(Role.objects.filter(pk=self.role.pk).exists())

All of this is working fine, however, in on of my models I've overwritten the default 'delete' method. Basically everytime I delete a 'TenantPurchase' object I want to check for the existence of a linked 'PurchaseRequest' object and delete it as well. I wrote the following code to do so, within the TenantPurchase model:

def delete(self, *args, **kwargs):
    try:

        purchase_user = self.user
        purchase_arrangement_period = self.item

        #Import here to avoid circular import
        from arrangement.models import ArrangementBuyRequest

        linked_buy_request = ArrangementBuyRequest.objects.filter(
            user=purchase_user,
            arrangement_period=purchase_arrangement_period) \
            .order_by('request_date').last()

        linked_buy_request.delete()
    except (ArrangementBuyRequest.DoesNotExist, AttributeError) as e:
        pass

    super(TenantPurchase, self).delete(*args, **kwargs)

When I test manually on our development server, I behaves as it should. Linked buy Requests are deleted and no errors are thrown.

However, all my Unittests for this model fail. It passes the first three tests (assert 200, assert 302, assert 404)

But a direct query shows that the object still exists

self.assertFalse(
        TenantPurchase.objects.filter(tenant=self.tenant, user=self.user, item_id=self.period.pk).exists())


Traceback (most recent call last):
(...), line 105, in test_linked_request_deleted

self.assertFalse(ArrangementBuyRequest.objects.filter(user=self.user,         arrangement_period=self.period).exists())
AssertionError: True is not false

Ditto for the linked buyrequest:

# Check if the related buyrequest has been deleted as well
    self.assertFalse(ArrangementBuyRequest.objects.filter(user=self.user, arrangement_period=self.period).exists())

Traceback (most recent call last):
(...), line 80, in test_tenant_purchase_deleted
TenantPurchase.objects.filter(tenant=self.tenant, user=self.user, item_id=self.period.pk).exists())
AssertionError: True is not false

Since the only difference between this situation and all the other (passing) tests is the overwritten 'delete' method in the model, is suscept that the problem comes from that part (perhaps its not loaded correctly in the tests) But I cant find the bug that it causing the test to fail. It doesnt help that everything works just fine on our development server, making it difficult to pinpoint the bug.

Does anyone have an idea what I am missing?


Solution

  • stumbled on this while troublshooting some of my own issues and just wanted to point you to this answer. When objects are deleted via QuerySet operations (aka any bulk operation, delete all from the admin, etc) Django doesn't call the model delete function and interacts directly with the table. The linked answer provides an example on how to get around this and seems like it might be what you are/were looking for.