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

Eze*_*iel 8 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
Run Code Online (Sandbox Code Playgroud)

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

如果我只添加纯ASCII字符,一切都OK.但如果我添加一个名为"á"的"类别"(说些什么),我会得到:

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)')
Run Code Online (Sandbox Code Playgroud)

我的django版本是1.1,我的数据库是5.1.37-1ubuntu5,带有utf8字符集,表格使用的是utf8_bin排序规则.

这个问题似乎太基本了,而且我是一个django新手,所以如果我错过了一些非常简单的话,我会提前对不起:)

Jim*_*unt 17

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

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

但是,Django 1.1"数据库"页面有一个关于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字节.

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

return self.nombre.decode('utf8')
Run Code Online (Sandbox Code Playgroud)

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

return self.nombre
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.


Shu*_*ang 7

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

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Run Code Online (Sandbox Code Playgroud)