最近工作有点多,趁周末有空,继续分享我在学习和使用python过程中的一些小tips。

有没有遇到过这样的事情:对数据库执行插入或更新操作,因为数据量大或其他原因,导致此次操作非常耗时,有时甚至等上好几个小时,也无法完成。很郁闷,怎么操作不超时啊?因为数据库配置时超时时间很长,并且有些操作又是需要很长时间的,所以不能修改默认的超时时间。

因为客观条件不允许,我们不能靠数据库超时来终止此次操作,所以必须要在自己的方法逻辑模块里实现超时检测的功能。

在python里有没有可以不用修改原来的方法内部逻辑,就能实现超时检测呢?肯定有啦,就是利用装饰器。装饰器是什么?在博客园找到了一篇介绍文章:函数和方法装饰漫谈(Function decorator)

废话听完,我现在介绍主角出场:超时装饰器,timeout decorator。

超时检测逻辑:启动新子线程执行指定的方法,主线程等待子线程的运行结果,若在指定时间内子线程还未执行完毕,则判断为超时,抛出超时异常,并杀掉子线程;否则未超时,返回子线程所执行的方法的返回值。

在实现过程中,发现python默认模块里是没有方法可以杀掉线程的,怎么办呢?当然先问问google或百度,果然,keill thread这个关键词很热门,很快就搜索到我想要的东西了:"Kill a thread in Python",就是以下这个KThread类,它继承了threading.Thread,并添加了kill方法,让我们能杀掉它:

 

import sys


class KThread(threading.Thread):
    
"""A subclass of threading.Thread, with a kill()
    method.
    
    Come from:
    Kill a thread in Python: 
    http://mail.python.org/pipermail/python-list/2004-May/260937.html
    
"""
    
def __init__(self, *args, **kwargs):
        threading.Thread.
__init__(self, *args, **kwargs)
        self.killed 
= False

    
def start(self):
        
"""Start the thread."""
        self.
__run_backup = self.run
        self.run 
= self.__run      # Force the Thread to install our trace.
        threading.Thread.start(self)

    
def __run(self):
        
"""Hacked run function, which installs the
        trace.
"""
        sys.settrace(self.globaltrace)
        self.
__run_backup()
        self.run 
= self.__run_backup

    
def globaltrace(self, frame, why, arg):
        
if why == 'call':
          
return self.localtrace
        
else:
          
return None

    
def localtrace(self, frame, why, arg):
        
if self.killed:
          
if why == 'line':
            
raise SystemExit()
        
return self.localtrace

    
def kill(self):
        self.killed 
= True


好了,万事戒备,让我们来完成剩下的代码吧,也就是timeout decorator:

class Timeout(Exception):
    
"""function run timeout"""
    
def timeout(seconds):
    
"""超时装饰器,指定超时时间
    若被装饰的方法在指定的时间内未返回,则抛出Timeout异常
"""
    
def timeout_decorator(func):
        
"""真正的装饰器"""
        
        
def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
            result.append(oldfunc(
*oldfunc_args, **oldfunc_kwargs))
        
        
def _(*args, **kwargs):
            result 
= []
            new_kwargs 
= { # create new args for _new_func, because we want to get the func return val to result list
                'oldfunc': func,
                
'result': result,
                
'oldfunc_args': args,
                
'oldfunc_kwargs': kwargs
            }
            thd 
= KThread(target=_new_func, args=(), kwargs=new_kwargs)
            thd.start()
            thd.join(seconds)
            alive 
= thd.isAlive()
            thd.kill() 
# kill the child thread
            if alive:
                
raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
            
else:
                
return result[0]
        _.
__name__ = func.__name__
        _.
__doc__ = func.__doc__
        
return _
    
return timeout_decorator

 

真的能运行吗?写个测试程序运行运行:

@timeout(5)
def method_timeout(seconds, text):
    
print 'start', seconds, text
    time.sleep(seconds)
    
print 'finish', seconds, text
    
return seconds

if __name__ == '__main__':
    
for sec in range(110):
        
try:
            
print '*' * 20
            
print method_timeout(sec, 'test waiting %d seconds' % sec)
        
except Timeout, e:
            
print e

 

看,真的行:

 

 

本次的tips可能有点复杂,运用到多线程,装饰器等,希望它对你有所帮助。

PS:山顶风光果然一流,独缺美女相伴!!!

posted @ 2008-08-30 22:29 MK2 阅读(818) | 评论 (3)编辑
对于我这个从.NET过来的人,对python的str和unicode会感到非常不适应。经常在一些常用的地方遇到编码异常问题。如保存字符串到文本中,是要先编码还是直接保存呢?字符串是str还是unicode呢?保存字符串到数据库是直接保存str又或是先将unicode编码得到的str呢?
好多个问号,这都是我个python初学者碰到的问题。在尝试多次痛苦后,总算有了一些思路。原来unicode早已在python实现的很好,只是我使用不当罢了。

一个很关键的并且要常记住的,就是代码中所有字符串都统一使用unicode,而不是str。这样,自己就能很清楚要处理的字符串类型了。请记住,是所有,任何地方。
例如:
>>> s1 = u'%s欢迎您!' % u'北京'
>>> s1
u'\u5317\u4eac\u6b22\u8fce\u60a8\uff01'
>>> print s1
北京欢迎你!

