Django头痛与简单的非ASCII字符串 [英] Django headache with simple non-ascii string

查看:111
本文介绍了Django头痛与简单的非ASCII字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚创建了以下模型:

  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字符,一切都可以。但是,如果我添加一个名为á(表示某事)的类别,我得到:

 环境:

请求方法:GET
请求URL:http://192.168.2.103:8000/administracion/locales/categoria/
Django版本:1.1.1
Python版本:2.6。 4
已安装的应用程序:
['django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
' django.contrib.admin',
'cruzandoelsuquiaDJ.locales']
安装的中间件:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions。
'django.contrib.auth.middleware.AuthenticationMiddleware')


模板错误:
在模板/ usr / lib / pymodules / python2 .6 / django / contrib / admin / templates / admin / change_list.html,第78行错误
在呈现时捕获异常:('ascii','\xc3\xa1',0,1,'序号不在范围(128)')
68:{%end如果%}


69:{%endblock%}


70:


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


72:{%如果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:

追溯:
文件/ usr / lib / pymodules / python2.6 / django / core / handlers / base.pyin get_response
92. response = callback(request,* callback_args,** callback_kwargs)
文件/ usr / lib / pymodules / python2.6 / django / contrib / admin / options.pyin wrapper
226. return self.admin_site.admin_view(view)(* args,** kwargs)
文件/ usr / lib / pymodules / python2.6 / django / views / decorators / cache.pyin _wrapped_view_func
44. response = view_func(request,* args,** kwargs)
文件/ usr /内部
186. lib / pymodules / python2.6 / django / contrib / admin / sites.py返回视图(request,* args,** kwargs)
文件/ usr / lib / pymodules /python2.6/django/contrib/admin/options.pyin changelist_view
986.],context,context_instance = context_instance)
文件/usr/lib/pymodules/python2.6/django/ render_to_response
20中的快捷方式/ __ init__.py。返回HttpResponse(loader.render_to_string(* args,** kwargs),** httpresponse_kwargs)
文件/usr/lib/pymodules/python2.6/django/template/loader.py在render_to_string
返回t.render(context_instance)
文件/usr/lib/pymodules/python2.6/django/template/__init__.py在render
178. return self.nodelist.render(context )
文件/usr/lib/pymodules/python2.6/django/template/__init__.py在render
779. bits.append(self.render_node(node,context))
文件/usr/lib/pymodules/python2.6/django/template/debug.py在render_node
71. result = node.render(context)
文件/ usr / lib / pymodules /python2.6/django/template/loader_tags.pyin render
97. return compiled_pa​​rent.render(context)
文件/usr/lib/pymodules/python2.6/django/template/__init__ .py在render
178. return self.nodelist.render(context)
文件/usr/lib/pymodules/python2.6/django/template/__init__.py中的rend er
779. bits.append(self.render_node(node,context))
render_node中的文件/usr/lib/pymodules/python2.6/django/template/debug.py
71. result = node.render(context)
文件/usr/lib/pymodules/python2.6/django/template/loader_tags.py在render
97. return compiled_pa​​rent.render(context )
文件/usr/lib/pymodules/python2.6/django/template/__init__.py在render
178. return self.nodelist.render(context)
文件/ $ ab

文件/ usr / lib / lib / p / render_node
中的pymodules / python2.6 / django / template / debug.py71. result = node.render(context)
文件/usr/lib/pymodules/python2.6/django/template render
中的/loader_tags.py24. result = self.nodelist.render(context)
文件/usr/lib/pymodules/python2.6/django/template/__init__.py在渲染中
77 9. bit.append(self.render_node(node,context))
render_node
中的文件/usr/lib/pymodules/python2.6/django/template/debug.py71. result = node.render(context)
文件/usr/lib/pymodules/python2.6/django/template/loader_tags.py在render
中24. result = self.nodelist.render(context)
文件/usr/lib/pymodules/python2.6/django/template/__init__.py在render
779. bits.append(self.render_node(node,context))
文件/usr/lib/pymodules/python2.6/django/template/debug.py在render_node
81. raise wrapped

