Why its better to use .exists() method on query rather then do try-except block

Why its better to use .exists() method on query rather then do try-except block?

by

in

Both of the provided code samples achieve the same result, but they use different approaches to handle the case when the instance with the given primary key does not exist.

class Balance(models.Model):
    current_balance = models.DecimalField(_("Current Balance"), max_digits=12, decimal_places=2, default=0.00)
    last_balance = models.DecimalField(_("Last Balance"), max_digits=12, decimal_places=2, null=True)

    def save(self, *args, **kwargs):
        if self.pk:
            try:
                prev_state = Balance.objects.get(pk=self.pk)
            except Balance.DoesNotExist:
                prev_state = None
            if prev_state and self.current_balance != prev_state.current_balance:
                self.last_balance = prev_state.current_balance
        super().save(*args, **kwargs)

 

In the first version of the save() method, we use a try-except block to catch the DoesNotExist exception that is raised when the Balance.objects.get() method fails to retrieve an instance with the given primary key. If this happens, we set prev_state to None, which means that the previous state of the current_balance field is unknown.

By handling the DoesNotExist exception in this way, we can avoid the Balance matching query does not exist error when trying to update an instance that doesn’t exist.

Why don’t u consider using the .exists() method?

You could definitely use the exists() method to check if an instance with the given primary key exists in the database, like this:

class Balance(models.Model):
    current_balance = models.DecimalField(_("Current Balance"), max_digits=12, decimal_places=2, default=0.00)
    last_balance = models.DecimalField(_("Last Balance"), max_digits=12, decimal_places=2, null=True)

    def save(self, *args, **kwargs):
        if self.pk and Balance.objects.filter(pk=self.pk).exists():
            prev_state = Balance.objects.get(pk=self.pk)
            if self.current_balance != prev_state.current_balance:
                self.last_balance = prev_state.current_balance
        super().save(*args, **kwargs)

 

Using exists() before calling get() can be more efficient than just calling get() directly, since exists() only needs to check if any matching records exist in the database, whereas get() has to retrieve the entire record.

Either way, the important thing is to check if an instance with the given primary key exists before trying to retrieve or update it, to avoid the Balance matching query does not exist error.

In conclusion, what should you choose .exists() or try-except:

The first code sample uses Balance.objects.filter(pk=self.pk).exists() to check if the instance exists, and if it does, retrieves the previous state using Balance.objects.get(pk=self.pk). This approach may be more efficient because it only requires one database query to check if the instance exists and retrieve the previous state.

The second code sample uses a try-except block to handle the case when Balance.DoesNotExist is raised. This approach may be more readable and simpler to understand, but it requires two database queries if the instance exists (one for the check and one for retrieving the previous state).

Overall, the first approach may be more optimized and effective in terms of database performance, but the second approach may be more readable and easier to understand. The choice ultimately depends on your personal preference and project requirements.

 


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *