how to handle try for possible object not existing in django - python

I have an object that may or may not exist. Due to this fact I have wrapped the statement in a try / except block.
try:
generic_type = ContentType.objects.get_for_model(myentity)
my_object = MyObject.objects.filter(content_type__pk=generic_type.id, object_id=myentity.id)[0]
except:
The reason I ask is because I have nothing to put in the Except condition in this situation, but django/python requires it.
Is this the proper way to handle this situation? If it is, what should I put after the Except?

You can use the pass statement anywhere a statement is required when you want to do nothing, although you should specify the actual exception to catch.
except WhateverExceptionGetsRaised:
pass

If you are retrieving an object based on "PK" then it is only going to return one object. There isn't a need for multiple filters. Instead of:
my_object = MyObject.objects.filter(content_type__pk=generic_type.id, object_id=myentity.id)[0]
You can use:
my_object = MyObject.objects.get(content_type__pk=generic_type.id, '')
You would use this if you want it to return nothing hence the double single quotes if it fails to get the first object specified. This may be a more concise answer than an try/except pattern. Also, using:
filter()[0] vs. get()
will both return one object, but filter()[0] returns a QuerySet object type, where as get() returns the object only, so this is another thing to consider.

Related

How to make a function return nothing?

I have a function called crawl which will return a link to a website. Then I do something like:
found.append(crawl()) (found is a list)
This works fine as long as crawl returns a valid link, but sometimes it does not return anything. So a value of None gets added to the list.
So my question is that, is it possible to return something from crawl that will not not add anything to the list?
In Python nothing is something: None. You have to use if-condition:
link = crawl()
if link is not None:
found.append(link)
or let crawl return a list, which can contain one or zero elements:
found.extend(crawl())
What you could do is to pass the list in to the crawl function and if there is anything to add append it otherwise not. Something like:
def crawl(found):
""" Add results to found list """
# do your stuff saving to result
if result is not None:
found.append(result)
# Call this as
crawl(found)
This is not possible directly.
You can test for a None being returned though, using the following code.
returned_link = crawl()
if returned_link is not None:
found.append(returned_link)
If a function returns it has to return an object, even if that object is None. However, there is another answer being overlooked, and that is to raise an exception rather than returning None.
As other people point out, one approach is to check if the returned object is None before appending it to the list:
link = crawl()
if link is not None:
found.append(link)
The other approach is to define some exception, perhaps WebsiteNotFoundError, and have crawl execute raise WebsiteNotFoundError instead of return None. Then you can write:
try:
found.append(crawl())
except WebsiteNotFoundError:
pass # or take appropriate action
The advantage of the exception handling approach is that it is generally faster than checking for None if returning None is a relatively rare occurrence compared to returning a valid link. Depending on the use, it may be more readable in the sense that the code naturally explains what is going wrong with the function.

marching query does not exist in if statement

well go to the question. I make this query:
Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)
This works perfect, but when i put this in a if statement, like this:
if(Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)):
I have a problem, when the query returns a object Puntuaciones i haven't any problems, but when there isn't a result it throws me:
Exception Value: Puntuaciones matching query does not exist.
So my question is, How i can do a if statement for a query if this query can be unsuccessful.
I try with Q objects, with exists()(this just works for querysets... I dont know how make it work. Any suggestion? Thank you
get() is either returning an object or throws ObjectDoesNotExist exception, catch it with the help of try/except:
try:
Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)
# do something if object was found
except Puntuaciones.DoesNotExist:
# do smth if nothing found
Another options is to use exists():
if Puntuaciones.objects.filter(bar__id=b, usuario=v.usuario2).exists():
# do something if object was found
I would suggest a try: except: pair. That way, when the exception is triggered, you will be in the appropriate location to perform the code. Note that you really should use the correct exception type in the setup. Note that if you want to skip processing in the except, you need to put in an explicit pass (python noop) statement. Otherwise you will get an indentation error.
try:
if(Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)):
# put code in here
pass # dummy statement to be replaced by actual code.
except:
# Put exception code here.
pass

Idiomatic/fast Django ORM check for existence on mysql/postgres

If I want to check for the existence and if possible retrieve an object, which of the following methods is faster? More idiomatic? And why? If not either of the two examples I list, how else would one go about doing this?
if Object.objects.get(**kwargs).exists():
my_object = Object.objects.get(**kwargs)
my_object = Object.objects.filter(**kwargs)
if my_object:
my_object = my_object[0]
If relevant, I care about mysql and postgres for this.
Why not do this in a try/except block to avoid the multiple queries / query then an if?
try:
obj = Object.objects.get(**kwargs)
except Object.DoesNotExist:
pass
Just add your else logic under the except.
django provides a pretty good overview of exists
Using your first example it will do the query two times, according to the documentation:
if some_queryset has not yet been evaluated, but you
know that it will be at some point, then using some_queryset.exists()
will do more overall work (one query for the existence check plus an
extra one to later retrieve the results) than simply using
bool(some_queryset), which retrieves the results and then checks if
any were returned.
So if you're going to be using the object, after checking for existance, the docs suggest just using it and forcing evaluation 1 time using
if my_object:
pass

Multiple 'endings' to a function - return an object, return a string, raise an exception?