若像这样,就会抛异常:
>>> s2 = '%s欢迎您!' % u'北京'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 2: ordinal not in range(128)
由UnicodeDecodeError可猜想得到,解析器尝试使用ascii对'%s欢迎您!'进行解码,由于'%s欢迎您!'实际是使用utf-8编码的(这是我系统终端默认的),所以使用ascii解码肯定会错,只要如下,就可以重现这个异常了:
>>> s2 = '%s欢迎您!'.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 2: ordinal not in range(128)

分清encode和decode。str --> decode(c) --> unicode, unicode --> encode(c) --> str,其中编码类型c必须相同。

将unicode字符串写入文件前先使用特定编码对其进行编码(如unicodestr.encode('utf-8'))得到str,保证写入文件的是str;从文件读取到str,然后对其进行解码(如encodestr.decode('utf-8'))得到unicode。
这是互逆的两个操作,编码类型一定要一致,否则会出现异常。

自己支持了unicode,但是你团队的其他人是否都使用unicode呢?你使用的其他模块是否也使用unicode呢?这个一定要清楚的,不然同样会出现许多因为编码问题的异常。

好了,晚了,随便写了点,大家晚安,2008.8.1,本世纪的第一次日全蚀,你要看吗?

Technorati 标签: , ,
posted @ 2008-08-01 01:15 MK2 阅读(65) | 评论 (0)编辑

最近都在研究如何利用最少的字节判断两个PE文件是否相同。

PE文件几个关键:

1. 在一个PE文件的开始处,我们会看到一个MS-DOS可执行体(英语叫“stub”,意为“根,存根”);它使任何PE文件都是一个有效的MS-DOS可执行文件。如图蓝色框部分。0x5A4D:MZ,每个PE文件都是以此开始。

image

 

2. 在DOS-根之后是一个32位的签名以及魔数0x00004550 (IMAGE_NT_SIGNATURE)(意为“NT签名”,也就是PE签名;十六进制数45和50分别代表ASCII码字母E和P)。

image

3.

image

 

4. DOS-根和签名(DOS-stub and Signature)

image

你可以通过确认DOS-头部分是否为一个IMAGE_DOS_HEADER(DOS头)结构来认出DOS-根,它的前两个字节必须为连续的两个字母“MZ”(有一个#define IMAGE_DOS_SIGNATURE的定义是针对这个WORD单元的)。

DOS-根的概念很早从16位windows的可执行文件(当时是“NE”格式),现在是PE。

可以通过跟在后面的签名来将一个PE二进制文件和其它含有根的二进制文件区分开来,跟在后面的签名可由头成员'e_lfanew'(它是从字节偏移地址 60(0x3C)处开始的,有32字节长)所设定的偏移地址找到。对于OS/2系统和Windows系统的二进制文件来说,签名是一个16位的word单元;对于PE 文件来说,它是一个按照8位字节边界对齐的32位的longword单元,并且IMAGE_NT_SIGNATURE(NT签名)的值已由#defined定义为0x00004550(即字母“PE/0/0”)。

即:判断一个文件是否PE:1)判断开始两字节是否 0x5A4D;2)根据0x3C~3F的得到偏移地址,然后根据偏移地址获得签名,判断该签名是否属于PE即可。

 

5. 文件头

image 

开始于0x00E4,有0x14字节长,到0xF8:
    Machine                              4c 01       ; i386
    NumberOfSections              03 00       ; 代码段和数据段
    TimeDateStamp                  20 84 7D 3B ; 
    PointerToSymbolTable        00 00 00 00 ; 未用
    NumberOfSymbols               00 00 00 00 ; 未用
    SizeOfOptionalHeader         e0 00       ; 常量
    Characteristics                    0F 01(0000 0001 0000 1111B)       ; 32位机器上的可执行文件

 

