最近一个Web项目中涉及到多方合作,不同合作方要求返回的页面编码格式不一样,有的是UTF8,有的是GB2312。但是Django默认只支持一种编码格式,就是在settings.py里面设置的LANGUAGE_CODE,并且Django会自动将输入进来的参数(包括HttpRequest和数据库的读取)decode成Unicode,并在返回的时encode成LANGUAGE_CODE指定的编码。这样尝试在UTF8的项目里面直接输出GB2312的页面就会出现编码错误,返回Django的500页面。
在翻阅Django文档无果后,翻开Django源码寻求解决方案,Ubuntu下通过apt-get方式安装的Django位于 /usr/share/python-support/python-django/django,因为返回页面涉及到HttpResponse, 所以打开django/http下的__init__.py, 找到HttpResponse的定义:
class HttpResponse(object):
"""A basic HTTP response, with content and dictionary-accessed headers."""
status_code = 200
def __init__(self, content='', mimetype=None, status=None,
content_type=None):
from django.conf import settings
self._charset = settings.DEFAULT_CHARSET
if mimetype:
content_type = mimetype # For backwards compatibility
if not content_type:
content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
settings.DEFAULT_CHARSET)
if not isinstance(content, basestring) and hasattr(content, '__iter__')
self._container = content
self._is_string = False
else:
self._container = [content]
self._is_string = True
self.cookies = SimpleCookie()
if status:
self.status_code = status
# _headers is a mapping of the lower-case name to the original case of
# the header (required for working with legacy systems) and the header
# value.
self._headers = {'content-type': ('Content-Type', content_type)}
在项目里面定义一个派生自HttpResponse的GbkHttpResponse的新类:
from django.http import HttpResponse
from Cookie import SimpleCookie
class GbkHttpResponse(HttpResponse):
"""
返回GB2312编码的Response
"""
status_code = 200
def __init__(self, content='', content_type=None):
self._charset = 'GB2312'
content_type = "text/html; charset=GB2312"
if not isinstance(content, basestring) and hasattr(content, '__iter__'):
self._container = content
self._is_string = False
else:
self._container = [content]
self._is_string = True
self.cookies = SimpleCookie()
self._headers = {'content-type': ('Content-Type', content_type)}
在需要输出GB2312编码的view里面调用GbkHttpResponse即可(some_view所在的文件是UTF8编码)
def some_view(request):
return GbkHttpResponse('<html>\n<body>这里将输出GB2312编码的内容\n</body>\n</html>\n'.decode('utf8').encode('gbk'))