Archive for September 11th, 2007

在Python独立访问django数据模型

Tuesday, September 11th, 2007

在Python独立访问django数据模型

在需要使用其他独立运行的程序调用django的数据模型时往往会提示导入数据模型时的EnvironmentError异常。其实这都是因为没有正确的找到django的配置文件所造成的。这其实也难怪django,连数据库的连接信息都在settings.py中,没有指定这个文件当然没法使用模型了。

好了谈谈解决方法吧。按照django官方手册上的讲解,就是如下:

$ ./manage.py shell

这样就可以直接进入Python交互模式了,并且可以访问很多东东。

但是问题时,有时候需要使用其他独立运行的Python脚本来访问数据模型,也就不是在交互模式下。这时可以自己设置环境变量DJANGO_SETTINGS_MODULE来达到同样的效果。

对于交互模式可以这样运行:

$ DJANGO_SETTINGS_MODULE=settings python

这样的解释器就可以直接使用其他环境变量了。

也可以先设置好环境变量,然后再使用Python,不过这时如果系统当中有多个django工程时就比较麻烦了,总之自己考量吧。方法如下:

$ export -p DJANGO_SETTINGS_MODULE=settings
$ python

另外,有如前面说的,在有多个工程时,如果需要启动另外一个,则可以清除环境变量,如下:

$ export -n DJANGO_SETTINGS_MODULE

这样就又恢复到原来的样子了。

祝大家django愉快。

gashero的Pylons笔记

Tuesday, September 11th, 2007

gashero的Pylons笔记

目录

1   《Pylons初探》笔记

1.1   安装

  1. 下载安装工具ez_setup.py

  2. 命令行运行如下:

    python ez_setup.py Pylons
  3. 设置环境变量

    pyth -> C:Python24Scripts

  4. 运行命令paster,如果运行成功会出现如下结果:

    Usage: C:\Python24\Scripts\paster-script.py COMMAND
    ... ...

1.2   开始动手

  1. 新建一个Pylons工程:

    paster create --template=pylons helloworld

    运行成功后产生如下结果:

    Selected and implied templates::
    pylons#pylons  Pylons application template
    ... ...
  2. 运行这个新建的工程

    1. 启动服务器:

      cd helloworld
      paster serve --reload development.ini
    2. 访问 http://127.0.0.1:5000/ 将会看到欢迎页面

    3. helloworld/public 目录下创建test.html文件,内容如下:

      <html>
          <body>
              Hello world!
          </body>
      </html>
    4. 访问 http://127.0.0.1:5000/test.html 看到结果。

  3. 禁用调试功能

    将development.ini文件中的如下行的注释删除:

    # set debug=false
  4. 创建一个控制器,修改Routes

    1. 命令行运行:

      paster controller hello
    2. 修改 helloworld/controllers/hello.py ,代码如下:

      from helloworld.lib.base import *
      
      class HelloController(BaseController):
          def index(self):
              return Response('hello world')
    3. 修改 helloworld/config/routing.py ,代码如下:

      """
      Setup your Routes options here
      """
      import sys,os
      from routes import Mapper
      
      def make_map(global_conf={}, app_conf={}):
          root_path=os.path.dirname(os.path.dirname(\
                  os.path.abspath(__file__)))
          map=Mapper(directory=os.path.join(root_path,'controllers'))
          # 这个route handle用来显示错误页面
          map.connect('error/:action/:id', controller='error')
          #定义自己的route,可以定义很多细节
          #更多有用的信息参考http://routes.groovie.org/docs/
          map.connect('',controller='hello',action='index')
          map.connect(':controller/:action/:id')
          map.connect('*url',controller='template',action='view')
          return map
    4. 删除 public/index.html 。访问 http://127.0.0.1:5000/hellohttp://127.0.0.1:5000/ 将会看到 Hello world。

  5. 模板和请求周期

    1. 创建模板文件 helloworld/templates/serverinfo.myt ,代码如下:

      <p>Hi, here's the server environment: <br />
      <% str(request.environ) %></p>
      <p>
      and here's the URL you called: <% h.url_for() %>
      </p>
    2. 修改 helloworld/controllers/hello.py ,代码如下:

      from helloworld.lib.base import *
      class HelloController(BaseController):
          def index(self):
              return Response('hello world')
          def serverinfo(self):
              return render_response('/serverinfo.myt')
    3. 访问 http://127.0.0.1:5000/hello/serverinfo ,可以看到如下结果:

      Hi, here's the server environment:
      ... ...
      and here's the URL you called: /hello/serverinfo
  6. 使用Session,代码如下:

    def serverinfo(self):
        session['name']='George'
        session.save()
        return render_response('/serverinfo.myt')
  7. 控制器变量和模板全局变量

    控制器变量

    1. 修改 helloworld/controllers/hello.py ,代码如下:

      from helloworld.lib.base import *
      class HelloController(BaseController):
          def index(self):
              return Response('hello world')
          def serverinfo(self):
              c.value=2
              return render_response('/serverinfo.myt')
    2. 修改 helloworld/templates/serverinfo.myt ,代码如下:

      <p> The value of <tt>c.value</tt> is:
      <% c.value %>
    3. 访问 http://127.0.0.1:5000/hello/serverinfo ,可以看到 The value of c.value is: 2

    模板全局变量

    1. 修改 lib/app_globals.py ,代码如下:

      class Globals(object):
          def __init__(self,defaults,app,**extra):
              self.message='Hello'
          def __del__(self):
              """
              将清空代码放在这里
              """
              pass
    2. 修改 helloworld/controllers/hello.py ,代码如下:

      from helloworld.lib.base import *
      class HelloController(BaseController):
          def index(self):
              return Response('hello world')
          def serverinfo(self):
              c.value=2
              return render_response('/serverinfo.myt')
          def app_globals_test(self):
              resp=Response()
              if g.message=='Hello':
                  resp.write(g.message)
                  g.message='Hello world!'
              else:
                  resp.write(g.message)
              return resp
    3. 访问 http://127.0.0.1:5000/hello/app_globals_test/ ,可以看到 Hello world!

  8. 原文网址 http://pylonshq.com/docs/0.9.3/getting_started.html

2   Pylons首页信息

Pylons的最新版本为0.9.4.1,发布于2007-01-06。这是一个bugfix版本,原版本0.9.4发布于2006-12-29。上面那篇文章的对应版本为0.9.3,看来差的 还不是太远。

Pylons是一个轻量级的WEB开发框架,强调灵活性和快速开发。

2.1   为什么使用Pylons

Pylons结合了Ruby、Python和Perl的优点,提供了结构化的,但是却非常灵活的Python WEB开发框架。他也是首个支持新出现的WSGI标准的项目,在需要时允许广泛的重用和移植。Pylons的目标是使得WEB开发更加快速、灵活和简单。

更多信息

安装

开始学习

2.2   与其他组件一起使用

Pylons基于 Paste 并支持其他常见的Python组件:

2.3   最新的入门教程

2.4   有用的资源

你可能对 使用了Pylons的站点 感兴趣。如果你需要的信息在 文档 中是没有的,则可以参考 wiki ,这里的信息会有更快的更新,并且有更加全面的资源。当然,你也可以自己 添加文章

2.5   顶部导航栏链接

主页 文档 wiki 社区 FAQ 安装 Pastebin 查找文档

3   安装Pylons

首先,Windows上的Python2.3用户需要先安装 subprocess.exe (下载失效),而Python2.4用户则不需要。所有的Windows用户在安装完成后需要研读 安装后必读 ,而Ubuntu和Debian用户则需要安装 python-dev 包。

3.1   系统级安装