成员“Characteristics(特性)”是一个16位的,由许多标志位形成的集合组成,但大多数标志位只对目标文件和库文件有效。具体如下:
    位0 IMAGE_FILE_RELOCS_STRIPPED(重定位被剥离文件) 表示如果文件中没有重定位信息,该位置1,这就表明各节的重定位信息都在它们各自的节中;可执行文件不使用该位,它们的重定位信息放在下面将要描述的“base relocation”(基址重定位)目录中。
    位1 IMAGE_FILE_EXECUTABLE_IMAGE(可执行映象文件) 表示如果文件是一个可执行文件,也即不是目标文件或者库文件时,置1。如果链接器尝试创建一个可执行文件,却因为一些原因失败了,并保存映像以便下次例如增量链接时使用,此时此标志位也可能置1。
    位2 IMAGE_FILE_LINE_NUMS_STRIPPED(行数被剥离文件) 表示如果行数信息被剥除,此位置1;此位也不用于可执行文件。
    位3 IMAGE_FILE_LOCAL_SYMS_STRIPPED(本地符号被剥离文件) 表示如果文件中没有关于本地符号的信息时,此位置1(此位也不用于可执行文件)。
    位4 IMAGE_FILE_AGGRESIVE_WS_TRIM(强行工作集修剪文件) 表示如果操作系统被假定为:通过将正在运行的进程(它所使用的内存数量)强行的页清除来修剪它的工作集时,此位置1。如果一进程是大部分时间处于等待,且一天中仅被唤醒一次的演示性的应用程序之类时,此位也应该被置1。
    位7 IMAGE_FILE_BYTES_REVERSED_LO(低字节变换文件)和 位 15IMAGE_FILE_BYTES_REVERSED_HI(高字节变换文件) 表示如果一文件的字节序不是机器所预期的形式,因此它在读入前必须调换字节时,此位置1。这样做对可执行文件是不可靠的(操作系统期望可执行文件都已经被正确地按字节排整齐了)。
    位8 IMAGE_FILE_32BIT_MACHINE(32位机器文件) 表示如果使用的机器被期望为32位的机器时,此位置1。现在的应用程序总将此位置1;NT5系统可能工作不同。
    位9 IMAGE_FILE_DEBUG_STRIPPED(调试信息被剥离文件) 表示如果文件中没有调试信息,此位置1。此位可执行文件不用。按照其它信息([6])(这里指的是参考书目中的第[6]种----译者注),此位被称作“恒定”,并且当一个映象文件只有在被装入优先的装入地址才能运行(亦即:此文件不可重定位)时,此位置1。
    位10 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP(移动介质文件从交换文件运行) 表示如果一个应用程序不可以从可移动的介质,如软盘或CD-ROM上运行时,此位置1。在这种情况下,建议操作系统将文件复制到交换文件并从那里执行。
    位11 IMAGE_FILE_NET_RUN_FROM_SWAP(网络文件从交换文件运行) 表示如果一个应用程序不可以从网络上运行时,此位置1。在这种情况下,建议操作系统将文件复制到交换文件并从那里执行。
    位12 IMAGE_FILE_SYSTEM(系统文件) 表示如果文件是一个象驱动程序那样的系统文件,此位置1。此位可执行文件不用;我所见过的所有NT系统的驱动程序也不用。
    位13 IMAGE_FILE_DLL(DLL文件) 表示如果文件是一个DLL文件时,此位置1。
    位14 IMAGE_FILE_UP_SYSTEM_ONLY(仅但处理器系统的文件) 表示如果文件不设计运行在多处理器系统上(也就是说,因为此文件严格地依赖单一处理器的一些方式工作,所以它会发生冲突)时,此位置1。

在看来一个DLL的文件头

image

Characteristics                    0E 21(0010 0001 0000 1110B 高-低)       ; 32位机器上的DLL文件

 

参考:

http://bbs.pediy.com/showthread.php?threadid=21932

posted @ 2008-06-23 19:32 MK2 阅读(60) | 评论 (0)编辑
A呵呵,一直都是用WLW写blog的,很久之前就装了Scribefire,一直都没用,今天来个测试,呵呵,如果满意,以后就用它了。



直接帖截图测试:



edit





上传图片测试:OK





测试其他吧哈哈乱来。

©®°±¶º¿¿¾


呵呵,看来真的可以取代WLW



Technorati Tags: , ,
posted @ 2008-06-10 19:23 MK2 阅读(66) | 评论 (0)编辑

因经常在多台机器上使用Firefox,难免会想装一些已经习惯了的插件(晕,都依赖他们),没安装上总是用起来不顺手。于是就有了这篇文章。

1. 第一个要备忘的肯定是它:Google Browser Sync

image

可以同步些什么?看看这个截图吧:

image

很Cool吧,仿佛在那台机打开FF,都感觉是一样的,完全获取回上次的所有状态,并且支持加密传输,这样个人私隐就不会泄露了。

2. GMarks

虽然说Google Browser Sync可以同步Bookmarks,但是我还是喜欢将Bookmarks保存到互联网上,GMarks就是一个Google Bookmarks的插件,使用也非常简单,Bookmarks太多了吧,不記得放在那个位置了吧,呵呵,不怕,在自己的Bookmarks上搜索一下不就行了?

image

3. All-in-One Gestures Extension

有使用鼠标手势控制的习惯吧?怕使用了Firefox而无法拥有这个功能吗?呵呵,哪All-in-One Gestures Extension肯定是你的最爱,完全支持你想要的手势。

image

image

4. DictCN (呵呵,忘记推荐沪江小D,绝对比这个精彩多了!!!)

呵呵,像我这些英语很差但是又要经常看英文的人,这个插件肯定比钱包更加重要,放在你的FF上吧,肯定会用上的,特别是它还支持发音功能。

image image

5. AutoHide

觉得FF上方的工具栏太占位置了吗?导致看到的页面太小了吧?呵呵,这个插件绝对帮你将工具栏完全隐藏了,按Shift+F11让FF全屏吧。

image

6. Firebug 不顶不行

呵呵,这个不用我介绍了吧,太出名了!!!

image

估计每个做Web开发的人的FF上都会有它。o(∩_∩)o...

7. Showcase

经常打开几十个tab而又不想关掉它们吗?是不是要找一个tab花了很多时间?使用Showcase可以让你马上找到你想找的tab,不信?看看截图吧:

image

想用了吧?

8. IE Tab

不用IE不行啊,有时候真的没有了IE,很多事情就没法做了,于是有打开IE。很麻烦吧,如果你的系统是Windows,那么IE Tab可以很方便地设置当前页面使用IE内核访问,还可以设置更多的规则,唉,我们的世界没了IE真不容易:

