31

Which of the two is a better and efficient option to check if an instance exists. There can only be one record returned at most.

1) Use the filter option and see if it exists:

x = MyObject.objects.filter(someField=someValue).count()
if x:
    #Instance exists

2) Use get and check for exception:

try:
    x = MyObject.objects.get(someField=someValue)
except MyObject.DoesNotExist:
    #Do Something

Which of the above mentioned methods is efficient or more "Djangoic" ?

Aswin Murugesh
  • 10,831
  • 10
  • 40
  • 69

3 Answers3

53

An even better approach would be to use .exists() to check if a particular instance exists or not.

MyObject.objects.filter(someField=someValue).exists() # return True/False

From the .exists() docs:

It returns True if the QuerySet contains any results, and False if not. This tries to perform the query in the simplest and fastest way possible, but it does execute nearly the same query as a normal QuerySet query.

exists() is useful for searches relating to both object membership in a QuerySet and to the existence of any objects in a QuerySet, particularly in the context of a large QuerySet.

Some examples from the docs:

Example-1: To find whether a model with unique field is a member of QuerySet

The most efficient method of finding whether a model with a unique field (e.g. primary_key) is a member of a QuerySet is:

entry = Entry.objects.get(pk=123)

if some_queryset.filter(pk=entry.pk).exists(): # faster
    print("Entry contained in queryset")

which will be faster than the following which requires evaluating and iterating through the entire queryset:

if entry in some_queryset: # slower 
   print("Entry contained in QuerySet")

Example-2: Finding whether a queryset contains any items

To find whether a queryset contains any items, below method

if some_queryset.exists(): # faster
    print("There is at least one object in some_queryset")

will be faster than:

if some_queryset: # slower
    print("There is at least one object in some_queryset")

... but not by a large degree (hence needing a large queryset for efficiency gains).

What if i also want to use the object if it exists?

If you want to use the object also if it exists, then using .exists() is not efficient as then you will perform 2 queries. First query will be to check for the existence and 2nd query will be to get the object.

phoenix
  • 7,988
  • 6
  • 39
  • 45
Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
  • So is using exception a bad idea? – Aswin Murugesh Sep 29 '15 at 15:55
  • @AswinMurugesh I actually prefer duck typing for single instance lookup, see my answer – Alvaro Sep 29 '15 at 15:56
  • 1
    @AswinMurugesh If you only need to check if an instance exists or not, then this is the best approach. This method is even suggested in the docs to be used to check for the existence of an instance. – Rahul Gupta Sep 29 '15 at 15:59
  • 4
    Note that using `MyObject.objects.filter(foo='bar').exists()` still fetches the entire object with all of its fields from the database. It can be faster using `MyObject.objects.only('foo').filter(foo='bar').exists()` which changes the query to only fetch the same column being filtered. This is especially helpful if the field you're filtering is the primary key or has an index, as it allows the database to optimize to an index-only query. YMMV depending on the particular database underlying the model. – joe p Feb 13 '21 at 13:03
0

I would say use the exists() on the filtered queryset like this,

MyObject.objects.filter(someField=someValue).exists()

The Django docs mostly encourage using exists(), instead of alternative methods. You can read more about this here.

https://docs.djangoproject.com/en/1.8/ref/models/querysets/

Pieter Hamman
  • 1,532
  • 18
  • 18
0

It depends on you want to get one record or many

One need to include them in try and except blocks if you need to check existence in a pythonic way

try: 
  instance = MyModel.objects.all().get(condition) 
  #can continue to use instance  
except MyModel.DoesNotExist: 
  #do something if model does not exist  
  Print(“model instances doesn't exist”)  

If you're using a filter or for getting all instances

instances = MyModel.objects.all().filter(condition)  
If instances: 
  #if list of instances have Atleast one instance  
  Pass 
else: 
  #do something if model does not exist  
  Print(“model instances doesn't exist”)