Django头痛与简单的非ascii字符串

时间:2010-01-30 17:56:50

标签: unicode django-admin

我刚创建了以下模型:

class Categoria(models.Model):
    nombre=models.CharField(max_length=30)
    padre=models.ForeignKey('self', blank=True, null=True)

    def __unicode__(self):
        return self.nombre

然后注册到管理界面和syncdb'd

如果我只添加纯ASCII字符,一切都好。但如果我添加名为“á”的“类别”(说些什么),我会得到:

Environment:

Request Method: GET
Request URL: http://192.168.2.103:8000/administracion/locales/categoria/
Django Version: 1.1.1
Python Version: 2.6.4
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.admin',
 'cruzandoelsuquiaDJ.locales']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware')


Template error:
In template /usr/lib/pymodules/python2.6/django/contrib/admin/templates/admin/change_list.html, error at line 78
   Caught an exception while rendering: ('ascii', '\xc3\xa1', 0, 1, 'ordinal not in range(128)')
   68 :         {% endif %}


   69 :       {% endblock %}


   70 :       


   71 :       <form action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>


   72 :       {% if cl.formset %}


   73 :         {{ cl.formset.management_form }}


   74 :       {% endif %}


   75 : 


   76 :       {% block result_list %}


   77 :           {% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions %}{% endif %}


   78 :            {% result_list cl %} 


   79 :           {% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions %}{% endif %}


   80 :       {% endblock %}


   81 :       {% block pagination %}{% pagination cl %}{% endblock %}


   82 :       </form>


   83 :     </div>


   84 :   </div>


   85 : {% endblock %}


   86 : 

Traceback:
File "/usr/lib/pymodules/python2.6/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/pymodules/python2.6/django/contrib/admin/options.py" in wrapper
  226.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/lib/pymodules/python2.6/django/views/decorators/cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)
File "/usr/lib/pymodules/python2.6/django/contrib/admin/sites.py" in inner
  186.             return view(request, *args, **kwargs)
File "/usr/lib/pymodules/python2.6/django/contrib/admin/options.py" in changelist_view
  986.         ], context, context_instance=context_instance)
File "/usr/lib/pymodules/python2.6/django/shortcuts/__init__.py" in render_to_response
  20.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/usr/lib/pymodules/python2.6/django/template/loader.py" in render_to_string
  108.     return t.render(context_instance)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  178.         return self.nodelist.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  779.                 bits.append(self.render_node(node, context))
File "/usr/lib/pymodules/python2.6/django/template/debug.py" in render_node
  71.             result = node.render(context)
File "/usr/lib/pymodules/python2.6/django/template/loader_tags.py" in render
  97.         return compiled_parent.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  178.         return self.nodelist.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  779.                 bits.append(self.render_node(node, context))
File "/usr/lib/pymodules/python2.6/django/template/debug.py" in render_node
  71.             result = node.render(context)
File "/usr/lib/pymodules/python2.6/django/template/loader_tags.py" in render
  97.         return compiled_parent.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  178.         return self.nodelist.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  779.                 bits.append(self.render_node(node, context))
File "/usr/lib/pymodules/python2.6/django/template/debug.py" in render_node
  71.             result = node.render(context)
File "/usr/lib/pymodules/python2.6/django/template/loader_tags.py" in render
  24.         result = self.nodelist.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  779.                 bits.append(self.render_node(node, context))
File "/usr/lib/pymodules/python2.6/django/template/debug.py" in render_node
  71.             result = node.render(context)
File "/usr/lib/pymodules/python2.6/django/template/loader_tags.py" in render
  24.         result = self.nodelist.render(context)
File "/usr/lib/pymodules/python2.6/django/template/__init__.py" in render
  779.                 bits.append(self.render_node(node, context))
File "/usr/lib/pymodules/python2.6/django/template/debug.py" in render_node
  81.             raise wrapped

Exception Type: TemplateSyntaxError at /administracion/locales/categoria/
Exception Value: Caught an exception while rendering: ('ascii', '\xc3\xa1', 0, 1, 'ordinal not in range(128)')