image

9. Fireshot

一个页面太长了吧,是否有想将整个页面截图处理的需求呢?Fireshot可以实现,并且还有上传,直接将截图的链接发给你的朋友吧,呵呵,这样介绍网站,也是一个不错的选择。

image

image

10. Tab Scope

想预览一下tab里面是什么内容吗?看看它是不是已经加载完了?这个插件可以提高你的兴趣。

image

11. QuickDrag

可以直接拖拉页面上的链接,并在新tab中打开,不用点鼠标中键了,Cool啊!!

12. ColorZilla

可以获取页面上任意部位的颜色。

image

??. FEBE

好了,装了这么多插件,有备份这些插件的插件吗?呵呵,你都想备份了吧?用FEBE吧,你想怎样备份都可以。

image

image

这里可以查看更多截图:http://customsoftwareconsult.com/extensions/febe/febe50/FEBE5.0.html

 

呵呵,今天到此为止吧,以后用到更多好的插件我会继续补充的,:-)

 

希望对你有用!!

 

Technorati 标签: ,,,
posted @ 2008-06-09 10:49 MK2 阅读(251) | 评论 (2)编辑

在没有使用AjaxForm前,我做的一个小小的评论提交的Web form,评论内容使用了TinyMCE做文本编辑。为了增加一点点的用户体验,就顺手拿AjaxForm来实现Ajax提交。可是发现出现了一个意外的事情。就是每次提交,第一次提交时,AjaxForm会无法获得当前编辑的评论内容,即TextArea里面的内容,要再点击一次提交,才能将TextArea的内容提交上去。

关键是TinyMCE上的内容没有在提交前更新到TextArea中。于是想看看AjaxForm是否有在提交前的事件绑定,发现在beforeSubmit事件中,formData的内容已经被填充,虽然可以在此处自行将当前的TinyMCE的内容填充上去(详细可查看这里),可是总觉得是不太漂亮的解决方案。

