小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

使用 SQLAlchemy

 Dawnxu 2009-05-15

Noah Gift, 軟件工程師, Giftcs

2008 年 10 月 23 日

SQLAlchemy 是下一代的 Python Object Relational 映射器。通過本文您將了解如何使用新的 0.5 API、與第三方組件協(xié)作,并構(gòu)建一個基本的 Web 應用程序。

簡介

對 象關(guān)系映射器(Object Relational Mappers,ORM)在過去數(shù)年吸引了不少人的目光。主要原因是 ORM 經(jīng)常會在 Web 應用程序框架中被提起,因為它是快速開發(fā)(Rapid Development)棧中的關(guān)鍵組件。Django 和 Ruby on Rails 等 Web 框架采用了設計一個獨立棧的方法,將自主開發(fā)的 ORM 緊密集成到該框架中。而其他框架,如 Pylons、Turbogears 和 Grok,則采用更加基于組件的架構(gòu)結(jié)合可交換的第三方組件。兩種方法都有各自的優(yōu)勢:緊密集成允許非常連貫的體驗(如果問題映射到框架),而基于組件的 架構(gòu)則允許最大的設計靈活性。但是,本文的主題并不是 Web 框架;而是 SQLAlchemy。

SQLAlchemy 在構(gòu)建在 WSGI 規(guī)范上的下一代 Python Web 框架中得到了廣泛應用,它是由 Mike Bayer 和他的核心開發(fā)人員團隊開發(fā)的一個單獨的項目。使用 ORM 等獨立 SQLAlchemy 的一個優(yōu)勢就是它允許開發(fā)人員首先考慮數(shù)據(jù)模型,并能決定稍后可視化數(shù)據(jù)的方式(采用命令行工具、Web 框架還是 GUI 框架)。這與先決定使用 Web 框架或 GUI 框架,然后再決定如何在框架允許的范圍內(nèi)使用數(shù)據(jù)模型的開發(fā)方法極為不同。

什么是 WSGI?

WSGI 是下一代 Python Web 框架、應用程序和服務器應該遵循的規(guī)范。WSGI 中 一個有趣的方面是創(chuàng)建 Python 中間件,并在使用 Python 或任何語言創(chuàng)建的 Web 應用程序中使用。請參閱 參考資料,獲取關(guān)于 WSGI 和 WSGI 社區(qū)(Pypefitters)的大量鏈接。

SQLAlchemy 的一個目標是提供能兼容眾多數(shù)據(jù)庫(如 SQLite、MySQL、Postgres、Oracle、MS-SQL、SQLServer 和 Firebird)的企業(yè)級持久性模型。SQLAlchemy 正處于積極開發(fā)階段,當前最新的 API 將圍繞版本 0.5 設計。請參閱參考資料部分,獲取官方 API 文檔、教程和 SQLAlchemy 書籍的鏈接。

SQLAlchemy 取得成功的一個證明就是圍繞它已建立了豐富的社區(qū)。針對 SQLAlchemy 的擴展和插件包括:declarative、Migrate、Elixir、SQLSoup、django-sqlalchemy、 DBSprockets、FormAlchemy 和 z3c.sqlalchemy。在本文中,我們將學習一篇關(guān)于新 0.5 API 的教程,探究一些第三方庫,以及如何在 Pylons 中使用它們。

誰是 Mike Bayer?

Michael Bayer 是居住在紐約的一名軟件承包商,他擁有十余年處理各類關(guān)系數(shù)據(jù)庫的經(jīng)驗。他曾使用 C、Java? 和 Perl 編寫了許多自主研發(fā)的數(shù)據(jù)庫抽象層,并在 Major League Baseball 與大量多服務器 Oracle 系統(tǒng)打了多年交道,借助這些經(jīng)驗,他成功編寫了 “終極工具包” SQLAlchemy,用于生成 SQL 和處理數(shù)據(jù)庫。其目標是貢獻一個世界級、獨樹一幟的面向 Python 的工具包,以幫助 Python 成為一個廣泛普及的編程平臺。

安裝

本文假定您使用 Python 2.5 或更高版本,并且安裝了子版本。Python 2.5 包括 SQLite 數(shù)據(jù)庫,因此也是測試 SQLALchemy 內(nèi)存的好工具。如果您已經(jīng)安裝了 Python 2.5,則只需通過設置工具安裝 sqlalchemy 0.5 beta 。要獲取設置工具腳本,請在您的終端中下載并運行以下 4 條命令:

  wget http://peak./dist/ez_setup.py
                    python ez_setup.py
                    sudo easy_install http://svn./sqlalchemy/trunk
                    sudo easy_install ipython
                    

