如果一张表的主键是自动增长的,当插入一条记录后可以通过使用flush来获取id,再进行其它操作后再commit。代码如下:

1
2
3
4
5
user = User(name='chronos')
session.add(user)
session.flush()
print user.id
session.commit()

一直想找一个快速全文搜索的工具,目前找到的有Sphinx,xapian,Lucene,solr, elasticsearch ,whoosh,hyper estraier等,原本一直不太喜欢用java系的,内存大户伤不起啊。尝试了sphinx,xapian,hyper estraier,其中xapian资料太少,hyper estraier虽然比较简单,但资料也少。sphinx到是有一个中文化的分支coreseek,然后看到文档里面提到sphinx支持一元切分,但根据查询的例子去查的结果不是我想要的,不知道是不是我的查询语句用错了。而且因为我是在windows上测试的,而我的python又是2.7的版本,无法在 coreseek 上直接使用,应该需要重新编译。后来看到 elasticsearch ,真是亮瞎老夫的狗眼啊,这货直接可以用restful json操作又有pyes,pyelasticsearch这些已经封装好的操作库。 elasticsearch 还是支持分布式,扩展也方便了。由于是java开发的,跨平台也无问题,默认单机尝试的时候无须改配置,直接运行 bin/elasticsearch.bat 就可以了。

安装pyes

1
pip install pyes

使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#coding:utf-8

import pyes

conn = pyes.ES(['127.0.0.1:9200'])#连接es

conn.create_index('test-index')#新建一个索引

#定义索引存储结构
mapping = { u'parsedtext': {'boost': 1.0,
'index': 'analyzed',
'store': 'yes',
'type': u'string',
"term_vector" : "with_positions_offsets"},
u'name': {'boost': 1.0,
'index': 'analyzed',
'store': 'yes',
'type': u'string',
"term_vector" : "with_positions_offsets"},
u'title': {'boost': 1.0,
'index': 'analyzed',
'store': 'yes',
'type': u'string',
"term_vector" : "with_positions_offsets"},
u'position': {'store': 'yes',
'type': u'integer'},
u'uuid': {'boost': 1.0,
'index': 'not_analyzed',
'store': 'yes',
'type': u'string'}
}

conn.put_mapping("test-type", {'properties':mapping}, ["test-index"])#定义test-type
conn.put_mapping("test-type2", {"_parent" : {"type" : "test-type"}}, ["test-index"])#从test-type继承

#插入索引数据
#{"name":"Joe Tester", "parsedtext":"Joe Testere nice guy", "uuid":"11111", "position":1}: 文档数据
#test-index:索引名称
#test-type: 类型
#1: id 注:id可以不给,系统会自动生成
conn.index({"name":"Joe Tester", "parsedtext":"Joe Testere nice guy", "uuid":"11111", "position":1}, "test-index", "test-type", 1)

conn.index({"name":"data1", "value":"value1"}, "test-index", "test-type2", 1, parent=1)
conn.index({"name":"Bill Baloney", "parsedtext":"Bill Testere nice guy", "uuid":"22222", "position":2}, "test-index", "test-type", 2)
conn.index({"name":"data2", "value":"value2"}, "test-index", "test-type2", 2, parent=2)
conn.index({"name":u"百 度 中 国"}, "test-index", "test-type")#这个相当于中文的一元切分吧-_-
conn.index({"name":u"百 中 度"}, "test-index", "test-type")

conn.default_indices=["test-index"]#设置默认的索引
conn.refresh()#刷新以获得最新插入的文档

q = pyes.TermQuery("name", "bill")#查询name中包含bill的记录
results = conn.search(q)

for r in results:
print r

#查询name中包含 百度 的数据
q = pyes.StringQuery(u"百 度",'name')
results = conn.search(q)

for r in results:
print r

#查询name中包含 百度 或着 中度 的数据
q = pyes.StringQuery(u"百 度 OR 中 度",'name')
results = conn.search(q)

for r in results:
print r