为了找是否有其它途径解决此问题,我查看了一下AjaxForm的源代码,发现原来AjaxForm作者已经为这问题提出了统一的解决方案,具体源代码如下:

    // hook for manipulating the form data before it is extracted;
    // convenient for use with rich editors like tinyMCE or FCKEditor
    var veto = {};
    this.trigger('form-pre-serialize', [this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
        return this;
   }

果然,真的有对应的事件让我们可以在formData被序列号前将TinyMCE的数据更新到TextArea中。只要我们绑定form的form-pre-serialize事件即可。

于是一个我的代码就这样出来了:(对应FCKEditor类似)

    // bind form using 'ajaxForm' 
    $('#commentForm').ajaxForm(options);
    // 绑定form-pre-serialize事件,在触发form-serilaize事件前保存tinyMCE的数据到textarea中
    $('#commentForm').bind('form-pre-serialize', function(event, form, options, veto) {
	tinyMCE.triggerSave();
    });
 
^_^ 希望对你有用...

Technorati: , , ,

 
posted @ 2008-06-08 20:38 MK2 阅读(261) | 评论 (2)编辑

最近在收集PE的FileInfo信息,发现不是每个PE都会有,而且有也不一定全部都有,总结了样本,基本上包含一下信息:

LegalCopyright :版权信息

InternalName: 内部名称

FileVersion:文件版本

CompanyName:公司名称

LegalTrademarks:注册商标

Comments:注释

ProductName:产品名称

ProductVersion:产品版本

FileDescription:文件描述

OriginalFilename:原始文件名

PrivateBuild:私有编译 (见样本3)

SpecialBuild:特殊编译

 

几个特殊的信息:

BuildDate:  编译日期 (见样本1)

BuildNumber: 编译号(见样本1)

FileType: 文件类型 (本应该出现在VS_FIXEDFILEINFO中的,却又出现在FileInfo中,造成冲突,以VS_FIXEDFILEINFO中的为准)(见样本1)

OLESelfRegister:  (见样本2)

文件的分析信息列表:

样本1:http://www.cnblogs.com/Files/fengmk2/35d417aa12d58edfc4ed0156e8ee855f.Nap.txt

样本2:http://www.cnblogs.com/Files/fengmk2/OLESelfRegister_QQ.exe.txt

样本3:http://www.cnblogs.com/Files/fengmk2/PrivateBuild_8c26cc7d912ab9568b44a62291f7ac51.dll.txt

Technorati: ,

posted @ 2008-06-06 10:40 MK2 阅读(41) | 评论 (0)编辑

在threading module中,有一个非常特别的类local。一旦在主线程实例化了一个local,它会一直活在主线程中,并且又主线程启动的子线程调用这个local实例时,它的值将会保存在相应的子线程的字典中。

我们先看看测试代码:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Description: test the threading.local class
# Create: 2008-6-4
# Author: MK2[fengmk2@gmail.com]
from threading import local, enumerate, Thread, currentThread

local_data = local()
local_data.name = 'local_data'

class TestThread(Thread):
        def run(self):
                print currentThread()
                print local_data.__dict__
                local_data.name = self.getName()
                local_data.add_by_sub_thread = self.getName()
                print local_data.__dict__

if __name__ == '__main__':
        print currentThread()
        print local_data.__dict__
        
        t1 = TestThread()
        t1.start()
        t1.join()
        
        t2 = TestThread()
        t2.start()
        t2.join()
        
        print currentThread()
        print local_data.__dict__
运行结果:

<_MainThread(MainThread, started)>
{'name': 'local_data'}
<TestThread(Thread-1, started)>
{}
{'add_by_sub_thread': 'Thread-1', 'name': 'Thread-1'}
<TestThread(Thread-2, started)>
{}
{'add_by_sub_thread': 'Thread-2', 'name': 'Thread-2'}
<_MainThread(MainThread, started)>
{'name': 'local_data'}

 

主线程中的local_data并没有被改变,而子线程中的local_data各自都不相同。

怎么这么神奇?local_data具有全局访问权,主线程,子线程都能访问它,但是它的值却是各当前线程有关,究竟什么奥秘在这里呢?

查看了一下local的源代码,发现就神奇在_path()方法中:

def _patch(self):
    key = object.__getattribute__(self, '_local__key')
    d = currentThread().__dict__.get(key)
    if d is None:
        d = {}
        currentThread().__dict__[key] = d
        object.__setattr__(self, '__dict__', d)

        # we have a new instance dict, so call out __init__ if we have
        # one
        cls = type(self)
        if cls.__init__ is not object.__init__:
            args, kw = object.__getattribute__(self, '_local__args')
            cls.__init__(self, *args, **kw)
    else:
        object.__setattr__(self, '__dict__', d)
 

每次调用local实例的属性前,local都会调用这个方法,找到它保存值的地方.

d = currentThread().__dict__.get(key)  就是这个地方,确定了local_data值的保存位置。所以子线程访问local_data时,并不是获取主线程的local_data的值,在子线程第一次访问它是,它是一个空白的字典对象,所以local_data.__dict__为 {},就像我们的输出结果一样。

如果想在当前线程保存一个全局值,并且各自线程互不干扰,使用local类吧。

 

Technorati: , , ,

posted @ 2008-06-04 22:46 MK2 阅读(94) | 评论 (0)编辑

先来看看我们之前是怎样获取到当前登录user的:在view中,我们常常就会通过request对象来获取当前用户user的引用:

def comment_add(request):
    # do something...
    user = request.user
    # to do .....

 

这样,确实很方便就能获取多用户的信息。可是,如果要做别的地方获取user呢?例如要在model中获取user呢?

class Post(models.Model):
    title = models.CharField('Post标题', maxlength=100, db_index=True)
    create_date = models.DateTimeField('发布时间', default=datetime.now(), editable=False)
    modified_date = models.DateTimeField('最后修改时间', default=datetime.now(), editable=False)
    author = models.ForeignKey(User, verbose_name="作者", editable=False)
    content = models.TextField('内容')
    last_visitor_IP = models.IPAddressField('最后的访问者IP', null=True, blank=True, editable=False)
    tags = models.ManyToManyField(Tag, verbose_name="the list of tags", null=True, blank=True)
    slug = models.SlugField('自定义url', maxlength=100, null=True, blank=True)
    hits = models.IntegerField('点击数', editable=False, default=0)


可以看到,author是editable=False的,即我们想Post被保存是自动设置author为当前登录用户user。而这里没有request,怎样获取到这个user呢?找了一下django的文章,提到了使用middleware来解决这个需求。

好吧,先在项目中创建一个"middleware"模块(即带有一个空__init__.py文件的目录),接着创建"threadlocals.py"到此目录,代码如下:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Description: thread locals middleware
# Create: 2008-6-4
try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()
def get_current_user():
    return getattr(_thread_locals, 'user', None)

class ThreadLocals(object):
    """Middleware that gets various objects from the
    request object and saves them in thread local storage."""
    def process_request(self, request):
        _thread_locals.user = getattr(request, 'user', None)

接着将此middleware添加到项目中,打开setting.py,修改代码如下:

MIDDLEWARE_CLASSES = (
    "django.middleware.common.CommonMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "yourproject.middleware.threadlocals.ThreadLocals", 
)
写到这里,发现这不类似与asp.net中的HttpModule吗?

然后为了自动设置author为当前用户,我们需要重载post的save方法:

先导入middleware

from net4.middleware import threadlocals
def save(self):
    if self.id is None:
        self.author = threadlocals.get_current_user()
    super(Post, self).save()

编码工作完成了,还不快点进入admin看看是否可以正常工作了呢?

 

其实大部分都是算直接在参考文章里哪过来的,呵呵,反正是花了点时间才找到,呵呵,就拿来主义,让大家一齐分享咯。

 

希望对你有用! ^_^


本文参考:
Making User info available outside requests

posted @ 2008-06-04 16:52 MK2 阅读(106) | 评论 (2)编辑

今天在群聊的时候,有同学发了最新版Google拼音的功能介绍,其中英文提示:打英文时只需输入前几个字母,输入法自动提示您可能要找的单字。

就是这个功能,我联想到了每天都要做的事情:编程。第一个浮现在脑海里的是VS里的智能感知,于是打开很久没打开的VS2008来回味。

image

然后我在想,输入法能做到这样吗?为了看看英文提示的效果,我下载了google拼音输入法。

输入我们最喜欢的hello world.

image image

果然是有提示。然后我输入一个python的open方法image ,在此刻,我想到的是如果image 的正下方有open的api文档说明和使用示例该多好啊。就像VS2008的智能感知的截图一样。

让智能感知脱离IDE而存在,让我们这些程序员能在文本文档下编程也有智能感知的功能,只需要我们的输入法支持就可以了。

于是编程输入法的设想就这样出现,至于谁先去实现?我想谁都可以。

再看看Eclipse的智能感知:

image

同样的效果,不过条件都是需要装IDE。

相信不久的将来,我们肯定会用上这个输入法的。

 

 

Technorati 标签: ,,,
posted @ 2008-05-31 14:31 MK2 阅读(53) | 评论 (1)编辑

昨天在保存一些中文字符到文本文档时,发现一个很奇怪的现象。先看看代码:

#coding=utf-8
import os

def write_use_open(filepath):
    try:
        file = open(filepath, 'wb')
        try:
            content = '中华人民共和国abcd \r\nee ?!>??@@@!!!!!???¥@#%@%#xx学校ada\r\n'
            print file.encoding
            print file.newlines
            print file.mode
            print file.closed
            print content
            file.write(content)
        finally:
            file.close()
            print file.closed
    except IOError, e:
        print e
    

if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), 'file.txt')
    write_use_open(filepath)
 
