I'm in the midst of building a Django app and am hoping to get some advice on the proper way to handle errors and bugs in my code.
Here's a common situation exemplary of the problems I have: a user purchases a product. To process the purchase, my views need to perform a number of actions:
- First, the view should create a
Userobject in the database. - If that is successful, the view should create an
Orderobject and assign it to the newly-created User. - If that is successful, my code should create a
Productobject and add it to the newly created Order.
This is all well and good when no errors occur - but I find that the occasional error is inevitable in my code, and I want my app to deal with errors gracefully, rather than crashing outright. For example, if, for any reason, an Order object cannot be created, the view should show the user an error and remove the User object that was previously created. And, it should throw a graceful error message rather than crashing outright and serving the user a Http 500 error.
The only way I can think of to do this is an extremely complex series of nested try / except clauses, like below. But designing my code this way is extremely messy and time-consuming, and it doesn't feel like the right way to do things. I know there must be a better way to design for proper error handling in Django and Python, but I'm not quite sure what it is.
I would greatly appreciate any advice on how to better structure my code in this situation.
Example code:
try:
# Create a new user
u = User(email='[email protected]')
u.save()
try:
# Create a new order
o = Order(user=u, name='Order name')
o.save()
try:
# Create a new product
p = Product(order=o, name='Product name')
p.save()
# If a product cannot be created, print an error message and try deleting the user and order that were previously created
except:
messages.add_message(request, messages.ERROR, 'Product could not be created')
# If deleting the order doesn't work for any reason (for example, o.save() didn't properly save the user), 'pass' to ensure my application doesn't crash
try:
o.delete()
# I use these 'except: pass' clauses to ensure that if an error occurs, my app doesn't serve a Http 500 error and instead shows the user a graceful error
except:
pass
# If deleting the user doesn't work for any reason (for example, u.save() didn't properly save the user), 'pass' to ensure my application doesn't crash
try:
u.delete()
except:
pass
# If an order cannot be created, print an error message and try deleting the user that was previously created
except:
messages.add_message(request, messages.ERROR, 'Order could not be created')
# If deleting the user doesn't work for any reason (for example, u.save() didn't properly save the user), 'pass' to ensure my application doesn't crash
try:
u.delete()
except:
pass
# If the user cannot be created, throw an error
except:
messages.add_message(request, messages.ERROR, 'User could not be created')