前 三行代碼檢查最新版本的 sqlalchemy,并將它作為包添加到您本地系統(tǒng)的 Python 安裝中。最后一個代碼片段將安裝 IPython,它是一個實用的聲明式 Python 解釋器,我將在本文中使用它。首先,我需要測試已安裝的 SQLAlchemy 版本。您可以測試自己的版本是否為 0.5.x,方法是在 IPython 或普通 Python 解釋器中發(fā)起以下命令。

 In [1]: import sqlalchemy
                    In [2]: sqlalchemy.__version__
                    Out[2]: '0.5.0beta1'
                    

SQLAlchemy 0.5 快速入門指南

新的 0.5 發(fā)行版在 SQLAlchemy 中引入了一些顯著的變更。此外列出了這些變更的概要信息:

  • 聲明式擴展是多數(shù)情況下建議的開始方式。
  • session.query() 可以接受任意組合的 class/column 表達式。
  • session.query() 或多或少也是 select() 的支持 ORM 的替代方法。
  • 查詢提供了一些試驗性的 update()/delete() 方法,用于實現(xiàn)基于標準的更新/刪除。
  • 會話將在 rollback() 和 commit() 方法后自動過期;因此使用默認的 sessionmaker() 意味著您通常不必調(diào)用 clear() 或 close();對象將自動與當前的事務同步。
  • 使用 session.add()、session.add_all()(save/update/save_or_update 已刪除)在會話中添加內(nèi)容。

雖然 declarative 擴展從 0.4 開始便一直出現(xiàn)在 SQLAlchemy 中,但它也經(jīng)過了一些小修改,這使它在大多數(shù) SQLAlchemy 項目中都成為了一種強有力的便捷方式。新的 declarative 語法允許在一步中創(chuàng)建表、類和數(shù)據(jù)庫映射。下面我們來看看這種新語法的工作原理,以我編寫的一個用于跟蹤文件系統(tǒng)變化的工具為例。


清單 1. 新 SQLAlchemy 聲明樣式
                    #/usr/bin/env python2.5
                    #Noah Gift
                    from sqlalchemy.ext.declarative import declarative_base
                    from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
                    Base = declarative_base()
                    class Filesystem(Base):
                    __tablename__ = 'filesystem'
                    path = Column(String, primary_key=True)
                    name = Column(String)
                    def __init__(self, path,name):
                    self.path = path
                    self.name = name
                    def __repr__(self):
                    return "<Metadata('%s','%s')>" % (self.path,self.name)
                    

通 過這種新的聲明樣式,SQLAlchemy 能夠在一步中創(chuàng)建一個數(shù)據(jù)庫表、創(chuàng)建一個類以及類與表之間的映射。如果您剛開始接觸 SQLAlchemy,或許應該學習這種建立 ORM 的方法。此外,了解另一種更加顯式地控制各步驟的方式也是有益的(如果您的項目要求這種級別的詳細程度)。

在閱讀這段代碼時,需要指出一些可能會讓初次接觸 SQLAlchemy 或聲明性擴展的用戶犯難的地方。首先,

Base = declarative_base()

行創(chuàng)建了一個類,稍后的 Filesystem 類便繼承自該類。如果您保存并在 declarative_style 中運行該代碼,然后將它導入到 IPython 中,則會看到以下輸出:
In [2]: declarative_style.Filesystem?
                    Type:		DeclarativeMeta
                    Base Class:	<class 'sqlalchemy.ext.declarative.DeclarativeMeta'>
                    String Form:	<class 'declarative_style.Filesystem'>
                    

這個 DeclarativeMeta 類型的魔力就是允許所有操作發(fā)生在一個簡單的類定義中。

另一個需要指出的地方是本示例并未實際執(zhí)行任何操作。在運行創(chuàng)建表的代碼之前,將不會創(chuàng)建實際的表,并且,您還需要定義 SQLAlchemy 將使用的數(shù)據(jù)庫引擎。這兩行代碼如下所示:

       engine = create_engine('sqlite:///meta.db', echo=True)
                    Base.metadata.create_all(engine)
                    

