In Django, how can I get an exception's message?

Question:

In a view function, I have something like:

try:
    url = request.POST.get('u', '')
    if len(url) == 0:
        raise ValidationError('Empty URL')
except ValidationError, err:
    print err

The output is a string: [u'Empty URL']

When I try to pass the error message to my template (stuffed in a dict, something like { 'error_message': err.value }), the template successfully gets the message (using {{ error_message }}).

The problem is that I get the exact same string as above, [u'Empty URL'], with the [u'...']!

How do I get rid of that?

(Python 2.6.5, Django 1.2.4, Xubuntu 10.04)

Answers:

I fixed it by changing ValidationError to BaseException.

Answered By: Nikki Erwin Ramirez

ValidationError actually holds multiple error messages.

The output of print err is [u'Empty URL'] because that is the string returned by repr(err.messages) (see ValidationError.__str__ source code).

If you want to print a single readable message out of a ValidationError, you can concatenate the list of error messages, for example:

    # Python 2 
    print '; '.join(err.messages)
    # Python 3
    print('; '.join(err.messages))
Answered By: scoffey

If you are importing ValidationError from django.core.exceptions you can simply use messages method as err.messages.

https://github.com/django/django/blob/main/django/core/exceptions.py#L124

If you are importing ValidationError from rest_framework.serializers , there is no messages property for the ValidationError but there is detail property. so you can use err.detail which will give you a dictionary.

In order to concatenate all the error messages as a string, you can use
"".join(["".join(v) for v in err.detail.values()])
or
"".join([k+" - "+"".join(v) for k,v in err.detail.items()])

https://github.com/encode/django-rest-framework/blob/master/rest_framework/exceptions.py#L143

Answered By: Akhil RS

A more general way to always know where the message is to call the dir function on your err variable to show you all the attribute of this object.
from that list you can infer where the messages are, in my case (with django 3.2) i found out that the message dict is in an attribute called args.
so to use it (with a print for example)

try:
    url = request.POST.get('u', '')
    if len(url) == 0:
        raise ValidationError('Empty URL')
except ValidationError, err:
    print(err.args) # HERE THE ERROR DICT MESSAGE IS ACCESSIBLE

Answered By: Yehdhih ANNA