如果需要安装好的Pylons被所有用户所使用,就需要使用root帐户。如果你已经拥有了easy install,则可以执行如下命令:

$ easy_install Pylons

Note

偶尔python.org会挂掉。这时仍然可以用本地的文件来安装Pylons及其以来的包。:

easy_install -f http://pylonshq.com/download/ Pylons

这样会自动安装最新版本的包。如果你正在使用一个旧版本,则可以指定版本:

easy_install -f http://pylonshq.com/download/0.8.2/ Pylons

否则,先下载 easy install ,地址为 http://peak.telecommunity.com/dist/ez_setup.py 。然后运行:

$ python ez_setup.py Pylons

Note

你可以选择安装一个其他的扩展(extra),如下:

$ easy_install Pylons[extra]

pudge :支持构建构建文档,查看 为应用添加文档 。需要注意的是很多文档工具还处于开发中,并不是很稳定。

genshi :支持使用 genshi 模板,查看 使用其他模板语言

cheetah :支持使用 cheetah 模板,查看 使用其他模板语言

kid :支持使用 kid 模板,查看 使用其他模板语言

full :如上所有的

3.2   自定义安装位置

如果需要自定义安装位置,则可以参考:

http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations

查看Easy Install的文档可以了解Pylons是否是安装为系统级。

http://peak.telecommunity.com/DevCenter/EasyInstall

3.3   升级安装

升级到最新版本使用:

$ easy_install -U Pylons

3.4   工作于前沿(Living on the Cutting Edge)

如果不满意于最新的发行版,或者希望使用源代码工作,可以使用最新的开发版本:

http://pylonshq.com/docs/0.9.4.1/pylonsdev.html

3.5   Easy Install 的问题

有时候如果Pylons依赖的包安装失败会导致Easy Install出错。这时候确保 setuptools 是最新版本,使用如下命令:

$ easy_install -U setuptools

然后再次尝试安装Pylons,如果再次安装失败,就先手动安装Pylons依赖的软件包,然后再安装Pylons。例如,如果你安装Myghty时,可以指定最新版本的位置:

$ easy_install -U -f http://pylonshq.com/download/ Myghty

或者你也可以直接使用URL上的发行版来安装。这时我们将会从cheeseshop安装Myghty 1.1,但是你必须确保安装当前Pylons版本所使用的文件:

$ easy_install -U http://cheeseshop.python.org/packages/source/M/Myghty/Myghty-1.1.tar.gz#md5=5865361811dca4054f1ec60ac32ee965

3.6   软件包注释

Pylons使用的 Cheetah、docutils、elementtree、nose等等软件包多多少少的被 James Gardner 修改过,所以可以被setuptools和Python2.3方便的安装和使用。这些软件包的某些安装指令需要手动调整。如果你不打算使用Pylons提供的这些软件包版本,Pylons开发组并不确保可以工作。

4   启动Pylons之后,主页上的例子

helloworld/public/ 目录在运行之前搜索需要显示的静态文件。删除文件 helloworld/public/index.html 然后修改路由(Route) helloworld/config/routing.py 成如下的样子:

map.connect('',controller='hello',action='index')

新建一个hello.py文件,内容如下:

# helloworld/controllers/hello.py
from helloworld.lib.base import *
class HelloController(BaseController):
    def index(self):
        return Response('Hello world')

然后访问 http://127.0.0.1:5000/hello 可以看到结果。

使用模板的例子,Myghty模板:

# helloworld/templates/serverinfo.myt
<p>Hi, here's the server environment: <br />
<% str(request.environ) %></p>
<p>here's the URL you called: <% h.url_for() %> </p>
<p>and here's the name you set: <% c.name %></p>

然后将这些添加到你的hello控制器类当中:

def serverinfo(self):
    c.name='The Black Knight'
    return render_response('/serverinfo.myt')

然后通过 http://127.0.0.1:5000/hello/serverinfo 来访问。

5   《Getting Started》比《Pylons初探》增加的内容

尽管《Pylons初探》就是翻译自《Getting Started》,但是版本并不相同。现在版本比原版本增加了一些内容。

http://pylonshq.com/docs/0.9.4.1/getting_started.html

5.1   简介

如果尚未完成安装,阅读 安装过程 。这个文档引导用户快速入门。

5.2   创建一个Pylons工程

Pylons使用Paste创建和部署工程,当然还可以创建控制器及其单元测试。

创建一个新工程叫做 helloworld 使用如下命令:

paster create --template=pylons helloworld

Note

Windows用户必须先配置 PATH 环境变量在 安装后必读 。至少应该可以在控制台中得到 paster 的路径。

这将会创建一个基本的工程目录,目录具有如下结构:

-helloworld
    -data
    -helloworld
    -helloworld.egg-info
        -Various files including paste_deploy_config.ini_tmpl
    -development.ini
    -setup.cfg
    -setup.py

文件 setup.py 用于创建自安装包,叫做 eggegg 可以看作等同于Java中的 .jar 文件。而 setup.cfg 包含了工程的其他信息,目录 helloworld.egg-info 包含关于egg的信息,包括一个 paste_deploy_config.ini_tmpl 文件用作工程使用的配置模板,可以用 paster make-config 命令来通过这个模板创建配置文件。发行和部署工程可以参考 发行工程 ,而最终用户可以参考 安装应用

注意 data 目录,这个目录可以被 development.ini 文件所配置,并用于保存缓存数据和会话。

helloworld 中的 helloworld 目录用于放置应用程序的特定文件。目录结构如下:

-helloworld
    -helloworld
        -config
        -controllers
        -docs
        -i18n
        -lib
        -models
        -public
        -templates
        -tests
        -__init__.py
        -websetup.py

config 目录包含了WEB应用的配置选项。

controllers 目录放置控制器。控制器是程序的核心,决定了装入哪些数据,和如何显示。

docs 目录用于放置程序的文档。你可以使用 setup.py pudge 来将他们转换为HTML。

i18n 目录用来放置多语言信息编目。

lib 目录用来放置各个控制器之间的共享模块,第三方代码,或者其他合适的代码。

models 目录用来放置模型对象,比如ORM使用的类。在 models/__init__.py 中的对象定义将会被装入并作为模型 model.YourObject 。数据库的配置字符串保存在 development.ini 文件。

public 目录用来放置HTML、图像、JavaScript、CSS等等静态文件。有如apache的htdocs目录。

tests 目录用来放置控制器等等的单元测试。控制器的单元测试使用Nose和 paste.fixture 。

templates 目录来保存模板。模板包含混合的静态文本和Python代码,用来生成HTML文档。Pylons使用Myghty模板作为缺省,但是同时支持Cheetah、Kid等等其他多种模板,这些需要通过Buffet来调用。查看 如何使用其他模板

__init__.py 文集那将 helloworld 目录作为一个Python包来发布。

websetup.py 文件包含了用户在运行 paster setup-app 时运行的代码,参考 安装应用 。如果希望在应用执行之前运行一些代码,这里比较好。

5.3   尝试使用模板

我们可以尝试一个模板工程如下:

$ cd helloworld
$ paster serve --reload development.ini

这些命令会使用配置development.ini进行启动并提供Pylons服务。

选项 –reload 会在Python代码或 development.ini 文件发生改变时自动重启服务器。这在开发中是非常有用的。

如果访问 http://127.0.0.1:5000/ 你可以看到欢迎页面( 127.0.0.1 是本机IP),但是可以通过 development.ini 文件来修改。

尝试创建一个新文件 test.html 在目录 helloworld/public 中,内容如下:

<html>
    <body>
        Hello world!
    </body>
