2

Lets consider I am trying to find if a user with primary key 20 exists or not? I can do this in 2 ways.

The First one :

try:
   user = User.objects.get(pk=20)
except User.DoesNotExist:
   handle_non_existent_user()

The other way could be :

users = User.objects.filter(pk=20)
if not users.exists():
   handle_non_existent_user()

Which is better method to do check existence?

This might be related to this : What is the best way to check if data is present in django? However, people favoured the first method because of specified examples did not had the reference of model queryset.

Also in the answer of following question : what is the right way to validate if an object exists in a django view without returning 404? It is largely based because we are not getting the reference of object in question.

Anshul Sharma
  • 327
  • 4
  • 14
  • 1
    `exists()` exists for only one reason. Please use it. In some cases, such as when you plan to evaluate the queryset anyways, use `bool(queryset)` instead of `exists()` ([from the docs](https://docs.djangoproject.com/en/dev/ref/models/querysets/#exists)) – Jedi Jul 18 '17 at 05:31

2 Answers2

2

TLDR: For cases when you almost always sure that the object is db it is better to use try:get for cases when there is 50% chance that object doesn't exists then it is better to use if:filter.exists

It really depends on code context. For example there are cases when if statement is better than try/except Using try vs if in python

So for your question it is the same Difference between Django's filter() and get() methods. get method underneath calls filter

https://github.com/django/django/blob/stable/1.11.x/django/db/models/query.py#L366

def get(self, *args, **kwargs):
    """
    Performs the query and returns a single object matching the given
    keyword arguments.
    """
    clone = self.filter(*args, **kwargs)
    if self.query.can_filter() and not self.query.distinct_fields:
        clone = clone.order_by()
    num = len(clone)
    if num == 1:
        return clone._result_cache[0]
    if not num:
        raise self.model.DoesNotExist(
            "%s matching query does not exist." %
            self.model._meta.object_name
        )
    raise self.model.MultipleObjectsReturned(
        "get() returned more than one %s -- it returned %s!" %
        (self.model._meta.object_name, num)
    )

So in case when you use filter with exists. It will do almost the same code because exists underneath does this

def exists(self):
    if self._result_cache is None:
        return self.query.has_results(using=self.db)
    return bool(self._result_cache)

And as you can see filter.exists will execute less code and should work faster, but it doesn't return you an object.

Sardorbek Imomaliev
  • 14,861
  • 2
  • 51
  • 63
1

The first one is the best way in my opinion because if I ever forget to check whether the user exists or not, it will give me an error even if I don't use the try / except clause.

Also, get was made specifically to get ONE item only.

MiniGunnR
  • 5,590
  • 8
  • 42
  • 66