Reputation: 133
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
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
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.
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)
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);
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
Reputation: 711
return HttpResponse(data, content_type='application/octet-stream')
worked for me.
Upvotes: 17