SQlite 是試驗 SQLAlchemy 的理想選擇,并且您還可以選擇使用內(nèi)存數(shù)據(jù)庫,在這種情況下,您的代碼行應如下所示:

        engine = create_engine('sqlite:///:memory:', echo=True)
                    

或者,只創(chuàng)建一個簡單的文件,如第一個例子所示。如果您選擇創(chuàng)建一個基于 SQLite 文件的數(shù)據(jù)庫,則可以通過拋棄數(shù)據(jù)庫中的所有表從零開始,而不需要刪除文件。為此,您可以發(fā)起以下代碼行:

                    Base.metadata.drop_all(engine)
                    

此 時,我們已經(jīng)了解了創(chuàng)建 SQLAlchemy 項目和通過 SQLAlchemy API 控制數(shù)據(jù)庫所需的知識。在開始實際應用之前,惟一需要掌握一點是會話的概念。SQLAlchemy “官方” 文檔將會話描述為數(shù)據(jù)庫的句柄。在實際應用中,它允許不同的基于事務的連接發(fā)生在 SQLAlchemy 一直在等待的連接池中。在會話內(nèi)部,這通常是添加數(shù)據(jù)到數(shù)據(jù)庫中、執(zhí)行查詢或刪除數(shù)據(jù)。

要創(chuàng)建會話,請執(zhí)行下面這些后續(xù)步驟:

        #establish Session type, only need to be done once for all sessions
                    Session = sessionmaker(bind=engine)
                    #create record object
                    create_record = Filesystem("/tmp/foo.txt", "foo.txt")
                    #make a unique session
                    session = Session()
                    #do stuff in session.  We are adding a record here
                    session.add(create_record)
                    #commit the transaction
                    session.commit()
                    

這 些就是使 SQLAlchemy 正常運行所需的所有工作。雖然 SQLAlchemy 提供了一個非常復雜的 API 來處理許多復雜的事情,但它實際上非常容易使用。在本節(jié)結(jié)束時,我還想指出,上例使用 echo=True 創(chuàng)建引擎。這是查看由 SQLAlchemy 創(chuàng)建的 SQL 的便捷方法。對于 SQLAlchemy 初學者,強烈建議使用該方法,因為它會讓您覺得 SQLAlchemy 不再那么神秘。現(xiàn)在,運行自己創(chuàng)建的一些代碼,并查看 SQL 創(chuàng)建表的過程。


清單 2. SQLAlchemy SQL 表創(chuàng)建輸出
2008-06-22 05:33:46,403 INFO
                    sqlalchemy.engine.base.Engine.0x..ec PRAGMA
                    table_info("filesystem")
                    2008-06-22 05:33:46,404 INFO sqlalchemy.engine.base.Engine.0x..ec {}
                    2008-06-22 05:33:46,405 INFO sqlalchemy.engine.base.Engine.0x..ec
                    CREATE TABLE filesystem (
                    path VARCHAR NOT NULL,
                    name VARCHAR,
                    PRIMARY KEY (path)
                    )
                    

Pylesystem:類似于 Spotlight 或 Beagle 的實時文件系統(tǒng)元數(shù)據(jù)索引程序

抽 象地討論如何使用某個工具會讓許多人不好理解,因此,我將使用 SQLAlchemy 演示如何創(chuàng)建一個元數(shù)據(jù)工具。此工具的目標是監(jiān)控文件系統(tǒng)、創(chuàng)建和刪除事件,以及在一個 SQLAlchemy 數(shù)據(jù)庫中保存這些變更的記錄。如果您曾經(jīng)在 OS X 上使用過 Spotlight,或在 Linux? 上使用過 Beagle,那就應該使用過一款實時的文件系統(tǒng)索引工具。要繼續(xù)本文,您需要運行 Linux 內(nèi)核 2.6.13 或更高版本。

下一個示例比較大,大約有 100 行代碼。查看整個示例并運行它,然后,我將介紹代碼各部分的作用。要運行此腳本,您必須在終端中執(zhí)行以下步驟:

  1. wget http://peak./dist/ez_setup.py
  2. sudo python ez_setup.py
  3. sudo easy_install
    "http://git./?p=pyinotify.git;a=snapshot;h=HEAD;sf=tgz"
  4. sudo easy_install http://svn./sqlalchemy/trunk