异常类型:TemplateSyntaxError at / administracion / locales / categoria /
异常值:在呈现时捕获异常:('ascii','\xc3\xa1',0,1,'ordinal not in range(128)')

我的django版本是1.1,我的数据库是带有utf8字符集的5.1.37-1ubuntu5,该表使用的是utf8_bin归类。



这个问题似乎太基本不成立,我是一个django新手,所以我很抱歉,如果我错过了一些非常简单的东西:)

解决方案

Django通常具有非常好的Unicode支持(请参阅 Django 1.1Unicode数据文档详细信息)。在我的代码中,我发现如果我在使用简单的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中的数据库后端将返回bytestrings(而不是
的unicode字符串)任何字符
字段返回从
数据库接收。这是一个强大的变化
从Django的正常练习
总是返回unicode字符串。
取决于您,开发人员处理
如果您配置
表以使用utf8_bin排序规则,您将收到
bytestrings的事实。
Django本身应该顺利地运行
这样的列,但如果您的代码
必须准备好调用
django.utils.encoding.smart_unicode()
有时if它真的想要工作
一致的数据...


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



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

  return self.nombre.decode('utf8')

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

  return self.nombre 
/ pre>

希望这有帮助。


I just created the following model:

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

    def __unicode__(self):
        return self.nombre

Then registered to the admin interface and syncdb'd

Everything ok if I just add plain ASCII chars. But if I add a "Categoria" named "á" (to say something) I get:

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)')

My django version is 1.1 and my database is 5.1.37-1ubuntu5 with utf8 charset and the table is using a utf8_bin collation.

This problem seems too basic to be true, and I'm a django newbie so I'm sorry in advance if I'm missing something very simple :)

解决方案

Django generally has very good Unicode support (see the Django 1.1 "Unicode data" documentation for details). In my code I find that, if I'm having a problem with simple Unicode features, the problem usually is that I'm not understanding Django's details well, not that Django has a bug in its Unicode support.

The "Unicode Data" page tells us that "All of Django’s database backends ... automatically convert strings retrieved from the database into Python Unicode strings. You don’t even need to tell Django what encoding your database uses: that is handled transparently." So your simple return self.nombre should return a Python Unicode string.

However, the Django 1.1 "Databases" page has an important note about how the MySQL backend handles the utf8_bin collation:

...if you really want case-sensitive comparisons on a particular column or table, you would change the column or table to use the utf8_bin collation. The main thing to be aware of in this case is that if you are using MySQLdb 1.2.2, the database backend in Django will then return bytestrings (instead of unicode strings) for any character fields it returns receive from the database. This is a strong variation from Django's normal practice of always returning unicode strings. It is up to you, the developer, to handle the fact that you will receive bytestrings if you configure your table(s) to use utf8_bin collation. Django itself should work smoothly with such columns, but if your code must be prepared to call django.utils.encoding.smart_unicode() at times if it really wants to work with consistent data ...

So, in your original example, the column "nombre" used utf8_bin collation. This meant that self.nombre was returning a Python byte string. When you put it in an expression that required a Python Unicode string, Python performed its default conversion. This is the equivalent of self.nombre.decode('ascii'). And of course, .decode('ascii') fails when it encounters any byte above 0x7F, such as the UTF-8 bytes which encode "á".

You discovered the two ways to solve this problem. The first is to convert the Python byte string returned by self.nombre into a Python Unicode string explicitly. I'll bet the following simpler code would have worked:

return self.nombre.decode('utf8')

The second approach is to change the MySQL collation for column "nombre", which causes Django's MySQL backend to return Python Unicode strings instead of the unusual byte strings. Then your original expression gives a Python Unicode string:

return self.nombre

Hope this helps.

这篇关于Django头痛与简单的非ASCII字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