This one's a structure design problem, I guess. Back for some advice.
To start: I'm writing a module. Hence the effort of making it as usable to potential developers as possible.
Inside an object (let's call it Swoosh) I have a method which, when called, may result in either success (a new object is returned -- for insight: it's an httplib.HTTPResponse) or failure (surprising, isn't it?).
I'm having trouble deciding how to handle failures. There are two main cases here:
user supplied data that was incorrect
data was okay, but user interaction will be needed () - I need to pass back to the user a string that he or she will need to use in some way.
In (1) I decided to raise ValueError() with an appropriate description.
In (2), as I need to actually pass a str back to the user.. I'm not sure about whether it would be best to just return a string and leave it to the user to check what the function returned (httplib.HTTPResponse or str) or raise a custom exception? Is passing data through raising exceptions a good idea? I don't think I've seen this done anywhere, but on the other hand - I haven't seen much.
What would you, as a developer, expect from an object/function like this?
Or perhaps you find the whole design ridiculous - let me know, I'll happily learn.
As much as I like the approach of handling both cases with specifically-typed exceptions, I'm going to offer a different approach in case it helps: callbacks.
Callbacks tend to work better if you're already using an asynchronous framework like Twisted, but that's not their only place. So you might have a method that takes a function for each outcome, like this:
def do_request(on_success, on_interaction_needed, on_failure):
"""
Submits the swoosh request, and awaits a response.
If no user interaction is needed, calls on_success with a
httplib.HTTPResponse object.
If user interaction is needed, on_interaction_needed is
called with a single string parameter.
If the request failed, a ValueError is passed to on_failure
"""
response = sumbit_request()
if response.is_fine():
on_success(response)
elif response.is_partial()
on_interaction_needed(response.message)
else:
on_failure(ValueError(response.message))
Being Python, there are a million ways to do this. You might not like passing an exception to a function, so you maybe just take a callback for the user input scenario. Also, you might pass the callbacks in to the Swoosh initialiser instead.
But there are drawbacks to this too, such as:
Carelessness may result in spaghetti code
You're allowing your caller to inject logic into your function (eg. exceptions raised in the callback will propagate out of Swoosh)
My example here is simple, your actual function might not be
As usual, careful consideration and good documentation should avoid these problems. In theory.
I think raising an exception may actually be a pretty good idea in this case. Squashing multiple signals into a single return value of a function isn't ideal in Python, due to duck typing. It's not very Pythonic; every time you need to do something like:
result = some_function(...)
if isinstance(result, TypeA):
do_something(result)
elif isinstance(result, TypeB):
do_something_else(result)
you should be thinking about whether it's really the best design (as you're doing).
In this case, if you implement a custom exception, then the code that calls your function can just treat the returned value as a HTTPResponse. Any path where the function is unable to return something its caller can treat that way is handled by throwing an exception.
Likewise, the code that catches the exception and prompts the user with the message doesn't have to worry about the exact type of the thing its getting. It just knows that it's been explicitly instructed (by the exception) to show something to the user.
If the user interaction case means the calling code has to show a prompt, get some input and them pass control back to your function, it might be ugly trying to handle that with an exception. Eg,
try:
Swoosh.method()
except UserInteraction, ex:
# do some user interaction stuff
# pass it back to Swoosh.method()?
# did Swoosh need to save some state from the last call?
except ValueError:
pass # whatever
If this user interaction is a normal part of the control flow, it might be cleaner to pass a user-interaction function into your method in the first place - then it can return a result to the Swoosh code. For example:
# in Swoosh
def method(self, userinteractor):
if more_info_needed:
more_info = userinteractor.prompt("more info")
...
ui = MyUserInteractor(self) # or other state
Swoosh.method(ui)
You can return a tuple of (httplib.HTTPResponse, str) with the str being optionally None.
Definitely raise an exception for 1).
If you don't like returning a tuple, you can also create a "response object" i.e. an instance of a new class ( lets say SomethingResponse ) that encapsulates the HTTPResponse with optional messages to the end-user( in the simplest case, just a str).

Types & exceptions for a generic function to return an object or raise exception from QuerySet with a single item?

I have a pattern in my project where I need to re-use filtering logic for returning multiple results and a single result (depending on the input and needs of the caller). I'd like to make some generic function that takes a QuerySet as its input and either returns the only item in it or raises an exception like Model.objects.get() does if the number of results is not 1.
def single_result_from_qset(qset: "QuerySet") -> Any:
"""TODO: make this work somehow"""
if len(qset) > 1:
raise qset.MultipleObjectsReturned
try:
return qset[0]
except IndexError: # this is not unreachable, no matter what PyCharm tells you
raise qset.DoesNotExist
The problem I have with the above code I've tried arises when I need to raise an error. Instead of raising the error I asked it to, I get an AttributeError because neither MultipleObjectsReturned nor DoesNotExist are attributes of a QuerySet. How do I raise these errors from the objects the QuerySet is acting on?
As a bonus question, what is the proper type signature for the function definition?
The better solution is to use .get() from QuerySet rather than implement a new helper function. .get() returns and throws exactly what I was asking the above helper function to do.
Instead of calling rabbit = single_result_from_qset(search_animals_by_meat("Haßenpferrer)), I can use rabbit = search_animals_by_meat("Haßenpferrer).get().
search_animals_by_meat(q: str) -> "QuerySet[Animal]" could be a wrapper for something like Animals.objects.filter(meat_name__icontains=q) or a far more complex filtering scheme.

Categories

Resources