清單 3. 文件系統(tǒng)事件監(jiān)控數(shù)據(jù)庫
#/usr/bin/env python2.5
                    #Noah Gift 06/21/08
                    #tweaks by Mike Bayer 06/22/08
                    import os
                    from sqlalchemy.ext.declarative import declarative_base
                    from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
                    from sqlalchemy import create_engine
                    from sqlalchemy.orm import sessionmaker
                    from sqlalchemy.orm import scoped_session
                    from pyinotify import *
                    path = "/tmp"
                    #SQLAlchemy
                    engine = create_engine('sqlite:///meta.db', echo=True)
                    Base = declarative_base()
                    Session = scoped_session(sessionmaker(bind=engine))
                    class Filesystem(Base):
                    __tablename__ = 'filesystem'
                    path = Column(String, primary_key=True)
                    name = Column(String)
                    def __init__(self, path,name):
                    self.path = path
                    self.name = name
                    def __repr__(self):
                    return "<Metadata('%s','%s')>" % (self.path,self.name)
                    def transactional(fn):
                    """add transactional semantics to a method."""
                    def transact(self, *args):
                    session = Session()
                    try:
                    fn(self, session, *args)
                    session.commit()
                    except:
                    session.rollback()
                    raise
                    transact.__name__ = fn.__name__
                    return transact
                    class ProcessDir(ProcessEvent):
                    """Performs Actions based on mask values"""
                    @transactional
                    def process_IN_CREATE(self, session, event):
                    print "Creating File and File Record:", event.pathname
                    create_record = Filesystem(event.pathname, event.path)
                    session.add(create_record)
                    @transactional
                    def process_IN_DELETE(self, session, event):
                    print "Removing:", event.pathname
                    delete_record = session.query(Filesystem).                    filter_by(path=event.pathname).one()
                    session.delete(delete_record)
                    def init_repository():
                    #Drop the table, then create again with each run
                    Base.metadata.drop_all(engine)
                    Base.metadata.create_all(engine)
                    session = Session()
                    #Initial Directory Walking Addition Brute Force
                    for dirpath, dirnames, filenames in os.walk(path):
                    for file in filenames:
                    fullpath = os.path.join(dirpath, file)
                    record = Filesystem(fullpath, file)
                    session.add(record)
                    session.flush()
                    for record in session.query(Filesystem):
                    print "Database Record Number: Path: %s , File: %s "                     % (record.path, record.name)
                    session.commit()
                    if __name__ ==  "__main__":
                    init_repository()
                    #Pyionotify
                    wm = WatchManager()
                    mask = IN_DELETE | IN_CREATE
                    notifier = ThreadedNotifier(wm, ProcessDir())
                    notifier.start()
                    wdd = wm.add_watch(path, mask, rec=True)
                    

要查看此腳本的實際運行結(jié)果,您需要打開兩個終端窗口。在第一個窗口中,運行 pylesystem.py 腳本。您將看到一系列輸出內(nèi)容,如下所示(請注意,以下版本經(jīng)過適當縮減):

2008-06-22 07:18:08,707 INFO
                    sqlalchemy.engine.base.Engine.0x..ec ['/tmp/ba.txt', 'ba.txt']
                    2008-06-22 07:18:08,710 INFO
                    sqlalchemy.engine.base.Engine.0x..ec COMMIT
                    2008-06-22 07:18:08,715 INFO
                    sqlalchemy.engine.base.Engine.0x..ec BEGIN
                    2008-06-22 07:18:08,716 INFO
                    sqlalchemy.engine.base.Engine.0x..ec SELECT filesystem.path
                    AS filesystem_path, filesystem.name AS filesystem_name
                    FROM filesystem
                    2008-06-22 07:18:08,716 INFO sqlalchemy.engine.base.Engine.0x..ec []
                    Database Record Number: Path: /tmp/ba.txt , File: ba.txt
                    

第一個腳本運行一個多線程文件系統(tǒng)事件監(jiān)控引擎,它將 /tmp 的所有創(chuàng)建和刪除變更寫入到 sqlalchemy 數(shù)據(jù)庫中。注意:由于它是多線程的,當您 完成此教程時,需要鍵入 Control + \ 來停止線程應用程序。

成功運行之后,您可以在第二個終端窗口中創(chuàng)建事件,新創(chuàng)建或刪除的文件將實時添加到數(shù)據(jù)庫中或從數(shù)據(jù)庫中刪除。如果您只創(chuàng)建了 /tmp 目錄中的某個文件,比如說 touch foobar.txt,則會在第一個窗口中看到以下輸出:

