【问题标题】:Unicode Problem with SQLAlchemySQLAlchemy 的 Unicode 问题
【发布时间】:2010-11-01 06:26:43
【问题描述】:

我知道我在从 Unicode 转换时遇到问题,但我不确定它发生在哪里。

我正在从 HTML 文件目录中提取有关最近一次欧洲旅行的数据。一些位置名称包含非 ASCII 字符(例如 é、ô、ü)。我正在使用正则表达式从文件的字符串表示中获取数据。

如果我在找到它们时打印位置,它们会打印字符,因此编码必须没问题:

Le Pré-Saint-Gervais, France
Hôtel-de-Ville, France

我正在使用 SQLAlchemy 将数据存储在 SQLite 表中:

Base = declarative_base()
class Point(Base):
    __tablename__ = 'points'

    id = Column(Integer, primary_key=True)
    pdate = Column(Date)
    ptime = Column(Time)
    location = Column(Unicode(32))
    weather = Column(String(16))
    high = Column(Float)
    low = Column(Float)
    lat = Column(String(16))
    lon = Column(String(16))
    image = Column(String(64))
    caption = Column(String(64))

    def __init__(self, filename, pdate, ptime, location, weather, high, low, lat, lon, image, caption):
        self.filename = filename
        self.pdate = pdate
        self.ptime = ptime
        self.location = location
        self.weather = weather
        self.high = high
        self.low = low
        self.lat = lat
        self.lon = lon
        self.image = image
        self.caption = caption

    def __repr__(self):
        return "<Point('%s','%s','%s')>" % (self.filename, self.pdate, self.ptime)

engine = create_engine('sqlite:///:memory:', echo=False)
Base.metadata.create_all(engine)
Session = sessionmaker(bind = engine)
session = Session()

我遍历文件并将每个文件中的数据插入数据库:

for filename in filelist:

    # open the file and extract the information using regex such as:
    location_re = re.compile("<h2>(.*)</h2>",re.M)
    # extract other data

    newpoint = Point(filename, pdate, ptime, location, weather, high, low, lat, lon, image, caption)
    session.add(newpoint)
    session.commit()

我在每次插入时看到以下警告:

/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/default.py:230: SAWarning: Unicode type received non-unicode bind param value 'Spitalfields, United Kingdom'
  param.append(processors[key](compiled_params[key]))

当我尝试对表格做任何事情时,例如:

session.query(Point).all()

我明白了:

Traceback (most recent call last):
  File "./extract_trips.py", line 131, in <module>
    session.query(Point).all()
  File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/orm/query.py", line 1193, in all
    return list(self)
  File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/orm/query.py", line 1341, in instances
    fetch = cursor.fetchall()
  File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/base.py", line 1642, in fetchall
    self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context)
  File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/base.py", line 931, in _handle_dbapi_exception
    raise exc.DBAPIError.instance(statement, parameters, e, connection_invalidated=is_disconnect)
sqlalchemy.exc.OperationalError: (OperationalError) Could not decode to UTF-8 column 'points_location' with text 'Le Pré-Saint-Gervais, France' None None

我希望能够正确存储位置名称,然后原封不动地返回位置名称。任何帮助将不胜感激。

【问题讨论】:

    标签: python unicode encoding character-encoding sqlalchemy


    【解决方案1】:

    尝试对 unicode 列使用 Unicode 列类型而不是 String:

    Base = declarative_base()
    class Point(Base):
        __tablename__ = 'points'
    
        id = Column(Integer, primary_key=True)
        pdate = Column(Date)
        ptime = Column(Time)
        location = Column(Unicode(32))
        weather = Column(String(16))
        high = Column(Float)
        low = Column(Float)
        lat = Column(String(16))
        lon = Column(String(16))
        image = Column(String(64))
        caption = Column(String(64))
    

    编辑:对评论的回应:

    如果您收到有关 unicode 编码的警告,那么您可以尝试以下两件事:

    1. 将您的位置转换为 Unicode。这意味着您的点创建如下:

      newpoint = Point(filename, pdate, ptime, unicode(location), weather, high, low, lat, lon, image, caption)

      无论是传入字符串还是unicode字符串,unicode转换都会产生unicode字符串,所以你不用担心传入的内容。

    2. 如果这不能解决编码问题,请尝试在 unicode 对象上调用 encode。这意味着使用如下代码:

      newpoint = Point(filename, pdate, ptime, unicode(location).encode('utf-8'), weather, high, low, lat, lon, image, caption)

      这一步可能不是必需的,但它本质上所做的是将 unicode 对象从 unicode 代码点转换为特定的字节表示形式(在本例中为 utf-8)。我希望 SQLAlchemy 在您传入 unicode 对象时为您执行此操作,但它可能不会。

    【讨论】:

    • 感谢您的建议。我认为这将我引向正确的方向。我现在收到有关我正在插入的数据编码的警告,但我不确定如何解决这个问题。我已更新我的问题以反映您的建议。
    【解决方案2】:

    来自sqlalchemy.org

    参见第 0.4.2 节

    为字符串添加了新标志和 创建引擎(), 断言 _unicode=(True|False|'warn'|None)。 默认为 FalseNone on 在 Unicode 类型上创建 _engine() 和 String, 'warn'。什么时候 True, 导致所有 unicode 转换操作引发 异常时 非 unicode 字节串作为绑定参数传递。 “警告”结果 在警告中。强烈建议所有 unicode 感知 应用 正确使用 Python unicode 对象(即 u'hello' 而不是 '你好') 以便数据往返准确。

    我认为您正在尝试输入非 unicode 字节串。也许这可能会引导你走上正确的轨道?需要某种形式的转换,比较 'hello' 和 u'hello'。

    干杯

    【讨论】:

      【解决方案3】:

      我发现这篇文章在一定程度上解释了我的烦恼:

      http://www.amk.ca/python/howto/unicode#reading-and-writing-unicode-data

      我能够通过使用“编解码器”模块获得所需的结果,然后按如下方式更改我的程序:

      打开文件时:

      infile = codecs.open(filename, 'r', encoding='iso-8859-1')
      

      打印位置时:

      print location.encode('ISO-8859-1')
      

      我现在可以查询和操作表中的数据,而不会出现以前的错误。我只需要在输出文本时指定编码。

      (我仍然不完全理解它是如何工作的,所以我想是时候了解更多关于 Python 的 unicode 处理了......)

      【讨论】:

      猜你喜欢
      • 2012-10-15
      • 2017-09-19
      • 1970-01-01
      • 2021-03-27
      • 1970-01-01
      • 2010-10-22
      • 2022-11-17
      • 2011-02-21
      • 2010-09-16
      相关资源
      最近更新 更多