</html>

如果访问 http://127.0.0.1:5000/test.html 可以看到 Hello World! 这个信息。任何在 public 目录下的文件都回按照相同的名字对外提供服务,Pylons有个选项可以决定从 public 目录返回,还是从代码返回。这个行为可以通过修改 config/middleware.py 文件中的 Cascade 的顺序来改变。

5.4   交互调试器

交互调试器是开发中的强大工具。他在使用 development.ini 作为配置时是默认启用的。当启用时,他允许通过一个WEB页面寻找错误发生的位置。在产品环境中调试器将会降低安全级别,所以通过 paster make-config 生成的产品环境配置文件需要关闭调试器。

关闭调试器,取消如下的注释,在 development.ini 文件的 [app:main] 节中:

# set debug=false

改为:

set debug=false

然后。将debug设置为false就是为了在产品环境提高安全系数。

更多相关信息参考 交互调试器 文档。

5.5   创建控制器并修改URL路由

你现在可以创建一个自己的WEB应用了。首先给hello world创建一个控制器:

$ paster controller hello

命令 paster 会创建 controllers/hello.py 文件,并同时创建其单元测试文件 helloworld/tests/functional/test_hello.py 用来运行这个控制器的单元测试。

如下是用于在 http://127.0.0.1:5000/hello 打印 ‘Hello world’ 的简单控制器代码。将这些代码放入 helloworld/controllers/hello.py 文件中:

from helloworld.lib.base import *
class HelloController(BaseController):
    def index(self):
        return Response('Hello world')

Pylons使用一个强大的并且灵活的URL路由来控制代码和URL的映射。

我们希望同时在 http://127.0.0.1:5000/hellohttp://127.0.0.1:5000/ 下显示,可以通过如下路由。将如下的行添加到配置文件 helloworld/config/routing.py ,如下:

map.connect('',controller='hello',action='index')
map.connect(':controller/:action/:id')
map.connect('*url',controller='template',action='view')

这样就可以将空URL匹配到 hello 控制器的 index 行为上,否则就按照 controller/action/id 的方式匹配,当然要确保这些可以匹配到。如果确实匹配不到了,就转到 templates 控制器的 view 行为,显示404错误。

改变了URL的路由之后必须重启服务器。但是如果你有开启 --reload 选项则会自动重启服务器,要不就要手动关闭和启动。

Note

Myghty模板的改变不需要重启服务器,也不需要 --reload 就可以起效。

访问 http://127.0.0.1:5000/hellohttp://127.0.0.1:5000/ 可以看到第一个显示 Hello world ,而第二个显示从前的欢迎页面。这是因为在 public 目录下的静态文件要优先于代码被显示。

删除文件 public/index.html 可以得到预期效果。更多信息参考 URL路由手册

5.6   模板和请求周期

当你的控制器的方法被WSGI应用所请求并返回Response对象时,如果希望使用模板返回,可以使用 command 命令,或者 render_response 命令。随之会处理模板并生成响应(Response)对象。

Note

如果希望获得更多关于 renderrender_reponse 的信息,参考 Pylons模板API

下面的例子模板,使用Myghty,打印一些信息。

创建一个模板文件 helloworld/templates/serverinfo.myt ,包含如下内容:

<p>Hi, here's the server environment: <br />
<% str(request.environ) %></p>
<p>
and here's the URL you called: <% h.url_for() %>
</p>

使用这个模板,在 helloworld 的HelloController控制器添加新方法如下:

def serverinfo(self):
    return render_response('/serverinfo.myt')

函数 render_response('/serverinfo.myt') 会使用默认引擎(Myghty)处理模板。

如果服务器仍然在运行,可以查看 http://127.0.0.1:5000/hello/serverinfo

也可以简单的重启服务器,在helloworld目录执行 paster serve --reload development.ini

5.7   使用Sessions

会话的处理来自应用程序的 Beaker middleware ,其包含Myghty的容器API。提供了健壮和强大的Session和缓存能力。

使用Session是很容易的,如下是保存Session的例子:

def serverinfo(self):
    session['name']='George'
    session.save()
    return render_response('/serverinfo.myt')

Session的选项可以通过 development.ini 来定制,并且使用相同的名字,详见 Myghty docs for sessions

Note

记住每次调用 session.save() 在返回相应之前来确保Session的保存。

5.8   控制器变量和模板全局变量

5.8.1   Pylons全局变量

为了方便,有少数几个通过导入 lib.base 就可以使用的全局变量,你可以在控制器中随意使用:

sessioin :存储Session数据,参考 Myghty Session docs

request :请求对象。

Response :响应类,控制器一般来说应该返回这个类的实例。

abort :用于中断请求,并发送 HTTPException ,可以附带状态码。

redirect_to :通过HTTP 302状态码来重定向浏览器到其他地址的函数,通过HTTPException实现。

render :用来使用模板生成字符串的函数。

render_response :用来使用模板生成 Response 对象的函数,相当于 Response(render(...))

h :用于引用Pylons的其他工具函数。缺省时,Pylons会将工具函数装入自 Web Helper 包。阅读文档时应该记住这些函数都可以通过 h 来引用。在Pylons下面通过这个作为命名空间。

c :用来向模板传递变量。

g :应用程序全局变量对象,可持续的。

5.8.2   传递变量到模板

Pylons控制器被每个请求创建一次。这意味着你可以在 self 上面绑定需要使用的变量。当然,这样做不太好跟踪,除非你需要传递到模板。如果希望传递传递数据到模板,可以使用变量 c 。因为Myghty模板默认就是使用 c 作为全局变量的。下面是使用的例子:

def serverinfo(self):
    c.value=2
    return render_response('/serverinfo.myt')

然后修改 templates 目录中的模板 serverinfo.myt 文件成如下:

<p>The value of <tt>c.value</tt> is:
<% c.value %>

Note

c对象在其他模板语言中也是适用的。

你可以看到打印出来的 2 。当访问c的属性不存在时,不会发生错误,而是返回空字符串。这对控制响应行为很有用。例如:

<p>Hi there <% c.name or c.full_name or "Joe Smith" %>

Warning

不要随意设置以 “_” 开头的c的属性。c和其他很多全局变量都是 StackedObjectProxies 类的成员。这可能会与已有的内置方法发生冲突,导致一些难于调试的问题。

c对象在每次请求时都回初始化,所以不需要担心控制器使用了先前请求的旧值。

5.8.3   应用程序全局对象和持续对象

某些场合需要在各个控制器之间共享一些信息而不会在每个请求中重启。例如在应用程序启动时开启一个TCP连接。你可以通过 g 变量。

g 变量是一个 Globals 类的实例在文件 lib/app_globals.py 中。在 __init__() 中设置的属性对 g 来说都是应用级别的全局属性。在任何一个请求中对g的某个属性的修改都会保持下来。在请求中设置全局变量时必须小心。

下例是如何使用 g 变量。首先修改 lib/app_globals.py Globals 类,把 __init__() 方法如下:

def __init__(self,global_conf,app_conf,**extra):
    self.message='Hello'

然后添加一个新方法到 helloworld/controllers/hello.py 如下:

def app_globals_test(self):
    resp=Response()
    if g.message=='Hello':
        resp.write(g.message)
        g.message='Hello World!'
    else:
        resp.write(g.message)
    return resp

这时如果运行服务器在 http://127.0.0.1:5000/hello/app_globals_test ,你可以看到信息 Hello 。如果再次访问,将会改变到 Hello World! ,然后就保持这样的改变了,因为在首次请求时,变量就已经改变了。

