Override accepted renderer in django-rest-framework on exception

Viewed 2948

I'm using django-rest-framework to create an endpoint which returns a PDF. However, when there is an error rendering the PDF, I want to return a JSON response. But DRF passes the data for the exception to my PDFRenderer class. How can I use JSONRenderer instead, only if there is an error?

class PDFRenderer(BaseRenderer):
    """ DRF renderer for PDF binary content. """
    media_type = 'application/pdf'
    format = 'pdf'
    charset = None
    render_style = 'binary'

    def render(self, data, media_type=None, renderer_context=None):
        return bytes(data)

For example, when my view says raise PermissionDenied(), because the authorized user does not have permission to view the requested PDF, DRF passes {'detail': 'You do not have permission to perform this action.'} as the data argument to PDFRenderer.render.

Edit: I tried a custom exception handler but apparently you still have to run it through DRF's exception handler as well, which passes it to the PDFRenderer.

2 Answers

If request is ok and file exists, I read it as bytes and pass it to Response, as custom renderer I use PDFRenderer as yours. If request isn't ok, I return json. My solution is to check if data is instance of bytes, if not, I just return bytes from valid json string, because render method should return bytes anyway

class PDFRenderer(BaseRenderer):
    media_type = 'application/pdf'
    format = 'pdf'
    charset = None
    render_style = 'binary'

    def render(self, data, media_type=None, renderer_context=None):
        if isinstance(data, bytes):
            return data
        data_to_response = json.dumps(data)
        return bytes(data_to_response.encode('utf-8'))
Related