【问题标题】:Django headache with simple non-ascii string简单的非ASCII字符串的Django头痛
【发布时间】:2010-01-30 17:56:50
【问题描述】:

我刚刚创建了以下模型:

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

    def __unicode__(self):
        return self.nombre

然后注册到管理界面并同步数据库

如果我只添加纯 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 新手,所以如果我错过了一些非常简单的东西,我很抱歉:)

【问题讨论】:

  • 在我看来,Django 本身应该自己解决这些问题。您可能应该尝试最新的 Django 和 MySQL python 绑定,确保您拥有 unicode 中的所有字符串(以及您的 python 源代码中的 unicode 标头——# -*- coding: utf-8 -*-)。如果这些都没有帮助,我会考虑将其作为 Django 中的错误提交。
  • 有人会认为...我会尝试提交错误。

标签: unicode django-admin


【解决方案1】:

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中的数据库后端然后将返回字节串(而不是 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

希望这会有所帮助。

【讨论】:

  • 是的,它帮助我理解。我将您的答案标记为正确,因为它解释得很好。谢谢
  • 如何更改 MySQL 列的排序规则类型?
  • 这是一个 Django 错误,恕我直言。你怎么看?为什么UTF8_bin会完全打破规则?
  • @Sylvain 我同意处理 UTF8_bin 是不正确的行为。可能是 MySQLdb 1.2.2 错误,而不是 Django 错误。但我不确定。
  • Mucho 出色的帖子,@JimDeLaHunt。到整理文档的链接很棒。加上您的解释,帮助我理解了我面临的类似问题。我们必须直接在数据库中将排序规则更改为 utf8_general_ci (您也可以使用显式 MYSQL 语句编写迁移来完成),以免出现愚蠢的 unicode 解码错误。
【解决方案2】:

这个问题可以通过稍微修改一下django的代码来解决。 在 django/utils/encoding.py 中添加以下代码

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

【讨论】:

    【解决方案3】:

    我在生产中遇到过这个问题,而在开发服务器上从来没有。
    然后我意识到新表是使用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;
    

    【讨论】:

      【解决方案4】:

      好的……

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

      成功了。

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

      【讨论】:

        【解决方案5】:

        我通过简单地为模型创建一个管理模型并将所有变量包含在“list_display”中来解决问题。

        【讨论】:

        • 应该是评论
        【解决方案6】:

        最近更改 MySQL 表以在暂存中使用排序规则 utf8_bin 而在 dev 中没有问题(python2.7,Django1.4.2 在两种环境中)时,我遇到了类似的问题。我发现在 dev 中我有 MySQL-python 1.2.4c1,在 staging 中我有 1.2.3。升级到 MySQL-python 1.2.4 为我解决了这个问题。

        【讨论】:

          猜你喜欢
          • 2011-06-05
          • 2017-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-22
          • 2016-04-09
          • 1970-01-01
          • 2011-02-14
          相关资源
          最近更新 更多