__init__() 方法需要参数 global_confapp_conf ,这些配置保存在文件 development.ini 中。这意味着可以在这里就设置全局变量。注意在第一个请求没有建立之前不可以设置变量c和h。

可以给全局变量添加 __del__() 方法,确保在程序退出时执行。

6   《Windows用户安装后必读》笔记

安装后必读

7   调试中发现的问题

7.1   URL映射的定义

必须在一开始就进行URL映射的定义,否则无法从URL上访问到自己的模块。在文件 config/routing.py 中定义。定义格式如下:

map.connect('urlpath',controller='controller_name',action='index')

其中的action是干什么是不知道的,重要的只是指定URL和控制器。而且要注意,这个定义必须写在 make_map() 函数中,并且必须在如下的两个语句之前定义,因为这两个语句会尽可能匹配多的URL,放在这后面不会起作用:

map.connect(':controller/:action/:id')
map.connect('*url',controller='template',action='view')

当然,这种使用URL映射的方式,可以很好自定义URL的样式。

另外,只要手动重启服务器,不去 routing.py 定义URL映射,也是可以直接使用模块名来访问的。当然,这个所谓模块名是不包含 .py 的。

7.2   参数传递,方法参数传递

Pylons用于暴露的方法是允许接受参数的,当然,如果硬是不传递,也没有设置默认值的时候会由Pylons好心的传递一个None过来。这里有个例子:

class HappyController(...):
    def test(self,id):
        return Response('test'+id)

当然,顶层类是使用 paster controller happy 自动生成的,所以在URL中也是使用 happy 这个词的。而 test 则是其暴露出来供访问的方法。这时有几个URL可供调用,结果分别为:

URL 解释
/happy/test 返回异常,报告id为None不可以连接字符串
/happy/test/ 返回异常,报告id为None不可以连接字符串
/happy/test/50 id得到参数50,返回 test50

当然这里注意,这个暴露方法参数只是通过URL的分级方式提供的,而问号之后的查询参数是不会传递到这里的。

还要注意routing.py中的一句:

map.connect(':controller/:action/:id')

这句的意思是允许以 控制器名/方法名/id 的方法来调用,作为一种默认的调用方法。而注意这个 :id ,就是说,方法的参数名只能是 id ,如果使用其他的则会发生错误。

7.3   共享模块代码

工程目录中的lib目录可以用于放置一些共享模块。调用的方法么,举个例子,比如有个模块的文件名是helloworld/lib/testunit.py,那么导入语句就可以写作:

import helloworld.lib.testunit

这样,可以在lib目录中放置数据库访问模块等等,多种东东。

Python的logging模块

Tuesday, September 11th, 2007

Python的logging模块

翻译: gashero <harry.python@gmail.com>

目录

1   简介-Python文档

从Python2.3版本中开始引入的logging模块为应用提供了灵活的日志系统。

logging的行为依靠调用 Logger 类的方法来实现,实例一般叫做logger。每个实例都拥有自己的名字,并且可以通过点来分割具备层次的名字。例如,一个logger叫做”scan”是一个叫做”scan.text”的logger的顶层,当然也包括”scan.html”和”scan.pdf”。logger的名字指示了他属于应用程序的哪个位置。

日志信息也拥有级别指定其重要程度。缺省提供的级别包括DEBUG,INFO,WARNING,ERROR,CRITICAL(严重)。为了方便,你可以调用特定的方法来指定日志的重要性,对应的方法为 debug()info()warning()error()critical() 。你也不必拘泥于这些级别,你可以使用更为通用的方法 log() 并且手动指定其级别。

日志级别对应值如下表所示。了解这些有助于你定义自己的日志级别的相对关系。如果你定义的级别与已有的数值相同,则原有的级别会被覆盖。

级别 数值
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0

日志级别也可以在指定logger时定义,可以在开发时装入和存储配置。当调用logger的日志方法时,logger对比日志级别和自己的被指定的级别。如果本身的级别高于调用方法的级别,则不会记录这个日志信息。这是一个方便的方法用于忽略过多细节的日志。

日志信息会被编码为 LogRecord 类,当logger决定记录一个事件时,就会为日志信息创建一个LogRecord实例。

日志信息会被发布(dispatch)机制通过handler来发布出去,这些handler继承自 Handler 类。Handler负责把日志信息(LogRecord的实例)发布到对应的位置供处理这些信息。Handler传递LogRecord实例并指定特定目标。每个logger都可以拥有0个或多个handler,通过 addHandler() 方法添加。除了handler与logger的组合之外,所有的handler还会被所组合的祖先logger所调用来发布信息。

有如logger,handler也可以有自己的级别过滤器,用于过滤日志级别。如果一个handler决定发布一个事件,可以调用 emit() 来发送信息到目的。大多数用户继承的Handler的子类需要重载这个emit()方法。

除了基本的Handler类,比较有用的子类如:

  1. StreamHandler实例发送错误到流(类似文件的对象)。
  2. FileHandler实例发送错误到磁盘文件。
  3. BaseRotatingHandler是所有轮徇日志的基类,不能直接使用。但是可以使用RotatingFileHandler和TimeRotatingFileHandler。
  4. RotatingFileHandler实例发送信息到磁盘文件,并且限制最大的日志文件大小,并适时轮徇。
  5. TimeRotatingFileHandler实例发送错误信息到磁盘,并在适当的事件间隔进行轮徇。
  6. SocketHandler实例发送日志到TCP/IP socket。
  7. DatagramHandler实例发送错误信息通过UDP协议。
  8. SMTPHandler实例发送错误信息到特定的email地址。
  9. SysLogHandler实例发送日志到UNIX syslog服务,并支持远程syslog服务。
  10. NTEventLogHandler实例发送日志到WindowsNT/2000/XP事件日志。
  11. MemoryHandler实例发送日志到内存中的缓冲区,并在达到特定条件时清空。
  12. HTTPHandler实例发送错误信息到HTTP服务器,通过GET或POST方法。

StreamHandler和FileHandler类都是在核心logging模块中定义的。其他handler定义在各个子模块中,叫做logging.handlers。当然还有一个logging.config模块提供了配置功能。

日志信息在输出之前会经过 Formatter 类的格式化。他们在最开始使用%操作符来设置。

批量格式化信息,需要 BufferingFormatter 类。除了格式化字符串之外,它还会在输出信息之前加上其他信息。

当基于logger和handler的级别过滤器仍然不够时,可以使用 Filter 类的实例来添加到logger和handler实例中,通过他们的 addFilter() 方法。当决定输出日志之前,logger和handler会询问过滤器,如果过滤器返回False,则不会显示这条日志。

最简单的过滤器功能用于指定日志的名字。如果使用了这个过滤器,则发送到命名logger和其子logger的日志将会通过,其他的会被丢弃。

除了上面所描述的,还有很多模块级别的函数。如下:

getLogger([name])

返回一个logger,可以指定名字,如果没有指定名字则返回根logger。指定的名字典型的为以点分隔的分层次的名字。选择一个恰当的名字,让别人知道,谁在输出日志。所有使用相同名字调用这个函数都会返回相同的logger实例。这意味着logger实例不需要在应用中到处传递。

getLoggerClass()

返回一个标准的Logger类,或者上次传递到 setLoggerClass() 的类。这个函数用于定义一个新的日志类,但是之前的代码不会受到影响。例如:

class MyLogger(logging.getLoggerClass()):
    #重载一些行为

debug(msg[,*args[,**kwargs]])

记录一个DEBUG级别的日志信息到根logger。 msg 参数就是用于输出的日志, args 参数是用于填入msg字符串的参数,当然kwargs也是差不多的角色。这说明msg可以是一个包含%d、%s等等的待格式化字符串。

