《Python Cookbook(第3版)中文版》——6.8 同关系型数据库进行交互

    xiaoxiao2024-08-21  102

    本节书摘来自异步社区《Python Cookbook(第3版)中文版》一书中的第6章,第6.8节,作者[美]David Beazley , Brian K.Jones,陈舸 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    6.8 同关系型数据库进行交互

    6.8.1 问题

    我们需要选择、插入或者删除关系型数据库中的行数据。

    6.8.2 解决方案

    在Python中,表达行数据的标准方式是采用元组序列。例如:

    stocks = [ ('GOOG', 100, 490.1), ('AAPL', 50, 545.75), ('FB', 150, 7.45), ('HPQ', 75, 33.2), ]

    当数据以这种形式呈现时,通过Python标准的数据库API(在PEP 249中描述)来同关系型数据库进行交互相对来说就显得很直接了。该API的要点就是数据库上的所有操作都通过SQL查询来实现。每一行输入或输出数据都由一个元组来表示。

    为了说明,我们可以使用Python自带的sqlite3模块。如果正在使用一个不同的数据库(如MySQL、Postgres或者ODBC),就需要安装一个第三方的模块来支持。但是,底层的编程接口即使不完全相同的话也几乎是一致的。

    第一步是连接数据库。一般来说,要调用一个connect()函数,提供类似数据库名称、主机名、用户名、密码这样的参数以及一些其他需要的细节。示例如下:

    >>> import sqlite3 >>> db = sqlite3.connect('database.db') >>>

    要操作数据的话,下一步就要创建一个游标(cursor)。一旦有了游标,就可以开始执行SQL查询了。示例如下:

    >>> c = db.cursor() >>> c.execute('create table portfolio (symbol text, shares integer, price real)') <sqlite3.Cursor object at 0x10067a730> >>> db.commit() >>>

    要在数据中插入行序列,可以采用这样的语句:

    >>> c.executemany('insert into portfolio values (?,?,?)', stocks) <sqlite3.Cursor object at 0x10067a730> >>> db.commit() >>>

    要执行查询操作,可以使用下面这样的语句:

    >>> for row in db.execute('select * from portfolio'): ... print(row) ... ('GOOG', 100, 490.1) ('AAPL', 50, 545.75) ('FB', 150, 7.45) ('HPQ', 75, 33.2) >>>

    如果想执行的查询操作需要接受用户提供的输入参数,请确保用?隔开参数,就像下面的示例这样:

    >>> min_price = 100 >>> for row in db.execute('select * from portfolio where price >= ?', (min_price,)): ... print(row) ... ('GOOG', 100, 490.1) ('AAPL', 50, 545.75) >>>

    6.8.3 讨论

    从较低的层次来看,同数据库的交互其实是一件非常直截了当的事。只要组成SQL语句然后将它们传给底层的模块就可以更新数据库或者取出数据了。尽管如此,这里还是有一些比较棘手的细节问题需要针对每种情况逐项考虑。

    其中一个比较复杂的问题就是将数据库中的数据映射到Python的类型中。对于像日期这样的条目,最常见的是使用datetime模块中的datetime实例,或者也可能是time模块中用到的系统时间戳(system timestamps)。对于数值型的数据,尤其是涉及小数的金融数据,这些数字可以用decimal模块中的Decimal实例来表示。不幸的是,确切的映射关系会因数据库后端的不同而有所区别,因此必须去阅读相关的文档。

    另一个极其重要的问题是需要考虑组成SQL语句的字符串。我们绝对不应该用Python的字符串格式化操作符(即%)或者.format()方法来创建这种字符串。如果给这样的格式化操作符提供的值是来自于用户的输入,那么这就等于将你的程序敞开大门迎接SQL注入攻击(参见http://xkcd.com/327 )。在查询操作中,特殊的?通配符会指示数据库后端启用自己的字符串替换机制,这样才能做到安全(希望如此)。

    可悲的是,数据库后端对通配符的支持并不一致。有许多模块采用的是?或%s,而其他一些可能会使用不同的符号,比如用:0或者:1来代表参数。这里再次说明,必须查阅正在使用的数据库模块的文档资料。数据库模块的paramstyle属性中也包含有关于引用样式的相关信息。

    对于简单地三趸将数据从数据库表项中取出和输入,使用数据库API通常足够了。如果要处理更加复杂的任务,那么使用一种更高层次的接口就显得很有意义了,比如那些提供有对象关系映射组件(object-relational mapper,ORM)的接口。像SQLAlchemy(http://www.sqlalchemy.org )这样的库允许数据库表项以Python类的形式来描述,在执行数据库操作时可隐藏大部分底层的SQL。

    相关资源:Python Cookbook 第三版中文
    最新回复(0)