【问题标题】:Flask, SQLAlchemy and Jinja2 - UnicodeDecodeErrorFlask、SQLAlchemy 和 Jinja2 - UnicodeDecodeError
【发布时间】:2013-10-04 16:16:44
【问题描述】:

我有一个使用 Flask、SQLAlchemy 和 WTForms 的 Web 应用程序,以及必要的 Flask 扩展以使其正常工作。 MySQL 正在为所有表和列使用utf8_bin

我插入了一些中文字符,phpMyAdmin 可以正确显示它们,但是每当我尝试打开页面时,都会出现以下异常:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)

我知道我应该 decode('utf8') 我想显示的字段,但这不应该由 SQLAlchemy 为我处理吗?

我设法完成这项工作的唯一方法是遍历结果列表并执行类似的操作:

object.property = object.property.decode('utf8')

但显然这不应该是手工完成的。我错过了什么?

更新:SQLAlchemy 映射

class Thread(db.Model):

    __tablename__ = 'Thread'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.Unicode(255), nullable=False)
    body = db.Column(db.Text, nullable=True)
    date_created = db.Column(db.DateTime, nullable=False, default=datetime.now())
    created_by = db.Column(db.Integer, ForeignKey(User.id))
    user = relationship(User, backref='threads')
    display_hash = db.Column(db.Unicode(255), nullable=False, unique=True)
    display_name = db.Column(db.Unicode(255), nullable=True)
    nsfw = db.Column(db.Boolean, nullable=False, default=False)
    last_updated = db.Column(db.DateTime, nullable=False)

    def __init__(self, title=None, body=None, category_id=None, display_name=None):
        self.title = title
        self.body = body
        self.category_id = category_id
        self.display_name = display_name
        self.display_hash = custom_uuid()
        self.last_updated = self.date_created

    def __repr__(self):
        return u'<Thread %r>' % (self.title)

    def url_title(self):
        """ Generates an ASCII-only slug. """

        result = []
        for word in _punct_re.split(self.title.lower()):
            result.extend(unidecode(word).split())
        return unicode(u'-'.join(result))

更新:堆栈跟踪

`127.0.0.1 - - [06/Oct/2013 02:37:15] "GET /index HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/views.py", line 90, in index
    return render_template('index.html', threads=threads, pagination=pagination)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/templating.py", line 128, in render_template
    context, ctx.app)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/flask/templating.py", line 110, in _render
    rv = template.render(context)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render
    return self.environment.handle_exception(exc_info, True)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/templates/index.html", line 1, in top-level template code
    {% extends 'base.html' %}
  File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/templates/base.html", line 50, in top-level template code
    {% block content %}
  File "/Users/homedirectory/Projects/Assorted/Fruit Show/app/templates/index.html", line 14, in block "content"
    <a href="{{ url_for('new_thread') }}/{{ thread.display_hash|safe }}/{{ thread.url_title()|safe }}">{{ thread.title|safe }}</a>
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/jinja2/filters.py", line 747, in do_mark_safe
    return Markup(value)
  File "/Users/homedirectory/.virtualenvs/fruitshow/lib/python2.7/site-packages/markupsafe/__init__.py", line 72, in __new__
    return text_type.__new__(cls, base)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)`

更新:项目 repo 的 URL:

https://github.com/ruipacheco/fruitshow

【问题讨论】:

  • 请使用您遇到问题的 SQLAlchemy 模型更新您的问题。
  • 感谢您的更新。您是否还可以更新您的问题并提供可用于复制错误的简短代码 sn-p,包括代码提供的完整堆栈跟踪。
  • 不确定我是否可以添加任何代码,因为没有,都是框架。我将数据放入数据库。 phpMyAdmin 显示正确的字符。我把数据拿出来,别碰它,Jinja2 死了。连接字符串已经有 ?charset=utf8 来表示我们想要 utf8 的 db。
  • 添加了堆栈跟踪来回答。将use_unicode=1 添加到连接字符串没有帮助。

标签: python sqlalchemy flask jinja2 flask-sqlalchemy


【解决方案1】:

问题出在我正在使用的 MySQL 驱动程序上。

我按照this 回答并将列类型从utf8_bin 切换到utf8_general_ci 就成功了。

【讨论】:

    【解决方案2】:

    Models 中的 Slug 字段的一点建议。

    有一个名为 Webhelpers (https://pypi.python.org/pypi/WebHelpers) 的库,导入它,您的标题将自动转换为 slug。

    安装WebHelpers,然后导入urlify

    from webhelpers.text import urlify
    .
    .
    .
    @property
    def slug(self):
        return urlify(self.title)
    

    【讨论】:

      【解决方案3】:

      在连接参数中设置字符集只会告诉 mysql 将列从数据库中的列转码为请求的格式编码。数据仍然以字节的形式在 MySQL 和客户端之间传递。简而言之,您必须告诉 sqlalchemy“这个特定”数据是 unicode 数据(在连接的编码中)。对于您的大多数列,您使用了Unicode,它可以用于此目的。一个值得注意的突出之处是body,它的类型是Text。你可能想要UnicodeTextText(convert_unicode=True)

      【讨论】:

        【解决方案4】:

        不是你的答案,但让我推荐ftfy(为你修复文本),它修复了一堆小的 unicode 和 html 转义问题。 Unicode 编码中一场真正令人讨厌的宗教战争是 UTF-8 无法处理各种单字节字符编码,例如 Latin-1。解码器不只是说“哦,那一定是一个简单的拉丁字符”,而是变得慌乱。当您的数据库驱动程序观察到“哦,这很合适”时,它会在 fatwah 处创建。

        【讨论】:

          猜你喜欢
          • 2012-08-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-25
          • 2018-11-27
          • 2014-05-20
          • 1970-01-01
          • 2012-12-19
          相关资源
          最近更新 更多