我的django版本是1.1,我的数据库是5.1.37-1ubuntu5,带有utf8字符集,表格使用了utf8_bin校对。

这个问题看起来太基本了,而且我是一个django新手,所以如果我错过了一些非常简单的话,我会提前感到抱歉:)

6 个答案:

答案 0 :(得分:17)

Django通常具有非常好的Unicode支持(有关详细信息,请参阅Django 1.1 "Unicode data" documentation)。在我的代码中,我发现,如果我遇到简单的Unicode功能问题,问题通常是我不能很好地理解Django的细节,而不是Django的Unicode支持有错误。

“Unicode数据”页面告诉我们“所有Django的数据库后端......自动将从数据库中检索到的字符串转换为Python Unicode字符串。您甚至不需要告诉Django您的数据库使用什么编码:即透明地处理。“所以你的简单return self.nombre应该返回一个Python Unicode字符串。

但是,Django 1.1 "Databases" page有一个关于MySQL后端如何处理utf8_bin排序规则的重要说明:

  

...如果你真的想要区分大小写的话   比较特定列或   表,你会改变列或   表使用utf8_bin排序规则。   在这方面要注意的主要事项   如果你使用的是MySQLdb   1.2.2,Django中的数据库后端将返回bytestrings(而不是   unicode字符串)任何字符   它返回的字段是从   数据库。这是一个很大的变化   来自Django的正常做法   总是返回unicode字符串。它   由开发人员负责处理   你将收到的事实   如果你配置你的字节串   要使用utf8_bin排序规则的表格。   Django本身应该顺利运作   有这样的列,但如果你的代码   必须准备打电话   django.utils.encoding.smart_unicode()   有时,如果它真的想工作   数据一致......

因此,在您的原始示例中,“nombre”列使用了utf8_bin排序规则。这意味着self.nombre正在返回一个Python字节字符串。当您将其放在需要Python Unicode字符串的表达式中时,Python会执行其默认转换。这相当于self.nombre.decode('ascii')。当然,.decode('ascii')在遇到0x7F以上的任何字节时都会失败,例如编码“á”的UTF-8字节。

您发现了解决此问题的两种方法。第一种是将self.nombre返回的Python字节字符串显式转换为Python Unicode字符串。我敢打赌,以下更简单的代码会起作用:

return self.nombre.decode('utf8')

第二种方法是更改​​列“nombre”的MySQL排序规则,这会导致Django的MySQL后端返回Python Unicode字符串而不是异常字节字符串。然后你的原始表达式给出了一个Python Unicode字符串:

return self.nombre

希望这有帮助。

答案 1 :(得分:7)

这个问题可以通过稍微更改django的代码来解决。 在django / utils / encoding.py

中添加以下代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

答案 2 :(得分:4)

我在生产中遇到过这个问题,从不在开发服务器上 然后我意识到新表是使用utf8_bin整理而不是utf8_general_ci创建的。

要查看哪些表需要转换,请键入

SHOW TABLE STATUS;

然后通过键入

转换utf8_bin归类的那些
ALTER TABLE app_table CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

最后,更改默认排序规则,以便不再发生这种情况:

ALTER DATABASE my_database character set utf8 collate utf8_general_ci;

答案 3 :(得分:2)

好的......

    return u"%s"%(self.nombre.decode('utf8'),)

诀窍。

但是也发现将utf8_bin改为utf8_general_ci可以解决问题,即self.nombre按预期工作。

答案 4 :(得分:1)

我通过简单地为模型创建管理模型并在&#34; list_display&#34;中包含所有变量来解决问题。

答案 5 :(得分:0)

我有类似的问题,最近改变了一个MySQL表,在staging中使用collat​​ion utf8_bin而dev中没有问题(python2.7,两个环境中的Django1.4.2)。我发现在开发中我有MySQL-python 1.2.4c1并且在暂存中我有1.2.3。升级到MySQL-python 1.2.4为我解决了这个问题。