Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle "matching query does not exist" when getting an object

When I want to select objects with a get() function like

personalProfile = World.objects.get(ID=personID)

If get function doesn't return find a value, a "matching query does not exist." error occurs.

If I don't need this error, I'll use try and except function

try:
   personalProfile = World.objects.get(ID=personID)
except:
   pass

But I think this is not the best way since I use

except:
      pass

Please recommend some idea or code sample to fight with this issue

like image 433
zHepHirotHz Avatar asked Oct 14 '15 07:10

zHepHirotHz


2 Answers

That depends on what you want to do if it doesn't exist..

Theres get_object_or_404:

Calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.

get_object_or_404(World, ID=personID)

Which is very close to the try except code you currently do.

Otherwise theres get_or_create:

personalProfile, created = World.objects.get_or_create(ID=personID)

Although, If you choose to continue with your current approach, at least make sure the except is localised to the correct error and then do something with that as necessary

try:
   personalProfile = World.objects.get(ID=personID)
except MyModel.DoesNotExist:
    raise Http404("No MyModel matches the given query.")

The above try/except handle is similar to what is found in the docs for get_object_or_404...

like image 77
Sayse Avatar answered Nov 15 '22 09:11

Sayse


A get_or_none() function has been proposed, multiple times now. The rejection notice is feature creep, which you might or might not agree with. The functionality is present --with slightly different semantics-- in the first() queryset method.

But first things first:

The manager throws World.DoesNotExist, a specialized subclass of ObjectDoesNotExist when a World object was not found:

try:
    personalProfile = World.objects.get(ID=personID)
except World.DoesNotExist:
    pass

There's also get_object_or_404() which raises a Http404 exception when the object was not found.

You can also roll your own get_or_none(). A possible implementation could be:

def get_or_none(queryset, *args, **kwargs):
    try:
        return queryset.get(*args, **kwargs)
    except ObjectDoesNotExist:
        return None

Note that this still raises MultipleObjectsReturned when more than one matching object is found. If you always want the first object regardless of any others, you can simplify using first(), which returns None when the queryset is empty:

def get_or_none(queryset, *args, **kwargs):
    return queryset.filter(*args, **kwargs).first()

Note however, for this to work reliably, you need a proper order for objects, because in the presence of multiple objects first() might be non-deterministic (it probably returns the first object from the database index used to filter the query and neither indexes not the underlying tables need be sorted or even have a repeatable order).

Use both, however, only when the use of the object to retrieve is strictly optional for the further program flow. When failure to retrieve an object is an error, use get_object_or_404(). When an object should be created when it does not exist, use get_or_create(). In those cases, both are better suited to simplify program flow.

like image 44
dhke Avatar answered Nov 15 '22 11:11

dhke