Best practice for intercepting error responses in Django and DRF

I have a Django app that uses the Django Rest Framework. Errors may occur on the Django side, like integrity errors in the database. The default error response will be something like:

{
  "details": {
    "email": "user with this email already exists."
  }
}

Validation errors may also occur DRF side:

{
  "detail": ...
}

As you can see, there is an inconsistency in the response message, as Django uses “details” and DRF uses “detail”.

However, I like neither format. I want to respond with a message in the following format:

{
  "message": ...
  "code": ...
}

My question is:

What is the best practice to handle both Django and DRF exceptions and respond with a custom response body?

I have tried:

  1. custom exception handler in DRF, but this only handles DRF exceptions
  2. custom error messages when defining models
      email = models.EmailField(error_messages={"required": {"message": "", "code": 123}})
    
    but Django can’t handle a dictionary as a message
  3. Adding a DRF validator to my serializer:
    email = serializers.EmailField(
        validators=[
            UniqueValidator(
                queryset=models.User.objects.all(),
                message={
                    "message": "a user with this email already exists",
                    "code": status.EMAIL_EXISTS,
                },
            )
        ],
    )
    
    but this does not override the response body, but instead it embeds the message as an error message to the {"details": {"message": {<embedded dictionary>}}}

The only thing I believe would work, is to try-except all exceptions inside my Views, but I would like to know if there is a prettier way than placing all my View code inside a try block.