开始我是IDLE编写的,并直接按F5运行,没发现问题,文件也被正确地保存,文件的编码类型也是utf-8.
image 
image
可是我用命令行运行,却发现显示出现乱码了,然后在打开文件发现文件被正确保存了,编码还是utf-8:
image 
我想问题是命令行不能自动识别字符编码吧,因为IDLE显示是正确的,它支持utf-8。
 
于是我修改了代码,在字符串前加了'u',表明content是unicode:

content = u'中华人民共和国abcd \r\nee ?!>??@@@!!!!!???¥@#%@%#xx学校ada\r\n'

可是运行发现,命令行是正确显示了,但是却出现异常:

image

很明显,content里包含了非ASCII码字符,肯定不能使用ASCII来进行编码的,write方法是默认使用ascii来编码保存的。

很容易就可以想到,在保存之前,先对unicode字符进行编码,我选择utf-8

#coding=utf-8
import os

def write_use_open(filepath):
    try:
        file = open(filepath, 'wb')
        try:
            content = u'中华人民共和国abcd \r\nee ?!>??@@@!!!!!???¥@#%@%#xx学校ada\r\n'
            print file.encoding
            print file.newlines
            print file.mode
            print file.closed
            print content
            print unicode.encode(content, 'utf-8')
            file.write(unicode.encode(content, 'utf-8'))
        finally:
            file.close()
            print file.closed
    except IOError, e:
        print e
    
if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), 'file.txt')
    write_use_open(filepath)
 
看看运行结果:
image 
OK了打开文档也是正确的。
读取文件又怎样?同样道理,只是这次不是编码了,而解码:
def read_use_open(filepath):
    try:
        file = open(filepath, 'rb')
        try:
            content = file.read()
            content_decode = unicode(content, 'utf-8')
            print 'original text'
            print content
            print 'decode using utf-8'
            print content_decode
        finally:
            file.close()
    except IOError, e:
        print e
    
if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), 'file.txt')
    write_use_open(filepath)
    print 'read file ---------------------------'
    read_use_open(filepath)

image

为什么不直接在open的时候就解码呢?呵呵,可以啊,可以使用codecs的open方法

import codecs
def read_use_codecs_open(filepath):
    try:
        file = codecs.open(filepath, 'rb', 'utf-8')
        try:
            print 'using codecs.open'
            content = file.read()
            print content
        finally:
            file.close()
    except IOError, e:
        print e
image 
 
好了,希望对你有用。
 
本文参考:Unicode HOWTO
Technorati 标签: ,,,,,
posted @ 2008-05-31 13:36 MK2 阅读(173) | 评论 (0)编辑

先来看个例子:

def foo(*args, **kwargs):
    print 'args = ', args
    print 'kwargs = ', kwargs
    print '---------------------------------------'

if __name__ == '__main__':
    foo(1,2,3,4)
    foo(a=1,b=2,c=3)
    foo(1,2,3,4, a=1,b=2,c=3)
    foo('a', 1, None, a=1, b='2', c=3)
输出结果如下:

args =  (1, 2, 3, 4)
kwargs =  {}
---------------------------------------
args =  ()
kwargs =  {'a': 1, 'c': 3, 'b': 2}
---------------------------------------
args =  (1, 2, 3, 4)
kwargs =  {'a': 1, 'c': 3, 'b': 2}
---------------------------------------
args =  ('a', 1, None)
kwargs =  {'a': 1, 'c': 3, 'b': '2'}
---------------------------------------

