Головная боль 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. Но если я добавляю "Categoria", названный "á" (для высказывания чего-то), я добираюсь:

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 новичок, таким образом, я сожалею заранее, если я пропускаю что-то очень простое:)

8
задан Ezequiel 30 January 2010 в 17:56
поделиться

2 ответа

Django в целом имеет очень хорошую поддержку Unicode (подробности см. в документации Django 1.1 "Unicode data"). В своем коде я обнаружил, что если у меня возникают проблемы с простыми функциями Unicode, то проблема обычно заключается в том, что я плохо понимаю детали Django, а не в том, что в Django есть ошибка в поддержке Unicode.

Страница "Unicode Data" говорит нам, что "Все бэкенды баз данных Django ... автоматически преобразуют строки, полученные из базы данных, в строки Python Unicode. Вам даже не нужно сообщать Django, какую кодировку использует ваша база данных: это делается прозрачно." Таким образом, ваш простой return self.nombre должен вернуть строку Python Unicode.

Однако, на странице Django 1.1 "Databases" есть важное замечание о том, как бэкенд MySQL обрабатывает utf8_bin collation:

...если вы действительно хотите чувствительные к регистру сравнения в определенном столбце или таблице, вы измените столбец или таблицы на использование коллизии utf8_bin. Главное, о чем следует помнить в этом случае это то, что если вы используете MySQLdb 1.2.2, то бэкенд базы данных в Django будет возвращать байтовые строки (вместо вместо строк юникода) для любых символьных полей, которые он получает из базы данных. Это сильное отклонение от обычной практики Django всегда возвращать строки юникода. Это зависит от вас, разработчика, чтобы справиться с тем. тот факт, что вы будете получать байтовые строки, если вы настроите вашу таблицу(и) на использование коллизии 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')

Второй подход заключается в изменении кодировки MySQL для столбца "nombre", что заставляет MySQL-бэкенд Django возвращать строки Python Unicode вместо необычных байтовых строк. Тогда ваше исходное выражение дает строку Python Unicode:

return self.nombre

Надеюсь, это поможет.

17
ответ дан 5 December 2019 в 05:26
поделиться

Хорошо...

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

делает трюк.

Но также выяснилось, что замена utf8_bin на utf8_general_ci делает трюк, т.е. self.nombre работает, как и ожидалось.

2
ответ дан 5 December 2019 в 05:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: