Pylons 入门实例教程 – cookie 和 session

本篇讲述在 Pylons 里使用 cookie 和 session。

示例还是在上篇《Pylons 入门实例教程 – 数据库操作》的代码里继续添加。先来尝试下  cookie,添加新的 cookietest controller。

修改 index 方法,添加显示部分:

    def index(self):
        name = 'NULL'
        if request.cookies.has_key('name'):
            name = request.cookies['name']
        return 'cookie name=%s' % name

cookie 读取可以通过 request.cookies 对象,类似一个字典结构。需要注意的是读取时候用最好 has_key 判断下,这样避免抛 KeyError 异常。当然你也可以 try…catch 捕获一下。

再重新写一个方法,用来写 cookie。

    def writecookie(self):
        response.set_cookie("name", "smallfish")
        return "write cookie ok"

这里只是简单设置一个值得,set_cookie 还有其他参数,具体如下:

set_cookie(self, key, value='', max_age=None, path='/', domain=None, secure=None,
                 httponly=False, version=None, comment=None, expires=None, overwrite=False)

基本一般需要设置:max_age,path,domain,expires 这几个参数。

下面再来尝试一下 session:

smallfish@debian:~/workspace/python/hellodb$ paster controller sessiontest
Creating /home/smallfish/workspace/python/hellodb/hellodb/controllers/sessiontest.py
Creating /home/smallfish/workspace/python/hellodb/hellodb/tests/functional/test_sessiontest.py

和上面 cookie 例子类似,在 controller 里有两个方法,index 负责显示 session,writesession 负责写。

    def index(self):
        name = session.get('name', 'NULL')
        return 'session name=%s' % name

    def writesession(self):
        session['name'] = 'smallfish'
        session.save()
        return "save session ok"

index 方法里 get 后面的 NULL 是默认值。writesession 里需要注意下设置 session 之后需要 save。

删除 session 可以尝试如下:

del session['name']
# 删除所有
session.delete()

到这里,WEB 常用的一些东西在 Pylons 里基本走了一圈,包含 URL、模板、数据库和会话部分。

下一节将会涉及怎么在 Nginx 上发布 Pylons 应用。

Pylons 入门实例教程 – 数据库操作

前面两篇入门,讲述了 Pylons 大致开发的流程、表单以及文件上传,思路大致跟传统的开发类似。本篇简单讲述下在 Pylons 如何使用数据库。

本篇侧重点是使用 ORM 框架 SQLAlchemy。现在 Python 社区里关注度比较高的大概有三:SQLAlchemySQLObject 和 Storm。其实本人最早是研究了一下 Storm,后来听虾哥(@marchliu)在应用里不是很爽之,遂关注了下他推荐的 SQLAlchemy。当然,你也可以对应数据库的 DB-API 库来进行操作。

示例代码的数据库是 PostgreSQL,对应的 Python 库使用的是 psycopg2。至于 Pg 配置和使用这里不再累赘,请狗之。

Debian/Ubuntu 安装很简单:

sudo aptitude install python-psycopg2

建立一个测试数据库,比如 test:

smallfish@debian:~/workspace/python/hello$ su postgres
postgres@debian:/home/smallfish/workspace/python/hello$ createdb -O smallfish test
postgres@debian:/home/smallfish/workspace/python/hello$ exit
smallfish@debian:~/workspace/python/hello$ psql -h 127.0.0.1 -p 5432 -U smallfish test
用户 smallfish 的口令:
psql (8.4.4)
SSL连接 (加密:DHE-RSA-AES256-SHA,位元:256)

输入 "help" 来获取帮助信息.

test=#

数据库的部分已经OK,下面就是来倒腾 Pylons 啦。

建立新项目,加入支持数据库部分,注意 Enter sqlalchemy那个选项,默认是 False,改成 True:

smallfish@debian:~/workspace/python$ paster create -t pylons hellodb
Selected and implied templates:
  Pylons#pylons  Pylons application template

Variables:
  egg:      hellodb
  package:  hellodb
  project:  hellodb
Enter template_engine (mako/genshi/jinja2/etc: Template language) ['mako']:
Enter sqlalchemy (True/False: Include SQLAlchemy 0.5 configuration) [False]: True
Creating template pylons
Creating directory ./hellodb

改成 True 之后在自动生成的 development.ini 里就有对应的数据库配置选项了。

再建立新的 db controller:

smallfish@debian:~/workspace/python$ cd hellodb/
smallfish@debian:~/workspace/python/hellodb$ paster controller db
Creating /home/smallfish/workspace/python/hellodb/hellodb/controllers/db.py
Creating /home/smallfish/workspace/python/hellodb/hellodb/tests/functional/test_db.py

编辑 development.ini,添加数据库配置部分。smallfish:123456 是对应的 PostgreSQL 用户名/密码,127.0.0.1:5432 是对应的主机地址/端口号,最后的test则是数据库名。

# SQLAlchemy database URL
sqlalchemy.url = postgresql://smallfish:123456@127.0.0.1:5432/test

编辑 hellodb/model/__init__.py,加上一个叫 msg 的表和字段的定义:

"""The application's model objects"""
from hellodb.model.meta import Session, metadata

from sqlalchemy import orm, schema, types
from datetime import datetime

def init_model(engine):
    """Call me before using any of the tables or classes in the model"""
    Session.configure(bind=engine)

def now():
    return datetime.now()

msg_table = schema.Table('msg', metadata,
    schema.Column('id', types.Integer, schema.Sequence('msg_seq_id', optional=True), primary_key=True),
    schema.Column('content', types.Text(), nullable=False),
    schema.Column('addtime', types.DateTime(), default=now),
)

class Msg(object):
    pass

orm.mapper(Msg, msg_table)

示例 Msg 表很简单,三个字段:ID、内容和时间。

上面的代码除去导入 sqlclchemy 包里几个库,基本上有一个对应表的字段定义,还有一个空的 Msg 对象。

最后一行,则是做一个 map 的动作,把 Msg 映射到 msg_table 上。

下面是不是要在数据库里建立对应的表呢?有个简单的办法 可以初始化数据库:paster setup-app development.ini:

smallfish@debian:~/workspace/python/hellodb$ paster setup-app development.ini
Running setup_config() from hellodb.websetup
20:08:43,619 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] select version()
20:08:43,619 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {}
20:08:43,625 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] select current_schema()
20:08:43,625 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {}
20:08:43,631 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and lower(relname)=%(name)s
20:08:43,631 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {'name': u'msg'}
20:08:43,637 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread]
CREATE TABLE msg (
        id SERIAL NOT NULL,
        content TEXT NOT NULL,
        addtime TIMESTAMP WITHOUT TIME ZONE,
        PRIMARY KEY (id)
)

20:08:43,637 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {}
20:08:43,732 INFO  [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] COMMIT

可以看到上面的输出日志,包括了建表的SQL语句。其中 SERIAL 对应上面 __init__.py 里 Column 的 Seq 定义。serial 类型 在 PostgreSQL 可以看成类似 MySQL 的自增ID(auto_increment) 。

现在进入 PostgreSQL 查询数据库,就可以看到表以及序列已经建立。

test=# \d
                  关联列表
 架构模式 |    名称    |  型别  |  拥有者
----------+------------+--------+-----------
 public   | msg        | 资料表 | smallfish
 public   | msg_id_seq | 序列数 | smallfish
(2 行记录)

到这里,准备工作已经完毕,包括了初始化数据库,配置文件还有示例 controller。

下面就在 controller 代码里增加读写数据库的功能吧。

首先建立一个表单模板 db.htm ,用来添加并保存到数据库表中:

<form action="/db/add" method="post">
    <input type="text" name="content" />
    <br />
    <input type="submit" value="save" />
</form>

对应 controller index 修改成,很简单。返回到模板:

class DbController(BaseController):

    def index(self):
        return render('/db.htm')

添加 add 方法,对应上面 form 中的 /db/add 路径:

    def add(self):
        content = request.POST['content']
        from hellodb import model
        msg = model.Msg()
        msg.content = content
        model.meta.Session.add(msg)
        model.meta.Session.commit()
        return "add %s ok..." % content

添加部分简单完成。获取 POST 文本框,然后初始化一个 Msg 对象(上面 model 里定义的)。

注意 add 之后,必须手动 commit,这样才会真正保存到数据库。

浏览器访问一下:http://127.0.0.1:5000/db/index,随意添加一点数据吧,这个时候你可以在 PostgreSQL 里查询已经数据已经加进来了。

下面在 index 方法传递一些值到模板,输出刚才已经添加的数据:

    def index(self):
        from hellodb import model
        c.msgs = model.meta.Session.query(model.Msg).all()
        return render('/db.htm')

c.msgs 可以理解成全局变量,关于 c 的定义在 controller前几行就应该看到了。修改模板 db.htm 显示记录:

% for msg in c.msgs:
<p>${msg.id}: ${msg.content} / ${msg.addtime}</p>
% endfor

很简单,只是一个普通 for 循环,遍历 index 方式里传递的 c.msgs。Mako模板还是很易读的吧?

继续刷新下:http://127.0.0.1:5000/db/index,可以在页面上看到已经添加的数据了。

在狂输入了几十条之后,在一页里显示是不是忒土鳖了?

下面再介绍下 Pylons 里 webhelper 里一个分页组件的用法,当然你也可以自己写分页算法。下面是示例:

    def list(self):
        from webhelpers import paginate
        from hellodb import model
        msgs = model.meta.Session.query(model.Msg)
        c.paginator = paginate.Page(
            msgs,
            page=int(request.params.get('page', 1)),
            items_per_page = 10,
        )
        return render("/list.htm")

导入 paginate,然后把查询的数据库对象当参数传递给 paginate.Page,里面的page则是页面的传递的页数参数,items_per_page 就好理解多了,就是多少条一页。这里是10条。

对应的模板 list.htm 如下:

<pre>
% if len(c.paginator):

% for msg in c.paginator:
<p>${msg.id}: ${msg.content}</p>
% endfor

<p> ${c.paginator.pager("count: $item_count $first_item to $last_item , $link_first $link_previous $link_next $link_last")} </p>
% endif

for 部分如同上面示例,下面加了一行pager。里面一些变量从名字上就可以看出功能了。包括了总条数、当前是第几到第几条,然后就是常用的首页、上页、下页和最后一页。

这里链接的文字都是<<, <, >, >>。想改成文字请查看文档吧。。如果是第一页,是不会显示首页和上一页的。这个做过分页的一般都写过类似的代码吧。

现在访问:http://127.0.0.1:5000/db/list,想看到效果当然你得多填点数据哦。10条才会显示分页的挖。

好了,这里对数据库增加和显示部分都已经有示例代码了,当然最后还有一个分页用法。至于删除和更新之类请参考 SQLAlchemy 文档吧。

Pylons 入门实例教程 – 表单和文件上传

继续上一篇《Pylons 入门实例教程 – Hello》,现在开始讲在 Pylons 里如何提交表单和上传文件。

继续延用上篇里面的 hello 工程,在 HiController 里添加 form 方法:

    def form(self):
        return render('/form.mako')

加完以后可以访问:http://127.0.0.1:5000/hi/form,会报错。

Server Error,根据报错内容大致就知道模板文件不存在了。如果有其他错误,也可以通过这个页面查看,当然还有很强大的 Debug 个功能哦。当然正式环境一般都是关闭这个功能的。这个,你懂得。。。

好吧,写一个表单的模板,只包含一个简单的文本框和提交按钮示例。

<form action="/hi/submit" method="post">
name: <input type="text" name="name" />
<br />
<input type="submit" value="submit" />
</form>

再添加一个 submit 方法来处理表单提交,

    def submit(self):
        return "hello, name: %s" % request.params['name']

request.params 包含了表单或者URL提交的参数,建议 POST 数据参照下面的上传部分。想获取更详细的列表,可以查看文档或者自己手动 dir()查阅。

下面尝试一下文件上传,首先在 development.ini 添加一个变量,用来存放文件上传后的文件夹。

[app:main]
upload_dir = %(here)s/upload

%(here) 启动后 server 会替换到当前目录地址,上面的地址就是当前路径下的upload文件夹。

修改一下刚才的表单,加一个 file 上传,注意 multipart/form-data 这句,上传必须。

<form action="/hi/submit" method="post"  enctype= "multipart/form-data">
name: <input type="text" name="name" />
<br />
file: <input type="file" name="file" />
<br />
<input type="submit" value="submit" />
</form>

修改 submit 方法,添加文件内容:

    def submit(self):
        name   = request.POST['name']
        myfile = request.POST['file']
        import os
        import shutil
        from pylons import config
        local_name = os.path.join(config['app_conf']['upload_dir'], myfile.filename)
        local_file = open(local_name, "wb")
        shutil.copyfileobj(myfile.file, local_file)
        myfile.file.close()
        local_file.close()
        return "hello, name: %s, upload: %s" % (name, myfile.filename)

里面 import 部分这里仅仅为了示例,正式的代码请放入程序开头部分,POST 内容可以从 request.POST 获取。

config['app_conf']['upload_dir'] 就是刚才配置里 development.ini 定义的地址。这个目录需要自己手动创建哦。

smallfish@debian:~/workspace/python/hello$ mkdir upload

OK,到这里程序部分都已经修改完成。重新访问一下:http://127.0.0.1:5000/hi/form

尝试一下上传,上传后可以在 upload 文件夹下看到文件了吧。。

当然这里只是示例,还需要处理一下上传的名字,防止有特殊符号哦。

如何写 Go 代码?

原文:http://golang.org/doc/code.html

简述

这篇文档描述了如何去写一个新的 package 和怎么去测试。本文假设你已经按照安装文档装好Go。

在修改一个存在的 package 或者新建立一个package,确保先发一封邮件到 mailing list,告诉大家你想做什么。这样有助于不要重复造轮子,在写代码之前最好讨论下。

社区资源

如果想获取实时帮助,可以加入 Freenode 上 IRC 频道 #go-nuts。

Go 语言官方邮件列表是 Go nuts.

Bugs 可以参考 Go issue.

对于那些想尝试开发代码的用户,这里有另外一个邮件列表 golang-checkins,邮件里包含了那些刚提交到 Go 代码库的消息。

建立Go包

下面的源码假设 package 的导入路径是 x/y,约定下保存的路径是:$GOROOT/src/pkg/x/y

Makefile

这将是很好的利用 Go-specific 工具里安排源码结构,如何按照顺序和构建代码。Go 使用 GUN make。所以首先在一个新的package 文件夹里建立一个 Makefile。最简单的做法就是从 src/pkg/container/vector/Makefile 源码包里拷贝一份。

include ../../../Make.$(GOARCH)

TARG=container/vector
GOFILES=\
	intvector.go\
	stringvector.go\
	vector.go\

include ../../../Make.pkg

当然在上面的源码包之外写一个新的 package ,通常的 Makefile 如下:

include $(GOROOT)/src/Make.$(GOARCH)

TARG=mypackage
GOFILES=\
	my1.go\
	my2.go\

include $(GOROOT)/src/Make.pkg

第一行 include 标准的定义和规则,package 的路径一般相对路径来代替 $(GOROOT)/src ,这样做到目的就是防止 make 时候 $(GOROOT) 含有空格,这样做很方便开发中使用Go。

TRAG 是包安装路径,这行就是其他程序导入到名字。在 Go 源码中,这个名字必须和文件夹中的 Makefile 中的一致,不需要 $GOROOT/src/pkg/ 前缀。在源码之外,你可以任意起名而不要和标准 package 的重名即可。常见的做法是独立一个 package 名:myname/tree, myname/filter,确保你的代码在 myname 里,运行 make install,将会编译后把二进制文件放入 $GOROOT/pkg,可以很方便的找到。

GOFILES 放入文件内需要编译的源码列表。多行用 \ 字符隔开。

如果想在 Go 源码树中新建包,需要添加列表到 $GOROOT/src/pkg/Makefile 中作为标准库编译,编译运行:

cd $GOROOT/src/pkg
./deps.b

更新依赖文件 Make.deps (这是每次 make all 或者 make build 都需要)

Go 源文件

在每个源码里第一行的名字应该是 Makefile 里面定义的 package 名,这里的 name 是作为默认的名字导入。(包里的每个 package 名都应该是同样的名字)Go的惯例是用路径的最后一个元素作为名字,比如 “crypto/rot13″ 应该是 rot13。到目前为止,Go 是依靠 package 名字来确定一个二进制的文件,当然可能会很快的取消。

Go 是在一个包内编译源码文件,在一个文件定义常量,变量,类型或者函数,在其他文件内适用不需要再定义和声明。

想写一个干净而优美的 Go 代码不在本文范围。请参考深入 Go 文档吧。

测试

Go 有一个轻量级的测试代码框架:gotest。编写一个测试代码,只需要新建一个跟你源码名字一样,加上:_test.go 即可,测试函数一般是 func TestXXX (t *testing.T)。每次运行测试其中的函数。如果想返回错误的话一般是返回: t.Error 或 t.Fail,测试时候就会抛错。详细 gotest 测试方法请参考:http://golang.org/pkg/testing/

*_test.go 不需要在 Makefile 中声明。

运行测试,编译时候 make test 即可,和 gotest 效果一样。如果想单独测试某一个源码,比如:one_test.go,则运行:gotest one_test.go。