今天搜索了一下pypi,发现flask的扩展好多,很多东西都非常有用,其中flask-debugtoolbar是调试的利器啊,看文档里面写的使用方法也非常简单,只要加一下配置初始化一下就好。可是我在使用的时候一直无法显示,但文档里也就那么几句话,搞不明白了。刚开始还以为是flask的版本问题,特意将0.9降到了0.8,但还是没有效果。后来下载了一个example,居然可以运行。只好一点点对比两个项目的不同之处,丫的最后才发现原来这个debugtoolbar一定要模板中存在 </body> 标签,否则无法显示。

首先请大家看一下错误信息:

Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\pyramid\mako_templating.py", line 192, in
__call__
    result = template.render_unicode(**system)
  File "C:\Python27\lib\site-packages\mako\template.py", line 311, in render_uni
code
    as_unicode=True)
  File "C:\Python27\lib\site-packages\mako\runtime.py", line 661, in _render
    return context._pop_buffer().getvalue()
  File "C:\Python27\lib\site-packages\mako\util.py", line 136, in getvalue
    return self.delim.join(self.data)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 151: ordina
l not in range(128)

如果也提示了这个信息,但页面的编码什么都正确的很可能就是遇到了跟我一样的问题。解决方法在注意__init__.py文件的内容。我这边的情况是工程的__init__.py文件中有下面一段内容就会出现这个错误。

1
2
3
4
5
6
7
8
9
10
11
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
config.add_route('getcategories','/get_categories')#获取wp类别信息
config.scan()
return config.make_wsgi_app()

注意其中的注释的位置,当注释跟在config.add_route语句后面直接出现中文的情况下就会出现那个问题,然后我对注释做了一下修改。

1
2
3
4
5
6
7
8
9
10
11
12
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
#获取wp类别信息
config.add_route('getcategories','/get_categories')
config.scan()
return config.make_wsgi_app()

将注释改到不同的行上面就不会出现错误了,当时我还以为我的项目名称有问题,特地的新建了一个项目。最后跟以前的另一个项目做对比,发现原来是这个地方出现问题了,看错误提示还真看不出来是什么问题。在此记下,以免以后又遇到这个问题的时候忘了怎么解决。

ubuntu的resolv.conf文件重启后被还原其实是因为/etc/init.d/resolvconf的关系,可以直接禁用resolvconf的自动启动,或着将nameserver添加到/etc/resolvconf/resolv.conf.d/base文件里面,格式跟resolv.conf文件相同,然后重启一下resolvconf服务就可以看到效果了。

base:

1
2
nameserver 8.8.8.8
nameserver 8.8.4.4

web浏览器的js打印在不同浏览器下面的效果有很大差别,对一些精度要求较高的场景很不适合,而且分页控制困难。如果采用pdf打印就比较完美了,目前测试ie和firefox都需要安装pdf阅读器才能支持pdf在线打开和打印,而chrome可以直接支持。

在python下有reportlab可以生成pdf,实用上较为复杂,后来发现了xhtml2pdf,直接转换html到pdf,支持css,实际使用下来发现它并不是完整的html支持,比如position就不支持,但可以通过@frame解决。

下面是一段示例:

test.py:

1
2
3
4
5
6
7
8
from cStringIO import StringIO

import xhtml2pdf.pisa as pisa

pdf = pisa.CreatePDF(open('test.html','rb'),open('test.pdf','wb'))

if not pdf.err:
print "pdf is build"

test.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<html>
<style>

@font-face {
font-family: simsun;
src: url(c:\windows\fonts\simsun.ttc);
}
body{
font-family: simsun;
}

@page {
margin: 1cm;
margin-bottom: 2.5cm;
font-family: simhei;
@frame footer {
-pdf-frame-content: footerContent;
bottom: 2cm;
margin-left: 1cm;
margin-right: 1cm;
height: 1cm;
font-family: simhei;
}
}
</style>
<body>
<div id="footerContent">
This is a 中文 on page #<pdf:pagenumber>
</div>
</body>
</html>

xhtml2pdf默认是不支持中文字体的,通过@font-face可以添加新字体,我在这里添加了一个宋体。<pdf:pagenumber> 是xhtml2pdf的特殊标签,这里指在是在这个位置显示当前页码。

我原先的一台下载机装的是ubuntu11.10的桌面版。后来因为完全用不到桌面,而且加了图形界面后速度慢很多,默认的更新服务也会严重拖慢我的硬盘速度,所以直接把图形给删掉了,然后安装了一个samba服务用于给windows共享文件。安装方法见 http://blog.plotcup.com/a/36 ,配置完成后打开共享时才发现原来用nautilus设置的共享文件夹居然全在,找了很久也没找到相关的配置在什么地方,后来还是在ubuntu论坛上的一个帖子里面找到的。

当nautilus设置共享的时候会在 /var/lib/samba/usershares 下面设置相应配置文件,一个文件夹对应一个文件。想去掉哪个文件夹直接删掉就好,当然如果想要添加共享文件夹也可以添加到这个地方,比较方便管理。

最近我这边原来的那个老的路由器出了点问题,经常抽风。正好因为以前外网有6个ip,所以当时把外网线直接接在了交换机上,那么就想着用虚拟机自己搭建一个简单的路由器用用。现在服务器资源过剩,有什么方案就在上面建虚拟机试验。去网上找了很多资料然后自己摸索着在ubuntu上搭了一个路由器。

配置网卡

建立一台虚拟机,并安装完成后以桥接的方式在虚拟机上面添加两张网卡。分别为eth0和eth1。

  • eth0: a.b.c.d(外网的上网地址)
  • eth1: 172.16.44.1(做为内网的网关)

tip

原先我使用eth0:0的这种虚拟网卡的形式去配置一直不成功,后来使用双网卡的时候一直忘了把eth0:0这张虚拟网卡删掉导致了限速配置一直不成功,浪费了大把的青葱。

配置iptables nat

1
2
3
4
5
6
7
8
9
10
#开启ip_forward
echo "1">/proc/sys/net/ipv4/ip_forward

#清除原来的防火墙规则
iptables -F
iptables -t nat -F
iptables -t mangle -F

#添加nat转发
iptables -t nat -A POSTROUTING -s 172.16.44.0/24 -o eth0 -j MASQUERADE

通过执行上面的代码后,局域网内的电脑就可以上网了。

端口转发

由于我的内网还挂了网站,所以要开启80端口的转发。

1
2
iptables -t nat -I PREROUTING -p tcp -d a.b.c.d --dport 80 -j DNAT --to 172.16.44.210:80
iptables -t nat -I POSTROUTING -p tcp -d 172.16.44.210 --dport 80 -j SNAT --to 172.16.44.1

这条命令指定外网地址a.b.c.d的80端口转发到172.16.44.210:80上。由于是双网卡,所以需要做一下回路。

下载限速

下载限速要在eth1上面做,判断数据包的目的地址来做限制。tc包括三部分:队列、类、过滤器。我使用了htb方式去限制速度,也可以使用cbq,但cbq配置比较复杂一点,而且据说性能没htb好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#删除原来的tc规则队列
tc qdisc del dev eth1 root
#添加tc规则队列
tc qdisc add dev eth1 root handle 10: htb default 256
#生成根类
tc class add dev eth1 parent 10: classid 10:1 htb rate 100mbit ceil 100mbit
#支类列表用于限制速度
#这里的rate指的是保证带宽,ceil是最大带宽。
tc class add dev eth1 parent 10:1 classid 10:10 htb rate 400kbps ceil 400kbps prio 1

#添加支类规则队列
#采用sfq伪随机队列,并且10秒重置一次散列函数。
tc qdisc add dev eth1 parent 10:10 handle 101: sfq perturb 10

