6

我有一个 django 项目,它使用可以由外部工具写入的 sqlite 数据库。文本应该是 UTF-8,但在某些情况下会出现编码错误。文本来自外部来源,因此我无法控制编码。是的,我知道我可以在外部源和数据库之间编写一个“包装层”,但我不想这样做,特别是因为数据库已经包含很多“坏”数据。

sqlite 中的解决方案是将 text_factory 更改为: lambda x: unicode(x, "utf-8", "ignore")

但是,我不知道如何告诉 Django 模型驱动程序。

我得到的例外是:

'Could not decode to UTF-8 column 'Text' with text' in /var/lib/python-support/python2.5/django/db/backends/sqlite3/base.py in execute

不知何故,我需要告诉 sqlite 驱动程序不要尝试将文本解码为 UTF-8(至少不使用标准算法,但它需要使用我的故障安全变体)。

4

6 回答 6

9

sqlite 中的解决方案是将 text_factory 更改为: lambda x: unicode(x, "utf-8", "ignore")

但是,我不知道如何告诉 Django 模型驱动程序。

你有没有尝试过

from django.db import connection
connection.connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")

在运行任何查询之前?

于 2010-06-18T21:11:35.800 回答
2

受米拉回答的启发,考虑以下猴子补丁,它将更宽容的 text_factory 安装到 django sqlite 连接中。当您无法控制如何将文本添加到 sqlite 数据库并且它可能不在 utf-8 中时使用。当然,这里使用的编码可能不是正确的,但至少你的应用程序不会崩溃。

import types
from django.db.backends.sqlite3.base import DatabaseWrapper

def to_unicode( s ):
    ''' Try a number of encodings in an attempt to convert the text to unicode. '''
    if isinstance( s, unicode ):
        return s
    if not isinstance( s, str ):
        return unicode(s)

    # Put the encodings you expect here in sequence.
    # Right-to-left charsets are not included in the following list.
    # Not all of these may be necessary - don't know.
    encodings = (
        'utf-8',
        'iso-8859-1', 'iso-8859-2', 'iso-8859-3',
        'iso-8859-4', 'iso-8859-5',
        'iso-8859-7', 'iso-8859-8', 'iso-8859-9',
        'iso-8859-10', 'iso-8859-11',
        'iso-8859-13', 'iso-8859-14', 'iso-8859-15',
        'windows-1250', 'windows-1251', 'windows-1252',
        'windows-1253', 'windows-1254', 'windows-1255',
        'windows-1257', 'windows-1258',
        'utf-8',     # Include utf8 again for the final exception.
    )
    for encoding in encodings:
        try:
            return unicode( s, encoding )
        except UnicodeDecodeError as e:
            pass
    raise e

if not hasattr(DatabaseWrapper, 'get_new_connection_is_patched'):
    _get_new_connection = DatabaseWrapper.get_new_connection
    def _get_new_connection_tolerant(self, conn_params):
        conn = _get_new_connection( self, conn_params )
        conn.text_factory = to_unicode
        return conn

    DatabaseWrapper.get_new_connection = types.MethodType( _get_new_connection_tolerant, None, DatabaseWrapper )
    DatabaseWrapper.get_new_connection_is_patched = True
于 2015-03-01T14:29:06.887 回答
0
from django.db import connection
connection.cursor()
connection.connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")

在我的具体情况下,我需要设置 connection.connection.text_factory = str

于 2014-09-22T14:15:08.040 回答
0

看来,这个问题经常出现,并且引起了许多人的极大兴趣。(因为这个问题有超过一千个观点和相当多的支持)

所以这是我为这个问题找到的答案,在我看来这是最方便的答案:

我检查了django sqlite3连接器并将str转换直接添加到get_new_connection(...)函数中:

def get_new_connection(self, conn_params):
    conn = Database.connect(**conn_params)
    conn.create_function("django_date_extract", 2, _sqlite_date_extract)
    conn.create_function("django_date_trunc", 2, _sqlite_date_trunc)
    conn.create_function("django_datetime_extract", 3, _sqlite_datetime_extract)
    conn.create_function("django_datetime_trunc", 3, _sqlite_datetime_trunc)
    conn.create_function("regexp", 2, _sqlite_regexp)
    conn.create_function("django_format_dtdelta", 5, _sqlite_format_dtdelta)
    conn.text_factory = str
    return conn

它似乎可以正常工作,并且不必单独检查每个请求中的 unicode 问题。不应该考虑将它添加到 django 代码(?),因为我不建议任何人手动修改他的 django 后端代码......

于 2013-11-13T22:39:22.043 回答
0

使用来自 Django的一个神奇的str 函数来提供数据:

smart_str(s, encoding='utf-8', strings_only=False, errors='strict')

或者

smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict')
于 2010-04-30T13:16:28.143 回答
0

不兼容的 Django 版本。首先检查 Django 版本以解决此错误。我在 Django==3.0.8 上运行,它产生了一个错误。比我在有 Django==3.1.2 的地方运行 virtualenv 并删除了错误。

于 2020-10-08T13:24:14.943 回答