在kwargs中有2个参数是必须的: exc_info 如果不为False,则异常产生的信息也会被记录;如果提供了一个异常tuple(以 sys.exc_info() 格式),则会使用它;否则会调用 sys.exc_info() 来获取异常信息。

另外一个参数为 extra 用于传递一个字典表示 LogRecord 中的 __dict__ 信息,可以加入用户自定义属性。这些传递的参数可以随你喜欢的。例如可能需要传递的:

FORMAT="%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
logging.basicConfig(format=FORMAT)
dict={'clientip':'192.168.1.1','user':'fbloggs'}
logging.warning("Protocol problem: %s","connection reset",extra=d)

将会有如下的显示:

2006-02-08 22:20:02,165 192.168.1.1 fbloggs Protocol problem: connection reset

extra字典中的键不会与已有的键相冲突,具体可以参考Formatter的文档中关于使用字典的部分。

在选择字典中的键名时,必须小心一些情况。上面的例子中,已经在待格式化字符串中有’clientip’和’user’了,这时如果没有传递这两个键,则不会输出日志,因为出现了异常了。这种情况时,你必须要传递这2个键。

出于这种复杂性,这种功能往往用在很特殊的地方,比如多线程服务器,或关心多种信息的上下文环境,例如远程IP和登录用户。在这些情况中,需要先指定Formatter实例。 extra 参数从2.5版本开始加入。

info(msg[,*args[,**kwargs]])

记录INFO级别的日志信息,其他参数同debug()。

warning(msg[,*args[,**kwargs]])

记录WARNING级别的日志信息,其他参数同debug()。

error(msg[,*args[,**kwargs]])

记录ERROR级别的日志信息,其他参数同debug()。

critical(msg[,*args[,**kwargs]])

记录CRITICAL级别的日志信息,其他参数同debug()。

exception(msg[,*args])

记录ERROR级别的日志信息,其他参数同debug()。一般用在异常处理中。

log(level,msg[,*args[,**kwargs]])

记录level级别的日志信息,其他参数同debug()。

disable(lvl)

提供一个在logger中禁用某个级别日志的方法,用于应用临时切换可显示的日志。

addLevelName(lvl,levelName)

给级别lvl指定一个名字levelName到内部字典。以后用于映射数字的级别到特定的名字,供给Formatter用来格式化字符串。也可以用于定义自己的级别。这里也是唯一可以注册级别用的地方,级别必须是数字,并且在按照一定的排序要求。

getLevelName(lvl)

返回lvl级别的文字说明。如果级别是CRITICAL、ERROR、WARNING、INFO、DEBUG中的某一个,也会返回对应的名字。如果你自己通过addLevelName()自定义过级别,那么也会返回对应的名字。如果对应级别不存在,则返回 "Level %s"%lvl 这个字符串。

makeLogRecord(attrdict)

创建并返回一个LogRecord实例,并使用attrdict赋值过。这个函数用于把一个LogRecord给pickle过后通过socket发送,并方便接收方重组这个信息。

basicConfig([**kwargs])

对日志系统进行基本配置,使用缺省的StreamHandler和Formatter并添加根logger。一些函数如debug()、info()、warning()、error()、critical()会自动使用basicConfig()配置好的根logger进行日志输出。在2.4版之前,basicConfig()不接受字典参数。

如下是支持的字典参数:

格式 描述
filename 指定FileHandler的文件名,而不是StreamHandler
filemode 打开文件的模式,同open函数中的同名参数,默认为’a’
format 输出格式字符串
datefmt 日期格式
level 设置根logger的日志级别
stream 指定StreamHandler。这个参数与filename冲突,忽略stream

shutdown()

告知日志系统准备关闭日志并将所有信息写入磁盘。

setLoggerClass(klass)

告知日志系统使用类klass作为示例的Logger类。这个类应该定义 __init__() 方法并接受一个参数表示名字,而且 __init__() 方法应该在内部调用 Logger.__init__() 方法。这个函数一般在应用自定义Logger的行为时使用。

PEP 282, A Logging System

Original Python logging package

2   各种Handler的子类

2.1   TimedRotatingFileHandler

TimedRotatingFileHandler 类是在logging.handler包中,支持对写入到磁盘的日志按照时间间隔来轮询。

class TimedRotatingFileHandler(filename[,when[,interval[,backupCount]]])

返回一个新的TimedRotatingFileHandler类实例,在指定文件名时会自动使用词缀。轮询发生的时间取决于参数 when 和 interval 。

你可以使用 when 来指定 interval 的类型。可选值如下,注意区分大小写:

interval的类型
S
M 分钟
H 小时
D
W
midnight 在午夜

如果 backupCount 为非零,则系统会在旧日志文件名的末尾添加词缀。词缀格式为日期和时间,使用 strftime 格式如 %Y-%m-%d %H:%M:%S 或者依赖于之前的规则。最多会保留 backupCount 个日志文件,如果继续增加,会持续删除最旧的的日志。

doRollover()

进行一次回转,有如上面描述的。

emit(record)

把日志输出到文件,按照如上的回转规则。

DBUtils超快速入门指南

Tuesday, September 11th, 2007

DBUtils超快速入门指南

版本: 0.9.2

目录

1   简介

DBUtils是一套Python数据库连接池包,并允许对非线程安全的数据库接口进行线程安全包装。DBUtils来自Webware for Python。

DBUtils提供两种外部接口:

  • PersistentDB :提供线程专用的数据库连接,并自动管理连接。
  • PooledDB :提供线程间可共享的数据库连接,并自动管理连接。

实测证明 PersistentDB 的速度是最高的,但是在某些特殊情况下,数据库的连接过程可能异常缓慢,而此时的PooledDB则可以提供相对来说平均连接时间比较短的管理方式。

另外,实际使用的数据库驱动也有所依赖,比如SQLite数据库只能使用PersistentDB作连接池。

下载地址:

http://www.webwareforpython.org/downloads/DBUtils/

2   使用方法

连接池对象只初始化一次,一般可以作为模块级代码来确保。

PersistentDB的连接例子:

import DBUtils.PersistentDB
persist=DBUtils.PersistentDB.PersistentDB(dbpai=MySQLdb,maxusage=1000,**kwargs)

这里的参数dbpai指使用的底层数据库模块,兼容DB-API的。maxusage则为一个连接最大使用次数,参考了官方例子。后面的**kwargs则为实际传递给MySQLdb的参数。

获取连接:

conn=persist.connection()

实际编程中用过的连接直接关闭 conn.close() 即可将连接交还给连接池。

PooledDB使用方法同PersistentDB,只是参数有所不同。

  • dbapi :数据库接口
  • mincached :启动时开启的空连接数量
  • maxcached :连接池最大可用连接数量
  • maxshared :连接池最大可共享连接数量
  • maxconnections :最大允许连接数量
  • blocking :达到最大数量时是否阻塞
  • maxusage :单个连接最大复用次数
  • setsession :用于传递到数据库的准备会话,如 ["set name UTF-8"]

一个使用过程:

db=pooled.connection()
cur=db.cursor()
cur.execute(...)
res=cur.fetchone()
cur.close() # or del cur
db.close() # or del db

DBUtils 用户指南(更新至0.9.3)

Tuesday, September 11th, 2007

DBUtils 用户指南

版本: 0.9.3

目录

摘要

DBUtils 是一套允许线程化 Python 程序可以安全和有效的访问数据库的模块。DBUtils已经作为 Webware for Python 一部分用来结合 PyGreSQL 访问 PostgreSQL 数据库,当然他也可以用在其他Python应用程序中来访问 DB-API 2 兼容的数据库接口。