#建立网络包过滤器,设置fw。
tc filter add dev eth1 parent 10: protocol ip prio 10 handle 1 fw classid 10:10
#在iptables里面设定mark值,与上面的handle值对应。
iptables -t mangle -A POSTROUTING -d 172.16.44.130 -j MARK --set-mark 1
iptables -t mangle -A POSTROUTING -d 172.16.44.130 -j RETURN

通过上面的代码就可以限制172.16.44.130这台机子的下载速度到400kbps。

tip

经过实际测试这里的kbps实际上就是KB/S每秒千字节。另一个单位是kbit,这个才是每秒千比特。这里的172.16.44.130也可以写成一个网段,比如:172.16.44.0/24

上传限速

上传限速的原理其实跟下载的差不多,只不过限制的网卡不同,要在eth0上过滤来源地址去限制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#删除原来的tc规则队列
tc qdisc del dev eth0 root

#添加tc规则队列
tc qdisc add dev eth0 root handle 20: htb default 256

#生成根类
tc class add dev eth0 parent 20: classid 20:1 htb rate 100mbit ceil 100mbit

#支类列表用于限制速度
tc class add dev eth0 parent 20:1 classid 20:10 htb rate 40kbps ceil 40kbps prio 1

#添加支类规则队列
tc qdisc add dev eth0 parent 20:10 handle 201: sfq perturb 10

#建立网络包过滤器
tc filter add dev eth0 parent 20: protocol ip prio 100 handle 2 fw classid 20:10
iptables -t mangle -A PREROUTING -s 172.16.44.130 -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -s 172.16.44.130 -j RETURN

tip

跟下载不同的是POSTROUTING要改成PREROUTING,-d改成-s。

观察连接数

通过iptables的nat连接可以通过下面的代码查看。至于统计连接数可以写代码实现,也可以利用awk,grep等工具。反正里面的内容就是文本,处理起来也比较简单。

1
cat /proc/net/ip_conntrack

写在结尾

到此上网、端口转发和流量限制都已经实现。下次再考虑配置个dhcp server和dnsmasq。至于一些路由器其它诸如mac地址绑定,限制上网等用到的时候再去研究研究。

下载

Sublime Text 2 的下载地址是 http://www.sublimetext.com/2,如果你的 Linux 系统是64位的,那么别忘了下载64位的程序包,速度和性能都大不一样的。

解压

你可以使用 GUI 管理工具来解压,不过我更加推荐使用命令行工具。打开 Terminal < ctrl + alt + t >,首先进入存放下载程序包的文件夹:(假设是用户目录下的 Downloads 文件夹)

1
~$ cd ~/Downloads/

然后解压缩下载好的程序包:

1
Downloads$ tar -xf Sublime\ Text\ 2.0.1\ x64.tar.bz2