可以看到,这两个是python中的可变参数。*args表示任何多个无名参数,它是一个tuple;**kwargs表示关键字参数,它是一个dict。并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前,像foo(a=1, b='2', c=3, a', 1, None, )这样调用的话,会提示语法错误“SyntaxError: non-keyword arg after keyword arg”。

 

呵呵,知道*args和**kwargs是什么了吧。还有一个很漂亮的用法,就是创建字典:

    def kw_dict(**kwargs):
        return kwargs
    print kw_dict(a=1,b=2,c=3) == {'a':1, 'b':2, 'c':3}

其实python中就带有dict类,使用dict(a=1,b=2,c=3)即可创建一个字典了。

 

“人生苦短,我用python。”

Technorati 标签: ,,,,
posted @ 2008-04-21 13:34 MK2 阅读(150) | 评论 (0)编辑

今天在测试读取RSS时,使用到自己在博客园的RSS链接来做测试,发现使用Last-Modified方式优化时,RSS每次返回都会更新Last-Modified。

以下是用Fiddler对几次请求的截获结果:

第一次请求,客户端不会添加头If-Modified-Since头,这是肯定的。

image

服务器端返回了Last-Modified,并且响应代码是200,这样客户端可以在下次请求中使用。

 

第二次请求,客户端根据上次请求返回的Last-Modified,添加If-Modified-Since头。

image

服务器返回结果并不是我们预料中的304,却依然是200,也就是说全部内容又重新下载了一遍,If-Modified-Since请求头并未起作用。原因是什么?看看服务器返回的Last-Modified就知道,RSS内容并未更新,长度还是67672,本应该Last-Modified与第一次的Last-Modified相等才对的。

 

再进行一次测试:

image

结果和上面一样,Last-Modified有变化了。

 

呵呵,Last-Modified得到支持,将会为我们双方都节省许多带宽的。与Last-Modified类似的,就是Etag头。想详细了解什么是Last-Modified和Etag,可参考:如何利用客户端缓存对网站进行优化?

Technorati 标签: ,,,,
posted @ 2008-04-19 16:10 MK2 阅读(1547) | 评论 (7)编辑

究竟在一次Request中,Django对数据库执行了那些查询和操作呢?呵呵,Django早就为我们想好了这个问题,使用django.core.context_processors.debug模块即可。

在setting中设置:

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.debug", #debug 一次请求调用到多少SQL语句",
)

并设置能看到次debug信息的请求IP:

INTERNAL_IPS = ('127.0.0.1',)

我们就可以在模板中设置一下,即可:

{% endblock %}
{% if sql_queries %}
<h3>SQL excute in this Request</h3>
<!-- debug: show the sql excute in this request -->
{% for query in sql_queries %}<h3>Excute times: {{query.time}}</h3>
<p>
<code>
{{query.sql}}
</code>
</p>
{% endfor %}<!-- debug ends here -->
{% endif %}
以上只会在你设置了TEMPLATE_DEBUG = DEBUG,和请求IP在INTERNAL_IPS设置过,才会显示。
看看一个截图吧:
image 
呵呵,看到了对Session的查询。
不错吧,这样我们可以对实际执行的SQL有底了。
Technorati 标签: ,,,,,
posted @ 2008-04-18 21:38 MK2 阅读(123) | 评论 (4)编辑

1. 创建app

manage.py startapp users

2. 编写profile model

from django.db import models
from django.contrib.auth.models import User

GENDER_CHOICES = (
                  ('M', '男'),
                  ('F', '女'),
                  )

class UserProfile(models.Model):
    # 这个字段是必须的,并且只能为user,且要添加外键关联到User
    user = models.ForeignKey(User, unique=True, verbose_name='用户的额外信息')
    # 以下可以按各自需求来定义
    tel = models.CharField('电话', maxlength=20, blank=True, null=True)
    mobile = models.CharField('移动电话', maxlength=20, blank=True, null=True)
    address = models.CharField('家庭地址', maxlength=100, blank=True, null=True)
    website = models.URLField('个人主页', blank=True, null=True)
    birthday = models.DateField('出生日期', blank=True, null=True)
    gender = models.CharField('性别', maxlength=1, choices=GENDER_CHOICES, radio_admin=True, default='M')
    blog = models.URLField('个人主页', blank=True, null=True)
    QQ = models.CharField('QQ', maxlength=50, blank=True, null=True)
    MSN = models.CharField(maxlength=50, blank=True, null=True)
    IM = models.CharField(maxlength=50, blank=True, null=True)
    position = models.CharField('目前所在地', maxlength=200, blank=True, null=True)
    country = models.CharField('目前所在国家', maxlength=50, blank=True, null=True, default='中国')

3. 设置AUTH_PROFILE_MODULE

AUTH_PROFILE_MODULE = 'users.UserProfile' #不区分大小写的

4. 添加INSTALLED_APPS

INSTALLED_APPS = (

...............
    'web.users',
)

5. 同步数据库

manage.py syncdb

 

只需使用User.get_profile()方法即可返回对应的UserPrfile对象实例了。

posted @ 2008-04-10 17:18 MK2 阅读(90) | 评论 (0)编辑

首先,写Python代码的IDE有许多,呵呵,至于功能强大的肯定是Eclipse + pydev了,以下是pydev的显著的特性:

Some feature-highlights

 

接着,我选择使用Django框架做Web开发的话,怎么能少了对HTML, CSS, JavaScript的编辑器呢?呵呵,同样是Eclipse的插件:Aptana ,强大的智能提示,肯定帮助我们加快开发的速度和提高开发体验的(呵呵,我们也要良好的用户体验喔)。

 

最后不用说,就是SVN,Eclipse的SVN插件:subclipse,这样3样工具,足够了。

 

