Prepend BOM à resposta XML de Django
-
07-07-2019 - |
Pergunta
Eu uso render_to_response
do Django para retornar um documento XML. Este documento XML especial destina-se a uma biblioteca de gráficos baseado em flash. A biblioteca exige que o documento XML começar com um BOM (byte ordem marcador). Como posso fazer Django prepent o BOM para a resposta?
Ele trabalha para inserir o BOM para o modelo, mas é inconveniente porque Emacs remove-lo cada vez que eu editar o arquivo.
Eu tentei reescrever render_to_response
como segue, mas falha porque o BOM está sendo UTF-8 codificado:
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)
Solução
Você não está realmente falando de um BOM (Byte Order Mark), uma vez que UTF-8 não tem um BOM. Do seu código exemplo, a biblioteca espera que o texto para ter 3 lixo bytes prefixado por alguma razão inexplicável.
Seu código é quase correto, mas você deve preceder os bytes como bytes , não caracteres. Tente isto:
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)
Outras dicas
Esta solução, com base em uma versão anterior da resposta de John Millikin, é mais complexa do que a que eu aceito, mas eu estou incluindo para ficar completo. Primeiro, definir uma classe middleware:
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
Adicione seu nome para MIDDLEWARE_CLASSES em suas configurações. Então render_to_response
redefine:
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
Agora, você pode fazer render_to_response("foo.xml", mimetype="text/xml", bom=True)
a fim prefixar o BOM para uma resposta particular.
A coisa mais simples poderia ser a de configurar Emacs para não remover o BOM.
Mas render_to_response não é uma função complicada. É basicamente:
def render_to_response(*args, **kwargs):
return HttpResponse(loader.render_to_string(*args, **kwargs))
Você poderia facilmente chamar render_to_string e preceder o BOM.