模块

DBUtils实际上是一个包含两个子模块的Python包,一个用于连接DB-API 2模块,另一个用于连接典型的PyGreSQL模块。

全局的DB-API 2变量
SteadyDB.py 用于稳定数据库连接
PooledDB.py 连接池
PersistentDB.py 维持持续的数据库连接
SimplePooledDB.py 简单连接池
典型的 PyGreSQL 变量
SteadyPg.py 稳定PyGreSQL连接
PooledPg.py PyGreSQL连接池
PersistentPg.py 维持持续的PyGreSQL连接
SimplePooledPg.py 简单的PyGreSQL连接池

对标准DB-API 2模块的依赖如下图所示:

dbdep.gif对典型的PyGreSQL模块依赖如下图所示:

pgdep.gif

下载

你可以从 Webware 的网站下载最新版本:

http://www.webwareforpython.org/downloads/DBUtils/

也可以从Python Package Index来下载:

http://www.python.org/pypi/DBUtils/

安装

安装为顶层模块

如果你打算在除了Webware之外的程序中使用,推荐安装为顶层模块:

python setup.py install

安装为Webware的子模块(插件)

如果你只是打算在Webware中使用,则可以按照如下安装:

python setup.py install --install-lib=/path/to/Webware

替换 /path/to/Webware 为Webware安装的根路径。你还需要运行Webware的安装程序来同时包含DBUtils的文档:

cd path/to/Webware
python install.py

功能

这一节的主要例子面向DB-API 2,但是也适用于典型的PyGreSQL模块。

SimplePooledDB

DBUtils.SimplePooledDB 是一个非常简单的数据库连接池实现。他比完善的 PooledDB 模块缺少很多功能。 DBUtils.SimplePooledDB 本质上类似于 MiscUtils.DBPool 这个Webware的组成部分。你可以把它看作一种演示程序。

SteadyDB

DBUtils.SteadyDB 是一个模块实现了”强硬”的数据库连接,基于DB-API 2建立的原始连接。一个”强硬”的连接意味着在连接关闭之后,或者使用次数操作限制时会重新连接。

一个典型的例子是数据库重启时,而你的程序仍然在运行并需要访问数据库,或者当你的程序连接了一个防火墙后面的远程数据库,而防火墙重启时丢失了状态时。

一般来说你不需要直接使用 SteadyDB 它只是给接下来的两个模块提供基本服务, PersistentDBPooledDB

PersistentDB

DBUtils.PersistentDB 实现了强硬的、线程安全的、顽固的数据库连接,使用DB-API 2模块。如下图展示了使用 PersistentDB 时的连接层步骤:

persist.gif当一个线程首次打开一个数据库连接时,一个连接会打开并仅供这个线程使用。当线程关闭连接时,连接仍然持续打开供这个线程下次请求时使用这个已经打开的连接。连接在线程死亡时自动关闭。

简单的来说 PersistentDB 尝试重用数据库连接来提高线程化程序的数据库访问性能,并且他确保连接不会被线程之间共享。

因此, PersistentDB 可以在底层DB-API模块并非线程安全的时候同样工作的很好,并且他会在其他线程改变数据库会话或者使用多语句事务时同样避免问题的发生。

PooledDB

DBUtils.PooledDB 实现了一个强硬的、线程安全的、有缓存的、可复用的数据库连接,使用任何DB-API 2模块。如下图展示了使用 PooledDB 时的工作流程:

pool.gif如图所示 PooledDB 可以在不同线程之间共享打开的数据库连接。这在你连接并指定 maxshared 参数,并且底层的DB-API 2接口是线程安全才可以,但是你仍然可以使用专用数据库连接而不在线程之间共享连接。除了共享连接以外,还可以设立一个至少 mincached 的连接池,并且最多允许使用 maxcached 个连接,这可以同时用于专用和共享连接池。当一个线程关闭了一个非共享连接,则会返还到空闲连接池中等待下次使用。

如果底层DB-API模块是非线程安全的,线程锁会确保使用 PooledDB 是线程安全的。所以你并不需要为此担心,但是你在使用专用连接来改变数据库会话或执行多命令事务时必须小心。

该选择哪一个?

PersistentDBPooledDB 都是为了重用数据库连接来提高性能,并保持数据库的稳定性。

所以选择何种模块,可以参考上面的解释。 PersistentDB 将会保持一定数量的连接供频繁使用。在这种情况下你总是保持固定数量的连接。如果你的程序频繁的启动和关闭线程,最好使用 PooledDB 。后面将会提到更好的调整,尤其在使用线程安全的DB-API 2模块时。

当然,这两个模块的接口是很相似的,你可以方便的在他们之间转换,并查看哪个更好一些。

使用方法

所有模块的使用方法都很相似,但是在初始化 “Pooled” 和 “Persistent” 时还有有些不同,尤其是DB-API和PyGreSQL之间。

这里只讲解 PersistentDB 和更复杂的 PooledDB 模块。其他模块的细节请参与其文档。使用Python解释器控制台,你可以显示 PooledDB 的文档,如下:

help(PooledDB)

PersistentDB

为了使用 PersistentDB 你首先需要通过创建 PersistentDB 的实例来设置一个特定数据库连接的生成器,床底如下参数:

  • dbapi: 需要使用的DB-API 2兼容的数据库模块
  • maxusage: 一个连接最大允许复用次数(缺省为 0False 意味着无限制的重用),当达到限制时,将会重新连接数据库
  • setsession: 一个可选的SQL命令列表可以用于准备会话,如 ["set datestyle to german", ...]
  • 其他的,你还可以传递用于传递给真实的DB-API 2模块的参数,例如主机名、数据库、用户名、密码等。

举个例子,如果你正在使用 pgdb 作为数据库模块并想要连接本机数据库 mydb ,允许重用1000次:

import pgdb # import used DB-API 2 module
from PersistentDB import PersistentDB
persist = PersistentDB(pgdb, 1000, database='mydb')

按照如上设置完成了连接生成器之后,你可以按照如下来请求一个连接:

db = persist.connection()

你可以使用这些连接就像使用原始的DB-API 2连接一样。实际上你得到的是一个通过SteadyDB得到的强硬的连接,基于DB-API 2。

关闭一个强硬的连接使用 db.close() ,这在内部实际上被忽略掉了,并且供下次使用。在线程关闭时,也会自动关闭数据库连接。你可以改变这个行为通过 persist._closeableTrue

PooledDB

为了使用 PooledDB 模块,你首先需要通过创建 PooledDB 来设置数据库连接池,传递如下参数:

  • dbapi: 需要使用的DB-API 2模块
  • mincached : 启动时开启的空连接数量(缺省值 0 意味着开始时不创建连接)
  • maxcached: 连接池使用的最多连接数量(缺省值 0 代表不限制连接池大小)
  • maxshared: 最大允许的共享连接数量(缺省值 0 代表所有连接都是专用的)如果达到了最大数量,被请求为共享的连接将会被共享使用。
  • maxconnections: 最大允许连接数量(缺省值 0 代表不限制)
  • blocking: 设置在达到最大数量时的行为(缺省值 0False 代表返回一个错误;其他代表阻塞直到连接数减少)
  • maxusage: 单个连接的最大允许复用次数(缺省值 0False 代表不限制的复用)。当达到最大数值时,连接会自动重新连接(关闭和重新打开)
  • setsession: 一个可选的SQL命令列表用于准备每个会话,如 ["set datestyle to german", ...]
  • 其他,你可以设置用于传递到真正的DB-API 2的参数,例如主机名、数据库、用户名、密码等。

