user3144420
user3144420

Reputation: 133

Returning binary data with django HttpResponse

I'm trying to get Django's HttpResponse to return binary data without much success. I've been trying different methods for a while now, but without success.

Encoding the string to ASCII works as long as the binary data values aren't outside the ASCII char scope, which is smaller than 0-255. The same happened when encoding with latin-1.

Creating byte string works nicely, but seems to fail if certain values are included, for example, if I have the following bytes included in the data: "\xf6\x52", I will get different bytes as a result. For some reason, the first byte, \xf6, gets converted to 0xfffd when I'm trying to review the result response.

I'd love to get some feedback and help with this.

Many thanks!

-A-

Upvotes: 12

Views: 22792

Answers (3)

rzlvmp
rzlvmp

Reputation: 9364

Here is an example code how to response binary data (Excel file in my case) with Django:

def download_view(request):
    # If you want to respond local file 
    with open('path/to/file.xlsx', 'rb') as xl:
        binary_data = xl.read()

    # Or if you want to generate file inside program (let's, say it will be openpyxl library)
    wb = openpyxl.load_workbook('some_file.xlsx')
    binary_object = io.BytesIO()
    wb.save(binary_object)
    binary_object.seek(0)
    binary_data = binary_object.read()

    file_name = f'FILENAME_{datetime.datetime.now().strftime("%Y%m%d")}.xlsx'

    response = HttpResponse(
        # full list of content_types can be found here
        # https://stackoverflow.com/a/50860387/13946204
        content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        headers={'Content-Disposition': f'attachment; filename="{file_name}"'},
    )
    response.write(binary_data)
    return response

Upvotes: 3

Christopher Peisert
Christopher Peisert

Reputation: 24134

A flexible way to return binary data from Django is to first encode the data using Base64.

Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation.

Since the Base64 encoded data is ASCII, the default HTTP response content type of text/html; charset=utf-8 works fine.

Image Example

Django

import base64
from io import BytesIO

from django.http import HttpRequest, HttpResponse
import PIL.Image


def image_test(request: HttpRequest) -> HttpResponse:
    file_stream = BytesIO()
    image_data = PIL.Image.open('/path/to/image.png')
    image_data.save(file_stream)
    file_stream.seek(0)
    base64_data = base64.b64encode(file_stream.getvalue()).decode('utf-8')
    return HttpResponse(base64_data)

Web Browser

After fetching the data from Django, the base64 data can be used to create a data URL.


// `data` fetched from Django as Base64 string
const dataURL = `data:image/png;base64,${data}`;
const newImage = new Image();
newImage.src = dataURL;
$('#ImageContainer').html(newImage);

JSON Response

The Base64 data may also be returned as part of a JSON response:

import base64
from io import BytesIO

from django.http import HttpRequest, JsonResponse
import PIL.Image

def image_test(request: HttpRequest) -> JsonResponse:
    file_stream = BytesIO()
    image_data = PIL.Image.open('/path/to/image.png')
    image_data.save(file_stream)
    file_stream.seek(0)
    base64_data = base64.b64encode(file_stream.getvalue()).decode('utf-8')
    json_data = dict()
    json_data['base64Data'] = base64_data
    return JsonResponse(json_data)

Upvotes: 5

sadashiv30
sadashiv30

Reputation: 711

return HttpResponse(data, content_type='application/octet-stream')

worked for me.

Upvotes: 17

Related Questions