如果你的修改影响性能,可以添加一个性能测试函数(参考:http://golang.org/pkg/testing/),然后运行:gotest -benchmarks=.

当你新的代码已经通过测试,也能运行,你就可以 review 和 commit.  http://golang.org/doc/contribute.html

一个测试的例子

这是一个名字叫 numbers 测试 package ,定义了一个叫 Double 的函数,返回一个整型,结果是输入的参数乘以2。一共有三个文件。

第一个是 numbers.go

package numbers

func Double(i int) int {
	return i * 2
}

第二个是测试文件 numbers_test.go

package numbers

import (
	"testing"
)

type doubleTest struct {
	in, out int
}

var doubleTests = []doubleTest{
	doubleTest{1, 2},
	doubleTest{2, 4},
	doubleTest{-5, -10},
}

func TestDouble(t *testing.T) {
	for _, dt := range doubleTests {
		v := Double(dt.in)
		if v != dt.out {
			t.Errorf("Double(%d) = %d, want %d.", dt.in, v, dt.out)
		}
	}
}

最后是 Makefile 文件

include $(GOROOT)/src/Make.$(GOARCH)

TARG=numbers
GOFILES=\
	numbers.go\

include $(GOROOT)/src/Make.

运行 make install 将会构建和安装包到 GOROOT/pkg/ 文件夹内(他在系统的任何地方导入调用)。

运行 make test (或者 gotest)将会重新构建包,并会运行 numbers_test.go 中的 TestDouble 函数。如果输出 “PASS” 则表示测试成功通过。如果不是2到3的倍数,将会看到错误报告。

更详细的请查看 gotest 文档测试package文档。

Pylons 入门实例教程 – Hello

Pylons 是 Python 的一个轻量级 MVC Web 开发框架,跟另外一个框架 TurboGears 比较相似,都是集合了一些优秀的组件而成。比如对 Request URL 采用了 Route,Template 采用了 Mako,数据库层则采用了ORM SQLAlchemy,当然,这些组件只是默认,你还可以根据自己喜好来选择其他组件,比如你可以采用 Jinja2 或 Genshi 模板,ORM也可以采用 SQLObject。完全是自由组合。

废话少说,现在开始安装吧。

smallfish@debian:~$ sudo aptitude install python-pylons

Debian/Ubuntu 系列系统可以直接 aptitude 安装,当然你也可以使用 easy_install 或者源码安装。

smallfish@debian:~$ sudo easy_install Pylons

更多安装文档请参考官网安装部分,http://pylonshq.com/docs/en/1.0/gettingstarted/#installing

好了,安装结束,来一个经典的Hello程序吧。

smallfish@debian:~/workspace/python$ paster create -t pylons hello
Selected and implied templates:
  Pylons#pylons  Pylons application template

Variables:
  egg:      hello
  package:  hello
  project:  hello
Enter template_engine (mako/genshi/jinja2/etc: Template language) ['mako']:
Enter sqlalchemy (True/False: Include SQLAlchemy 0.5 configuration) [False]:
Creating template pylons
Creating directory ./hello

下面输出略过,大致解说一下。Pylons 程序可以用 Paste 自动生成一些代码,包括controller。还可以运行 HTTP 服务来测试。

-t  表示自动创建的模板,可以如下来查看有哪些选项,更多就参考 help 吧。

smallfish@debian:~/workspace/python/hello$ paster create --list-templates
Available templates:
  basic_package:   A basic setuptools-enabled package
  paste_deploy:    A web application deployed through paste.deploy
  pylons:          Pylons application template
  pylons_minimal:  Pylons minimal application template

看一下hello的目录结构:

smallfish@debian:~/workspace/python/hello$ ls
development.ini  ez_setup.py  hello.egg-info  README.txt  setup.py
docs             hello        MANIFEST.in     setup.cfg   test.ini

这里具体各个文件意思就不讲解了,程序主体部分都在hello/hello目录下,development.ini 和 test.ini 分别是服务启动的配置文件,用于测试和开发环境。开始先运行一下,看效果吧。。

smallfish@debian:~/workspace/python/hello$ paster serve --reload development.ini
Starting subprocess with file monitor
Starting server in PID 1519.
serving on http://127.0.0.1:5000

在浏览器中打开:http://127.0.0.1:5000 看到页面了吧?恭喜。

继续,写一个简单的显示 hi的 controller 程序吧。

smallfish@debian:~/workspace/python/hello$ paster controller hi
Creating /home/smallfish/workspace/python/hello/hello/controllers/hi.py
Creating /home/smallfish/workspace/python/hello/hello/tests/functional/test_hi.py

自动生成程序和 test 文件。paster 启动服务不需要重启会自动加载,可以浏览器访问:http://127.0.0.1:5000/hi/index

很简单吧,打开 hi.py,基本如下:

class HiController(BaseController):

    def index(self):
        # Return a rendered template
        #return render('/hi.mako')
        # or, return a response
        return 'Hello World'

上面注释部分可以 return 一个模板文件,模板放入 templates 目录下即可。

去除上面的 return ‘Hello’ 返回 return render(‘/hi.mako’)

smallfish@debian:~/workspace/python/hello$ vi hello/templates/hi.mako
% for key, value in request.environ.items():
 ${key} = ${value}
% endfor

刷新 http://127.0.0.1:5000/hi/index ,可以看到一些环境变量的输出了吧。

今天就简单的说到这里吧,下回来一个完整的例子,包括URL、模板、数据库和Session的实例。

PostgreSQL COPY 导入/导出数据

COPY 命令可以快速的导入数据到 PostgreSQL 中,文件格式类似CVS之类。适合批量导入数据,比 \i 和恢复数据表快。

导出表数据到文件或 STDOUT :

COPY tablename [(column [, ...])]
   TO {'filename' | STDOUT}
   [[WITH]
      [BINARY]
      [OIDS]
      [DELIMITER [AS] 'delimiter']
      [NULL [AS] 'null string']
      [CSV [HEADER]
         [QUOTE [AS] 'quote']
         [ESCAPE [AS] 'escape']
         [FORCE NOT NULL column [, ...]]

导入文件或者 STDIN 到表中:

COPY tablename [(column [, ...])]
   FROM {'filename' | STDIN}
   [[WITH]
      [BINARY]
      [OIDS]
      [DELIMITER [AS] 'delimiter']
      [NULL [AS] 'null string']
      [CSV [HEADER]
         [QUOTE [AS] 'quote']
         [ESCAPE [AS] 'escape']
         [FORCE QUOTE column [, ...]]

导出表 employee 到默认输出 STDOUT:

psql> COPY employee TO STDOUT;
1       JG100011        Jason Gilmore         jason@example.com
2       RT435234        Robert Treat          rob@example.com
3       GS998909        Greg Sabino Mullane   greg@example.com
4       MW777983        Matt Wade             matt@example.com

导出表 employee 到 sql 文件:

psql> COPY employee TO '/home/smallfish/employee.sql';

从文件导入数据:

psql> COPY employeenew FROM '/home/smallfish/employee.sql';
psql> SELECT * FROM employeenew;
employeeid  | employeecode |     name            |       email
------------+--------------+---------------------+---------------
          1 | JG100011     | Jason Gilmore       | jason@example.com
          2 | RT435234     | Robert Treat        | rob@example.com
          3 | GS998909     | Greg Sabino Mullane | greg@example.com
          4 | MW777983     | Matt Wade           | matt@example.com
(4 rows)

输出对象ID(OIDS):

psql> COPY employee TO STDOUT OIDS;
24627  1       GM100011        Jason Gilmore         jason@example.com
24628  2       RT435234        Robert Treat          rob@example.com
24629  3       GS998909        Greg Sabino Mullane   greg@example.com
24630  4       MW777983        Matt Wade             matt@example.com

指定导出间隔符,默认是 \t ,这里为 | :

psql>COPY employee TO STDOUT DELIMITER '|';
1|GM100011|Jason Gilmore|jason@example.com
2|RT435234|Robert Treat|rob@example.com
3|GS998909|Greg Sabino Mullane|greg@example.com
4|MW777983|Matt Wade|matt@example.com

导入文件数据,指定间隔符为 | :

psql> COPY employeenew FROM '/home/smallfish/employee.sql' DELIMITER |;

导出指定字段的数据:

psql> COPY employee (name,email) TO STDOUT;
Jason Gilmore         jason@example.com
Robert Treat          rob@example.com
Greg Sabino Mullane   greg@example.com
Matt Wade             matt@example.com

为 NULL 字段设置默认值:

psql> COPY employee TO STDOUT NULL 'no email';
Jason Gilmore         no email
Robert Treat          rob@example.com
Greg Sabino Mullane   greg@example.com
Matt Wade             no email

导出为CVS格式:

psql> COPY employee (name, email) TO '/home/smallfish/employee.csv' CSV HEADER;

参考资料:Apress Beginning PHP and PostgreSQL 8: From Novice to Professional

Go 语言模块安装工具:goinstall

文档地址:http://golang.org/cmd/goinstall/ Go模块列表:http://godashboard.appspot.com/package

goinstall 主要是方便安装第三方模块,目前支持 hg(mercurial),git,svn三种版本控制系统。

下面来举例怎么安装 web.go 模块。源地址是:http://github.com/hoisie/web.go

smallfish@debian:~$ goinstall -dashboard=true github.com/hoisie/web.go

根据网速快慢,过一段时间会结束。期间木有任何提示。(可以加上 -v=true 参数,可以显示安装过程和提示。)

查看下安装的目录和路径:

smallfish@debian:~$ ls $GOROOT/src/pkg/github.com/hoisie/web.go/
examples  _go_.8   Makefile  Readme.md   scgi.go       status.go  web_test.go
fcgi.go   LICENSE  _obj      request.go  servefile.go  web.go

代码示例:

import (web "github.com/hoisie/web.go")

另外注意点,官方文档里 -update 选项现在版本里已经缩写,改成 -u。

Cython 教程 – 调用外部C语言函数

一般情况完全可以在 Python 里导入 from math import sin 然后调用 sin() 函数。然而,调用C里面的 sin() 函数速度会更快,尤其在复杂的循环里。在 Cython 里可以这样声明和使用:

cdef extern from "math.h":
    double sin(double)

cdef double f(double x):
    return sin(x*x)

请注意,上面的代码声明了 math.h 里的函数,提供给 Cython 使用。C编译器在编译时将会看到 math.h 的声明,但 Cython 不会去分析 math.h 和单独的定义。

当调用一个C函数时,一定要注意引入适当的链接库。这个依赖于特定的平台;下面的例子可以在Linux和Mac OS X下运行:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_modules=[
    Extension("demo",
              ["demo.pyx"],
              libraries=["m"]) # Unix-like specific
]

setup(
  name = "Demos",
  cmdclass = {"build_ext": build_ext},
  ext_modules = ext_modules
)

跟从 math 库里使用 sin() 函数一样,它可以声明和导入任何C库,Cython会生成正确的共享或者静态链接库。

参考:http://docs.cython.org/src/tutorial/external.html

其实我就是个演员

注:此文系纯水贴,正经人士请绕道。 :)

场景1
某日很HI的写着程序,凑巧做网页的美工不在,活又耽误不得,只能捋起袖子,装起了Dreamweaver+Fireworks,三下五除二搞定了前端页面。话说自从开始写程序起,就很少碰这些高级玩意了。现在只是偶尔PS修修抠抠图,享受下钢笔抠图小YY一把就足够了。
其实在做程序之前,俺一直是个美工,作图做页面只不过信手拈来。

场景2
简历给某朋友看了之后,很惊讶道:原来你是做Java的?只好含泪不语+内流满面了。难道我博客只写Python或者Perl,不意味着俺就是折腾这些的哇。只好幽幽的坦然回答之:其实我的主业是Java开发者,做了六年多。
其实动态语言只是我的业余爱好,顺带写了点分享的博文而已。只不过对外闭口没提Java。

场景3
有些朋友看我经常推荐PostgreSQL,就问俺:Pg和MySQL到底有哪些区别?描述种种,感觉可能他也云里雾里。遂让他自己说说需求,最后还是推荐他用MySQL。顺带讲述了一些常用优化和监控的办法。丫又惊讶的说原来你一直用的MySQL啊。好吧,只好再次内流。
其实我正儿八经用数据库最长久的就是MySQL了,基本也有六年多了把。Pg只是我的业余爱好,没事研究了下,寻找下乐趣而已。

如此场景会继续重现,遂略过数字。。。

其实,我就是个演员。对系统(Linux)、语言(Java/Python/Perl)、数据库(MySQL/PostgreSQL)都略懂的角色。

不同的时间,演绎不同的角色。过去是,现在是,将来也是。

[图文解说] Virtual Box 通过 NAT(默认) 共享虚拟机中的服务

Virtual Box 是个不错的虚拟机,小巧,功能也齐全。好像有点推销鸟。说正题,上次有个朋友就提到怎么能主机里访问虚拟机里的服务,昨晚实验了下,颇为顺利。记录下。这里利用的是默认的NAT上网,也就是共享主机上网,而不是设置独立的IP。

主机:Win XP
虚拟:Ubuntu 9.10

目的:Win里ssh进Ubuntu,能访问里面提供的服务。

主要是通过 VBoxManage setextradata 设置一些属性。

先上几个步骤图把。注意一下修改,先得关闭虚拟机,修改完事以后再启动。

1. 查看虚拟机中的名称:ubuntu9

2. 进入本机Vbox目录,运行VBoxManage,查看下。


3. 添加三个项目

下面的pcnet是vbox里的网络设置,0是表示第一个网卡,后面一次类推。22是ssh端口,映射到主机的22端口。

VBoxManage setextradata "ubuntu9"  "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/Protocol" TCP
VBoxManage setextradata "ubuntu9"  "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/GuestPort" 22
VBoxManage setextradata "ubuntu9"  "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/HostPort" 22

4. 再次查看

5. 启动虚拟机。

6. 设置putty登陆之。

到这里已经顺利ssh 到127.0.0.1,如果想访问虚拟机里的web服务器呢?同样很简单。

只要如下设置,web端口为81,跟上面也雷同:

VBoxManage setextradata "ubuntu9" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/Protocol" TCP
VBoxManage setextradata "ubuntu9" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/GuestPort" 81
VBoxManage setextradata "ubuntu9" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/HostPort" 81

另外如果想清空上面设置的选项,只要不设置后面的值即可:

VBoxManage setextradata "ubuntu9" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/web/Protocol"