举个例子,如果你正在使用 pgdb 作为DB-API模块,并希望连接池中至少有5个连接到数据库 mydb

import pgdb # import used DB-API 2 module
from PooledDB import PooledDB
pool = PooledPg(pgdb, 5, database='mydb')

一旦设置好了连接池,你就可以按照如下请求一个连接:

db = pool.connection()

你可以使用这些连接有如原始的DB-API 2一样。而实际使用的是SteadyDB版本的强硬连接。

请注意连接可以与其他线程共享,只要你设置 maxshared 参数为非零,并且DB-API 2模块也允许。如果你想要使用专用连接则使用:

db = pool.connection(0)

如果你不再需要这个连接了,则可以返回给连接池使用 db.close() 。你也可以使用相同的方法获取另一个连接。

警告: 在一个多线程环境,不要使用下面的方法:

pool.connection().cursor().execute(...)

这将会导致过早的释放连接以供复用,而且如果是非线程安全还会出错。确保连接对象在你的使用过程中是一直存在的,例如:

db = pool.connection()
cur = db.cursor()
cur.execute(...)
res = cur.fetchone()
cur.close() # or del cur
db.close() # or del db

在Webware中使用

如果你正在 Webware for Python 的 servlets 中使用DBUtils来存取数据库,你要确保数据库连接生成器只被应用启动一次,而不是每个servlet启动时都创建一个。为了达到这个目的,你可以在模块或类的初始化代码中添加这些代码,或者使用 __init__.py 中的 contextInitialize() 函数。

目录 Examples 是DBUtils发行包的一部分,包含了一个使用示例数据库的Webware的例子,用来跟踪演讲会的出席者(这个例子的主意来自Andrew Kuchling的 “The Python DB-API“)。

例子的正文可以通过创建配置文件 Configs/Database.config 来配置,改变例子 Examples/DBUtilsExample.py 的缺省参数。这种方式可以设置一个专用数据库的用户名和密码,你也可以选择底层的数据库模块。如果设置了 maxcached ,则例子会使用 “Pooled” 模块,否则会使用 “Persistent” 模块。

注意

如果你正在使用流行的ORM SQLObject ,你并不需要使用DBUtiils,因为他已经内含连接池了。 SQLObject 2 (SQL-API) 事实上还从DBUtils这里借用了连接池分层的代码。

未来功能

一些未来会使用的方法:

  • 一个连接最大被使用的次数,或一个连接最大活动时间。
  • 创建模块 MonitorDBMonitorPg 运行在单独的线程中,监控连接池中各个共享连接的状态。如果检测到一个损坏的连接,则会自动恢复这个连接。这在很多网站中是很实用的,因为晚上往往要重启数据库服务器。如果不使用监控线程,则用户要等到第二天早上才可以使用。正是因为如此,检测损坏的连接并自动恢复是很有用的。使用了监控线程之后,间断时间在晚上,而且很短。监控线程同样可以配置连接生成器的线程池,并且确保用户到达之前完成。
  • 可选的日志,记录损坏的连接和最大限制。

错误报告与回馈

请将错误报告、补丁、回馈直接发送给作者(使用下面给出的邮件地址)。

如果有Webware相关的问题,可以到邮件列表讨论 Webware for Python mailing list

链接

一些相关软件的链接:

作者列表

作者: Christoph Zwerschke <cito@online.de>

版权与许可

Copyright @ 2005-2006 by Christoph Zwerschke. All Rights Reserved.

DBUtils是一个自由开源软件,使用 Open Software License version 2.1 许可。

pysqlite使用指南

Tuesday, September 11th, 2007

pysqlite使用指南

最后更新: pysqlite 2.3.0

目录

1 简介

本使用指南并非Python、SQL、SQLite的入门指南;而是pysqlite功能的介绍,并且包含了使用模式的示例代码。这个指南将会指导你使用Python的数据库接口和SQLite的文档。

2 Python数据库接口2.0兼容

2.1 不兼容的选项

pysqlite包含不兼容的DB API 2.0的功能,如下:

  • 在cursor.description中并不包含类型信息

    cursor.description是一个元组包含如下字段(name,type_code,display_size,internal_size,precision,scale,null_ok)来定义每个列。特定的数据库接口需要至少name和type_code,但是有时cursor.description是内置的,pysqlite不只能检测到任何类型。所以,pysqlite只在cursor.description中填入name字段。其他的字段全部设置为None。

  • 没有类型对象

    同样的,模块级并没有STRING、BINARY、NUMBER、DATETIME、ROWID,并且也没什么用。

2.2 不支持的可选功能

Cursor
不支持nextset方法。这个方法没有实现是因为数据库引擎也没有实现单个游标返回多个结果集。

2.3 有名无实支持的可选功能

Cursor

  • arraysize 属性

    作为最基本的需求,这个属性的值用于支持 fetchmany 方法。不过改变这个值也没什么关系,因为数据库引擎根本就只支持一次获取一行。

  • setinputsizes 方法

    尽管提供了这个方法,但是什么都不做。

  • setoutputsize 方法

    什么活都不干的方法。

2.4 扩展与警告

pysqlite提供了大量的功能来实现对Python DB API的基本支持。大部分扩展在已经在本节的Native Database Engine Features and Extensions Beyond the Python DB API中有所介绍。

  • connect 函数

    参数 database 指定SQLite数据库的文件。一般指定文件系统的绝对或相对路径。

    这个链接函数支持如下可选参数:

    • timeout 当多个连接同时存取数据库时,并且其中一个进程修改了数据库,SQLite数据库会锁定(locked)直到事务被提交。这个超时参数指定连接会等待这个锁定多长时间,并抛出异常。缺省的超时参数是5.0秒。例如:
      sqlite.connect(database="mydb",timeout=10.0)
    • isolation_level pysqlite将会缺省的以”BEGIN”语句开始一个事务,当使用DML语句如INSERT/UPDATE/DELETE/REPLACE。一些用户并不想pysqlite暗自打开事务,而希望使用自动提交模式。其他用户想要pysqlite打开不同类型的事务,例如”BEGIN IMMEDIATE”。查看 控制事务 了解更多细节。注意你通过设置isolation_level属性可以选择不同的isolation级别。例如:
      # 打开自动提交模式
      con=sqlite.connect("mydb",isolation_level=None)
      # 将isolation_level设置到"IMMEDIATE"
      con.isolation_level="IMMEDIATE"
    • detect_types SQLite本来支持的类型包括TEXT、INTEGER、FLOAT、BLOB、NULL。如果你想使用其他类型,你需要自己添加支持。 detect_types 参数和使用自定义的 converters 来使用 register_converter 函数允许你做到这些。 detect_types 缺省是0,就是关闭,你可以设置 PARSE_DECLTYPES 和 PARSE_COLNAMES 的组合来改变设置的类型。参见 SQLite与Python类型 来了解更多。
      • sqlite.PARSE_DECLTYPES 这会

Warning

pause

3 简要入门

这个教会你如何初步的使用pysqlite。而并非是一个Python Database API入门,也不是覆盖其他使用的方面。

3.1 连接到数据库

例子1

连接到数据库文件 mydb

from pysqlite2 import dbapi2 as sqlite
con=sqlite.connect("mydb")

例子2

创建一个内存数据库:

from pysqlite2 import dbapi2 as sqlite
con=sqlite.connect(":memory:")

3.2 执行SQL语句

为了执行这一节,我们需要一个数据库按照如下定义:

CREATE TABLE people
(
    name_last   varchar(20),
    age         integer
);
INSERT INTO people (name_last,age) VALUES ('Yeltsin',72);
INSERT INTO people (name_last,age) VALUES ('Putin',51);