Creating File and File Record: /tmp/foobar.txt
                    2008-06-22 08:02:19,468 INFO
                    sqlalchemy.engine.base.Engine.0x..4c BEGIN
                    2008-06-22 08:02:19,471 INFO
                    sqlalchemy.engine.base.Engine.0x..4c INSERT INTO filesystem (path, name) VALUES (?, ?)
                    2008-06-22 08:02:19,472 INFO
                    sqlalchemy.engine.base.Engine.0x..4c ['/tmp/foobar.txt', '/tmp']
                    2008-06-22 08:02:19,473 INFO
                    sqlalchemy.engine.base.Engine.0x..4c COMMIT
                    

記得您之前啟用了 SQL echo 嗎?鑒于此,當代碼將此新條目添加到文件系統(tǒng)中時,您可以看到 SQL 語句。如果您現(xiàn)在刪除該文件,您也可以看到刪除的過程。下面是您鍵入 rm 語句 rm foobar.txt 時的輸出:

Removing: /tmp/foobar.txt
                    2008-06-22 08:06:01,727 INFO
                    sqlalchemy.engine.base.Engine.0x..4c BEGIN
                    2008-06-22 08:06:01,733 INFO
                    sqlalchemy.engine.base.Engine.0x..4c SELECT filesystem.path
                    AS filesystem_path, filesystem.name AS filesystem_name
                    FROM filesystem
                    WHERE filesystem.path = ?
                    LIMIT 2 OFFSET 0
                    2008-06-22 08:06:01,733 INFO
                    sqlalchemy.engine.base.Engine.0x..4c ['/tmp/foobar.txt']
                    2008-06-22 08:06:01,736 INFO
                    sqlalchemy.engine.base.Engine.0x..4c DELETE FROM filesystem WHERE filesystem.path = ?
                    2008-06-22 08:06:01,736 INFO
                    sqlalchemy.engine.base.Engine.0x..4c [u'/tmp/foobar.txt']
                    2008-06-22 08:06:01,737 INFO
                    sqlalchemy.engine.base.Engine.0x..4c COMMIT
                    

在 Filesystem 類中,您添加了一個 transactional 方法,您將使用一個修飾類來處理將文件系統(tǒng)事件提交給數(shù)據(jù)庫的語義。Pyinotify 中的實際 Filesystem I/O 監(jiān)控由 ProcessDir 類完成,該類繼承自 ProcessEvents 并覆蓋了其中的方法。如果您注意了 process_IN_CREATE 和 process_IN_DELETE 方法,會發(fā)現(xiàn)它們都附加了一個 transactional 修飾類。隨后,它們將接受創(chuàng)建或刪除事件并對數(shù)據(jù)庫執(zhí)行修改。

還有一個名稱為 initial_repository 的方法,每次運行腳本時它都會填充數(shù)據(jù)庫,實現(xiàn)方法是銷毀數(shù)據(jù)庫中的表并重新創(chuàng)建。腳本的最底部將通知 Pyinotify 代碼以不確定的方式運行,而這最終表示作為守護進程運行。

結(jié)束語

本文介紹了 SQLAlchemy 的一些特性,并演示了它和 API 的使用是多么簡單。借助 SQLAlchemy 和開源庫 Pyinotify,您還使用不到 100 行 Python 代碼構(gòu)建了一個 功能異常強大的工具。這是簡單但功能強大的 ORM 的特性之一。它消除了復雜的關(guān)系數(shù)據(jù)庫處理操作,現(xiàn)在它為用戶添加了快樂而不是負擔。隨后,這些省下來的精力可以用于解決感興趣的問題,因為 SQLAlchemy 將是最簡單的環(huán)節(jié)。

如果您有興趣了解更多關(guān)于 SQLAlchemy 的信息,則應該閱讀本文末尾列出的 參考資料。 其中包括一本出色的書籍和大量優(yōu)秀的在線文檔,您可以考慮研究其他一些使用 SQLAlchemy 的項目并擴展它們。最近一個較有興趣的 SQLAlchemy 相關(guān)項目就是 Website reddit.com。它使用純 WSGI 框架 Pylons 構(gòu)建,并整合了 SQLAlchemy 作為其默認 ORM。我附帶了到 reddit 完整源代碼的鏈接。借助新掌握的 SQLAlchemy 知識,您應該能夠快速實現(xiàn)自己的 reddit,并且應該能執(zhí)行一些數(shù)據(jù)庫查詢操作。祝您好運!

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多