.tar.bz2 这样后缀名的文件可以当作类似于 Windows 下的 .zip 文件;`\` 是转义字符,它的作用是把文件名中的空格做字符化处理,这样就不会被命令误当成是分隔符号了。

运行

进入解压缩后的文件夹,我们可以看到 Sublime Text 2 的组成文件,并且可以执行以下命令运行它:

1
Sublime Text 2$ ./sublime_text

不过还有两个问题值得注意:

  • 应用程序应该保存在什么特定的地方呢?

首先,象 Ubuntu 这样的 Linux 系统并没有规定用户必须把应用程序保存在一个固定的地方,不过按照惯例通常有以下几个方案可供选择:

  1. 保存在 /usr/lib/ 或 /usr/local/lib/ 文件夹下
  2. 保存在 /opt/ 文件夹下
  3. 保存在 ~/apps/ 或类似的用户自定义文件夹下

这些方案都可以,重要的是养成一个习惯,不要到处乱丢就好。假设我们选择放在 /usr/local/lib 文件夹下,于是我们可以输入:

1
2
Sublime Text 2$ cd ..
Downloads$ mv Sublime\ Text\ 2 /usr/local/lib/
  • 为什么在运行的时候要在前面加上 ./ 呢?

在 Linux 系统下,有一个环境变量叫做 $PATH ,系统在其中保存了一些可执行的二进制文件所存放的路径,因此我们可以在任何地方运行这些命令而不需要指定它们的绝对路径。

你可以在任何情况下输入下面的命令来查看当前系统的 $PATH 环境变量:

1
$ echo $PATH

在之前的例子中,`~/Downloads/Sublime Text 2/` 文件夹并不在 $PATH 环境变量之中,所以即使处于这个路径之下,也无法直接执行 sublime_text 这个命令,所以我们须要加一个 ./ (等同于当前目录)才可以。

可是这么一来岂不是很麻烦?难道每安装一个应用程序,就得把它所处的文件夹路径添加到 $PATH 变量中去才能运行它吗?当然不是的。

象 ls cd pwd 这样的命令,我们随时随地都可以运行,这是因为它们被统一存放在 /bin/ 或 /sbin/ 文件夹下,这些文件夹默认就在 $PATH 环境变量之中。同样的,`/usr/bin/` 和 usr/sbin/ 也是如此。不过我们没有把 Sublime Text 2 的所有文件都放在这些文件夹下,这是因为它们不全是可执行的二进制文件。我们可以这么做:

1
$ ln -s /usr/local/lib/Sublime\ Text\ 2/sublime_text /usr/bin/subl

这条命令的意思就是给可执行的 sublime_text 文件创建了一个叫做 subl 的连接(类似 Windows 下的快捷方式,只不过是运行在命令行下的),并且把它保存在 /usr/bin/ 文件夹下。于是,我们就可以通过输入 subl 来运行 Sublime Text 2 了。

简化

通过上述操作,我们就安装好了 Linux 版本的 Sublime Text 2,不过相比 Windows 或 Mac OS X 而言,这还是太麻烦了。是否可以创建一个图形化的快捷方式以便我们在 Ubuntu 的 Dash 或 Launch Bar 里运行它呢?

当然也是可以的啦!首先让我们进入一个文件夹:

1
$ cd /usr/share/applications/

在这里我们用 Sublime Text 2 创建一个文件:

1
$ subl sublime.desktop

.desktop 后缀的文件,就像是图形界面下的快捷方式,可以通过 Dash 搜索或运行它,也可以把它锁定在 Launch Bar 上。这个文件里需要输入的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Desktop Entry]
Version=1.0
Name=Sublime Text 2
GenericName=Text Editor

Exec=subl
Terminal=false
Icon=/usr/local/lib/Sublime Text 2/Icon/48x48/sublime_text.png
Type=Application
Categories=TextEditor;IDE;Development
X-Ayatana-Desktop-Shortcuts=NewWindow

[NewWindow Shortcut Group]
Name=New Window
Exec=subl -n
TargetEnvironment=Unity

注意: 第7行所指定的路径将决定快捷方式能否正确显示图标,请不要输错;第5行和第13行里的 subl 就是之前创建的那个连接,如果你创建的连接名字不一样,别忘了改正确。

用PIL写缩略图程序的时候出了点错误,提示JPEG support not available,应该是没有把jpeg编译到pil里面。然后去重新检查了一下,发现png和freetype也没弄进去。一并全搞了,在此记录一下安装方法。

由于我的系统是ubuntu的,所以就直接用apt-get安装了。

1
apt-get install libjpeg62 libjpeg62-dev libfreetype6 libfreetype6-dev zlib1g zlib1g-dev python-dev  libzip-dev libzip1

然后要对库的路径做一下软链接,否则PIL安装的时候将找不到库。

1
2
3
ln -s /usr/lib/i386-linux-gnu/libjpeg.so /usr/lib/
ln -s /usr/lib/i386-linux-gnu/libz.so /usr/lib/
ln -s /usr/lib/i386-linux-gnu/libfreetype.so /usr/lib/

然后再用pip或着easy_install又或着直接源码安装就可以了。注意安装后如果看到下面的信息才算成功:

--- JPEG support available
--- ZLIB (PNG/ZIP) support available
--- FREETYPE2 support available