Exception Handling In Django & Python Using Decorators
Published: 2023-12-19 08:31:28

When developing in Django, effective exception handling is crucial for maintaining a robust and resilient application. Here's a concise guide on how to enhance your error management using decorators

### Model Definition

``` python
# Importing necessary modules from Django
from django.db import models

# Defining a Django model for Users
class Users(models.Model):
    pass  # Placeholder, as the Users model does not have any fields defined

# Defining a Django model for ErrorLogs
class ErrorLogs(models.Model):
    # Defining a foreign key relationship with the Users model
    user = models.ForeignKey(
        Users, on_delete=models.SET_NULL, related_name='user_in_error_logs', null=True, blank=True
    )
    # Storing the expected error message
    expected_error = models.CharField(max_length=500)
    # Storing the field-specific error message
    field_error = models.CharField(max_length=500)
    # Storing the trace back information for debugging
    trace_back = models.TextField(max_length=500)
    # Storing the line number where the error occurred
    line_number = models.IntegerField()
    # Storing the date and time when the error was recorded (auto-generated)
    date_recorded = models.DateTimeField(auto_now_add=True)
    # Storing the browser information where the error occurred
    browser = models.CharField(max_length=500)
    # Storing the IP address from where the error was reported
    ip_address = models.CharField(max_length=500)
    # Storing the operating system information where the error occurred
    os = models.TextField(max_length=500)

    # Meta class to specify additional options for the model
    class Meta:
        # Specifying the database table name for the model
        db_table = 'errorlogs'

```


 
### Handling Exceptions

``` python
# Importing necessary modules and packages
from django.http import JsonResponse
from django.shortcuts import render
from functools import wraps
import httpagentparser, traceback, sys

# Importing the ErrorLogs model from the 'app' Django application
from app.models import ErrorLogs

# Importing custom packages
from customHandlers.generator import Messages


class Messages:
    def validation_message(message, input=None):
        return {
            'title': "Validation Error",
            'icon': "warning",
            'message': message,
            'isError': True,
            'input': input
        }

    def unauthenticated_message(message, input=None):
        return {
            'title': "Unauthenticated Error",
            'icon': "warning",
            'message': message,
            'isError': True,
            'input': input
        }

    def exception_message(message, input=None):
        return {
            'title': "Exception Error",
            'icon': "error",
            'message': message,
            'isError': True,
            'input': input
        }

    def success_message(message, input=None):
        return {
            'title': "Congratulations",
            'icon': "success",
            'message': message,
            'isError': False,
            'input': input
        }

    def unrecognized_message(message="You don't have permission to perform this action", input=None):
        return {
            'title': "Unrecognized",
            'icon': "warning",
            'message': message,
            'isError': True,
            'input': input
        }

def sendException(request, error):
    """
    Log and save information about an exception.

    :param request: HttpRequest object.
    :param error: Exception object.
    """
    user = request.user if request.user.is_authenticated else None

    ip = request.META.get('REMOTE_ADDR')
    get_client_agent = request.META['HTTP_USER_AGENT']

    # Parsing user agent information
    detect_os = httpagentparser.detect(get_client_agent)['os']['name']
    browser = httpagentparser.detect(get_client_agent)['browser']['name']

    trace_err = traceback.format_exc()
    expected_error = str(sys.exc_info()[0])
    field_error = str(sys.exc_info()[1])
    line_number = str(sys.exc_info()[-1].tb_lineno)

    # Creating an ErrorLogs instance and saving it to the database
    error_logs = ErrorLogs(
        user=user,
        ip_address=ip,
        browser=browser,
        expected_error=expected_error,
        field_error=field_error,
        trace_back=str(trace_err),
        line_number=line_number,
        os=detect_os,
    )
    error_logs.save()

def handle_exceptions():
    """
    Decorator function to handle exceptions in views.

    If an exception occurs, log the exception and return a JsonResponse with an error message.

    :return: Decorator function
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            try:
                # Call the original view function
                return view_func(request, *args, **kwargs)
            except Exception as error:
                # Log the exception and return an error message
                sendException(request, error)
                return JsonResponse(Messages.exception_message('Oops! Something went wrong. Please try again later or contact support at support@example.com for assistance.'))

        return wrapper
    return decorator

```

### Handling Exceptions

``` python
from django.shortcuts import render

from app.customHandlers import handle_exceptions

@handle_exceptions
def YourViewPage(request):
    return render(request , 'page.html' , {})


```


Exception handling made easy 💡 Dive into the details and level up your Django development