PS: 还有个可选的,就是UML建模工具:EclipseUML

posted @ 2008-04-10 10:12 MK2 阅读(93) | 评论 (0)编辑

1. syncdb

最简单而又令人兴奋的命令: manage.py syncdb

image

创建了指定app中的model对应的数据库表,如果是第一次使用此命令,会提示是否创建超级用户,输入用户名,Email和密码,接着可以看到在创建索引:

image 

2. validate

验证Model的正确性:manage.py validate,若Model全部有效,会提示:0 errors found.

3. sqlall [appname,....]

打印指定app的CREATE TABLE的语句,包括原始数据,创建索引等.

manage.py sqlall books

将会看到:

image

4. sqlreset [appname, ....]

修改了Model后,如果不需要保留原来的数据,就使用这个命令更新数据库对应的表,因为syncdb不会同步已有的表的。

manage.py sqlreset books

image

如果我们需要保留原来的数据,目前只能手动更改数据表了,可能将来会有类似updatedb的命令,帮助我们生成ALTER TABLE语句的。

Technorati 标签: ,
posted @ 2008-04-09 20:33 MK2 阅读(92) | 评论 (1)编辑

今天看到Lulu的闪存问到Cookie的问题,然后引发更多问题,突然想到昨晚使用Fiddler调试是否使用gzip压缩时,发现IE7下的localhost无法被捕获了。呵呵,然后就直接搜索了“Fiddler localhost”,找到了原因。

以下引用至:http://www.fiddlertool.com/Fiddler/help/knownissues.asp

I don't see IE7 or .NET traffic sent to localhost or 127.0.0.1.

IE7 and the .NET Framework are hardcoded not to send requests for Localhost through proxies.  Fiddler runs as a proxy.  The workaround is to use your machine name as the hostname instead of Localhost or 127.0.0.1.

So, for instance, rather than hitting http://localhost:8081/mytestpage.aspx, instead visit http://machinename:8081/mytestpage.aspx.  Alternatively, you can use http://localhost.:8081/mytestpage.aspx (note the trailing dot after localhost).  Alternatively, you can customize your Rules file like so:

static function OnBeforeRequest(oSession:Fiddler.Session){
  if (oSession.host.ToUpper() == "MYAPP") { oSession.host = "127.0.0.1:8081"; }
}

...and then navigate to http://myapp, which will act as an alias for 127.0.0.1:8081.

我比较喜欢localhost.  方式。

如果你使用IIS7的话,还可以自己定制

<system.net>
  <defaultProxy>
    <proxy  proxyaddress="http://127.0.0.1:8888" />
  </defaultProxy>
</system.net>

这样,就会通过代理来访问了,从而Fiddler就能捕获到数据了。

 

最后还联想到以前DF介绍的一款Fiddler的插件,帮助我们查看被去空白的Javascript代码插件-- Fiddler2 - JavaScript Beautifier Plugin (Fiddler 2的JavaScript代码美化插件)

 

呵呵,有时候想起某些事情是需要有导火线的。

 

Technorati 标签: ,,,
posted @ 2008-03-31 16:25 MK2 阅读(198) | 评论 (1)编辑

1. 验证用户输入;
2. 转化必要的字符,避免脚本攻击;
3. 防止用户估计禁止掉浏览器中的Javascript进行提交。
4. 防止用户恶意频繁输入。
5. 防止广告机器人。

6. asp.net Ajax访问页面静态方法或WebService时,要注意是否需要进行身份验证。

    [WebMethod]
    public static bool DeleteMessage(int id)
    {
        if (!HttpContext.Current.User.Identity.IsAuthenticated)
        {
            throw new System.Security.SecurityException("没有权限.");
        }
        //do something.
    }
7. 禁止用户手动输入input[type="file"]的文件路径,最简单的方式是
<input type="file" ContentEditable="false" />
posted @ 2008-03-28 17:40 MK2 阅读(92) | 评论 (0)编辑
昨天对自己的Blog添加动态更换皮肤功能时,还有一个问题没解决,就是子域名共享Cookie。例如我访问Blog的子域名是:fengmk2.cnblogs.com, 而页面很多链接的是在www.cnblogs.com/fengmk2/下进行访问的,而皮肤的设置保存在cookie中,导致访问两域名时,皮肤显示不同。今天搜索了一下博客园,发现Dudu已经给出了完全的解决方法。
解决方法:"将cookie关联的域设置为".domain.ext", 博客园的设置就是.cnblogs.com。"
我使用jQuerycookie插件,修改相应的操作就解决了。
function switchStylestyle(stylename)
{
    $(
'link[@rel*=style][@title]').each(function(i) 
    
{
        
this.disabled = true
        
if (this.getAttribute('title'== stylename) 
            
this.disabled = false;
        }

    }
);
    $.cookie(
'skinstyle', stylename, {expires: 356, domain: '.cnblogs.com', path: '/'});
}


$(document).ready(
function() {
    
//动态更换皮肤
    $("#navbar").children().append("<li><a class='styleswitch' rel='MainCss' href='#'>原版皮肤</a></li><li><a class='styleswitch' rel='MK2Css' href='#'>当前皮肤</a></li>");
//$("#navbar ul li a").eq(1).attr({href: "/fengmk2/"});
    $('.styleswitch').click(function()