Prepend BOM to XML response from Django
-
07-07-2019 - |
Question
I use Django's render_to_response
to return an XML document. This particular XML document is intended for a flash-based charting library. The library requires that the XML document start with a BOM (byte order marker). How can I make Django prepent the BOM to the response?
It works to insert the BOM into the template, but it's inconvenient because Emacs removes it every time I edit the file.
I have tried to rewrite render_to_response
as follows, but it fails because the BOM is being UTF-8 encoded:
def render_to_response(*args, **kwargs):
bom = kwargs.pop('bom', False)
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
s = django.template.loader.render_to_string(*args, **kwargs)
if bom:
s = u'\xef\xbb\xbf' + s
return HttpResponse(s, **httpresponse_kwargs)
Solution
You're not really talking about a BOM (Byte Order Mark), since UTF-8 doesn't have a BOM. From your example code, the library expects the text to have 3 garbage bytes prepended for some inexplicable reason.
Your code is almost correct, but you must prepend the bytes as bytes, not characters. Try this:
def render_to_response(*args, **kwargs):
bom = kwargs.pop('bom', False)
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
s = django.template.loader.render_to_string(*args, **kwargs)
if bom:
s = '\xef\xbb\xbf' + s.encode("utf-8")
return HttpResponse(s, **httpresponse_kwargs)
OTHER TIPS
This solution, based on a previous version of John Millikin's answer, is more complex than the one I accepted, but I'm including it here for completeness. First, define a middleware class:
class AddBOMMiddleware(object):
def process_response(self, request, response):
import codecs
if getattr(response, 'bom', False):
response.content = codecs.BOM_UTF8 + response.content
return response
Add its name to MIDDLEWARE_CLASSES in your settings. Then redefine render_to_response
:
def render_to_response(*args, **kwargs):
bom = kwargs.pop('bom', False)
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
rendered = django.template.loader.render_to_string(*args, **kwargs)
response = django.http.HttpResponse(rendered, **httpresponse_kwargs)
if bom:
response.bom = True
return response
Now, you can do render_to_response("foo.xml", mimetype="text/xml", bom=True)
in order to prepend the BOM to a particular response.
The simplest thing might be to configure Emacs not to remove the BOM.
But render_to_response is not a complicated function. It's basically:
def render_to_response(*args, **kwargs):
return HttpResponse(loader.render_to_string(*args, **kwargs))
You could easily call render_to_string and prepend the BOM.