例子1

这个例子显示了一个打印 people 表格内容的最简单的例子:

from pysqlite2 import dbapi2 as sqlite
# 创建数据库连接到文件"mydb"
con=sqlite.connect("mydb")
# 获取游标对象
cur=con.cursor()
# 执行SELECT语句
cur.execute("SELECT * FROM people ORDER BY age")
# 获取所有行并显示
print cur.fetchall()

输出:

[(u'Putin', 51), (u'Yeltsin', 72)]

例子2

如下是另一个小例子展示了如何单行显示记录:

from pysqlite2 import dbapi2 as sqlite
con=sqlite.connect("mydb")
cur=con.cursor()
SELECT="SELECT name_last,age FROM people ORDER BY age, name_last"
# 1. 第一种显示记录的方法
cur.execute(SELECT)
for (name_last,age) in cur:
    print '%s is %d years old.'%(name_last,age)
# 2. 第二种显示记录的方法
cur.execute(SELECT)
for row in cur:
    print '%s is %d years old.'%(row[0], row[1])

输出:

Putin is 51 years old.
Yeltsin is 72 years old.
Putin is 51 years old.
Yeltsin is 72 years old.

例子3

如下的程序以表格的方式打印表格内容:

from pysqlite2 import dbapi2 as sqlite
FIELD_MAX_WIDTH=20
TABLE_NAME='people'
SELECT="SELECT * FROM %s ORDER BY age,name_last"%TABLE_NAME
con=sqlite.connect("mydb")
cur=con.cursor()
cur.execute(SELECT)
#打印表头
for fieldDesc in cur.description:
    print fieldDesc[0].ljust(FIELD_MAX_WIDTH),
print #结束表头行
print '-'*78

#每行打印一次值
fieldIndices=range(len(cur.description))
for row in cur:
    for fieldIndex in fieldIndices:
        fieldValue=str(row[fieldIndex])
        print fieldValue.ljust(FIELD_MAX_WIDTH),
    print

输出:

name_last               age
---------------------------------------------
Putin                   51
Yeltsin                 72

例子4

插入人员信息到 people 表格:

from pysqlite2 import dbapi2 as sqlite
con=sqlite.connect("mydb")
cur=con.cursor()
newPeople=(
    ('Lebed',53),
    ('Zhirinovsky',57),
)
for person in newPeople:
    cur.execute("INSERT INTO people (name_last,age) VALUES (?,?)",person)
#修改之后必须明确的提交
con.commit()

注意参数化的SQL语句。当处理重复语句时,这会更快并产生更少的错误,相对于手动生成SQL语句。

而上面的核心语句:

for person in newPeople:
    cur.execute("INSERT INTO people (name_last,age) VALUES (?,?)",person)

可以被重写为:

cur.executemany("INSERT INTO people (name_last,age) VALUES (?,?)",newPeople)

在例子4的后面的打印结果为:

name_last                 age
-------------------------------------------
Putin                     51
Lebed                     53
Zhirinovsky               57
Yeltsin                   72

4 数据库引擎的本地功能和Python DB API的扩展功能

4.1 创建用户自定义函数

SQLite支持用户自定义函数。使用pysqlite,你使用连接的 create_function 方法来创建新函数:

def create_function(self,name,numparams,func)

如下是参数说明:

  • name

    SQL函数的名字

  • numparams

    函数接收的参数数量,-1是接收不限制数量的参数

  • func

    Python函数

函数可以返回任何pysqlite支持的SQLite类型:unicode、str、int、long、float、buffer和None。任何用户自定义函数中的异常都会导致SQL语句的执行中断。

例子:

from pysqlite2 import dbapi2 as sqlite
import md5
def md5sum(t):
    return md5.md5(t).hexdigest()
con=sqlite.connect(":memory:")
con.create_function("md5",1,md5sum)
cur=con.cursor()
cur.execute("SELECT md5(?)", ("foo",))
print cur.fetchone()[0]

4.2 创建用户自定义聚合体类型

SQLite支持用户自定义聚合类型函数。使用

Warning

pause

4.3 创建和使用对比函数

Warning

pause

4.4 检查语句完整性

Warning

pause

4.5 启用SQLite的共享缓存

Warning

pause

4.6 设置认证回调函数

Warning

pause

5 SQLite与Python类型

5.1 介绍

详见 http://sqlite.org/datatype3.html

Warning

pause

5.2 使用Python类型的SQLite数据库存储适配器

Warning

pause

5.3 转换SQLite值到Python类型

Warning

pause

5.4 缺省的pysqlite适配器和转换器

Warning

pause

6 控制事务

缺省时,pysqlite在DML语句(INSERT/UPDATE/DELETE/REPLACE)语句之前自动开启一个事务,并且在一个非DML语句或非DQL语句之前自动提交(除了SELECT/INSERT/UPDATE/DELETE/REPLACE)语句之外。

所以如果你在一个事务当中,要执行类似 CREATE TABLE … , VACUUM , PRAGMA 之类的命令,则pysqlite会在执行这些命令之前提交。有两个原因需要这么做。首先,大多数此类命令并不是工作在事务当中的。第二个原因是pysqlite需要保持对事务状态的跟踪,无论事务处于活跃状态与否。

你可以自己控制何种类型的”BEGIN”语句会自动执行(没有,或者所有),通过设置 connect 的 isolation_level 参数,或者连接对象的 isolation_level 属性。

如果你想要开启 autocommit 模式,设置 isolation_level 为None。

否则让这个值为缺省,将会使用平坦的”BEGIN”语句。或者设置一个SQLite支持的隔离(isolation)级别:DEFERRED(延时)、IMMEDIATE(立即)或EXCLUSIVE(独占)。

因为pysqlite需要对事务状态进行跟踪,所以你将不能使用 OR ROLLBACK 或 ON CONFLICT ROLLBACK 。作为交换,捕捉 IntegrityError 异常并手动调用连接的 rollback 方法。

7 高效的使用pysqlite

7.1 使用命令的捷径

使用非标准的连接的 execute() 、 executemany() 、 executescript() 方法,你的代码可以更加简明,因为你不需要再创建多余的游标对象了。作为交换,游标对象会隐含的创建并使用。这种方法,你可以直接在对象之上使用SELECT语句并使用序列方法。:

from pysqlite2 import dbapi2 as sqlite
persons=[
    ("Hugo","Boss"),
    ("Calvin","Klein")
    ]
con=sqlite.connect(":memory:")
#创建表格
con.execute("CREATE TABLE person (firstname,lastname)")
#填写表格
con.executemany("INSERT INTO person(firstname,lastname) VALUES (?,?)",
    persons)
#打印表格内容
for row in con.execute("SELECT firstname,lastname FROM person"):
    print row
#使用一个哑WHERE子句来让SQLite删除表格
print "I just deleted",con.execute("DELETE FROM person WHERE 1=1").rowcount,"rows"

7.2 使用列名而不是序号存取字段

一个pysqlite2.1.0的新功能是新的内建的sqlite.Row类设计作为记录工厂。 Rows包装了这个类并允许同时使用列序号(类似元组)和大小写不敏感的列名:

from pysqlite2 import dbapi2 as sqlite
con=sqlite.connect("mydb")
con.row_factory=sqlite.Row
cur=con.cursor()
cur.execute("SELECT name_last,age FROM people")
for row in cur:
    assert row[0] == row["name_last"]
    assert row["name_last"] == row["nAmE_lAsT"]
    assert row[1] == row["age"]
    assert row[1] == row["Age"]