how to catch the MultipleObjectsReturned error in django

38,559

Solution 1

This isn't the best practice. You can technically do this without using exceptions. Did you intend to use Location and Car in this example?

You can do this:

Location.objects.filter(name='Paul').order_by('id').first()

I strongly suggest you read the Django QuerySet API reference.

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

To answer your question about where the exception exists -- you can always access these QuerySet exceptions on the model itself. E.g. Location.DoesNotExist and Location.MultipleObjectsReturned. You don't need to import them if you already have the model imported.

Solution 2

Use a filter:

Location.objects.filter(name='Paul').first()

Or import the exception:

from django.core.exceptions import MultipleObjectsReturned
...
try:
    Location.objects.get(name='Paul')
except MultipleObjectsReturned:
    Location.objects.filter(name='Paul').first()

Solution 3

This is more pythonic way to do it.

try:
    Location.objects.get(name='Paul')
except Location.MultipleObjectsReturned:
    Location.objects.filter(name='Paul')[0]

Solution 4

Actually, even if we use MyModel.objects.get_or_create(...), there is still chances for creation of multiple instances due to race conditions. So, when we have to use MyModel.objects.get or MyModel.objects.get_or_create, we still have to expect return of multiple objects.

To handle this:

from django.core.exceptions import MultipleObjectsReturned

try:
    obj,is_created=MyModel.objects.get_or_create(....)
except MultipleObjectsReturned as e:
    # handle the case as you need here
    pass

Solution 5

Use get when you know there is only one object that matches your query. If no items match the query, get() will raise a DoesNotExist exception. If multiple items matches the query, get() will raise a MultipleObjectsReturned exception. Use get() like this:

try:
  one_entry = Entry.objects.get(blog=2000)
except Entry.DoesNotExist:
  # query did not match to any item.
  pass
except Entry.MultipleObjectsReturned:
  # query matched multiple items.
  pass
else:
  # query matched to just one item
  print(one_entry)
Share:
38,559
Tom
Author by

Tom

Noobie, very newwww

Updated on November 25, 2021

Comments

  • Tom
    Tom over 2 years

    Is it possible to catch the MultipleObjectsReturned error in Django?

    I do a searchquery and if there are more than one objects I want that the first in the list will be taken so I tried this:

    try:
        Location.objects.get(name='Paul')
    except MultipleObjectsReturned:
        Location.objects.get(name='Paul')[0]
    

    However, it exists in the doc though

    global variable MultipleObjectsReturned does not exist

  • Tom
    Tom over 8 years
    yeah true! sorry, meant Location both times. Why is using exceptions not the best practice?
  • veggie1
    veggie1 over 8 years
    Then what you probably want is just Location.objects.filter(name='Paul').order_by('id').first(). It returns None if there isn't a record with that name. I updated the answer. Using exceptions in this case is unneccessary. Instead of causing an exception to be thrown, you can still have a happy path without raising any errors.
  • RemcoGerlich
    RemcoGerlich over 7 years
    This isn't actually an answer to the question.
  • RemcoGerlich
    RemcoGerlich over 7 years
    You mean filter, but at least it does answer how to catch the exception.
  • Vaseem Ahmed Khan
    Vaseem Ahmed Khan over 7 years
    @RemcoGerlich yes it filters or return object according to query. get return object whereas .filter returns queryset.
  • AlanSE
    AlanSE about 7 years
    @VaseemAhmedKhan The answer should be updated to do Location.objects.filter(name='Paul')[0], otherwise the except block will result in the same exception being thrown. You need a queryset because that contains the logic about which object to return, for instance Location.objects.get(name='Paul').order_by('age')[0] will return the youngest Paul in the database. This is how you return the correct Paul, according to your business logic.
  • jojo
    jojo over 6 years
    Note: Location.objects.get(name='Paul')[0] will raise MultipleObjectsReturned again. Use Location.objects.filter(name='Paul').first() instead.
  • lcary
    lcary almost 6 years
    "This isn't the best practice." Are you sure catching the exception isn't best practices? I think it might be best practice in Python. According to "EAFP" in docs.python.org/3/glossary.html, I think stackoverflow.com/a/32173014/2573242 is the correct answer here.
  • Paulo Fabrício
    Paulo Fabrício almost 5 years
    It doesn't work in older versions of Django like 1.5. Using first() gives AttributeError. I had to import MultipleObjectsReturned instead.
  • Greg Schmit
    Greg Schmit over 4 years
    @AlanSE No, the exception block will not throw the same exception. It might throw a DoesNotExist exception, but not MultipleObjectsReturned.