Rainfall’s CodeLife

C/C++/C#/VB/JavaScript/Python/XML

 

Python对象转换REST、Json(下) December 22, 2006

Filed under: Python — Rainfall @ 11:47 pm

★ REST格式

 REST格式采用XML标准,这里我们采用xml.dom.minidom来构建REST数据。这里采用递归函数在父节点下转换当前数据:

def simple2rest(self, instance, pnode, force_child=False):
if isinstance(instance[1], (DictType)):

elif isinstance(instance[1], ListType):

elif instance[0][:-1].lower() == ’s’:

else:

instance是当前数据对象二元组(名称,值),其中pnode是上级数据结构对应的DomNode,force_child是标识强制在父节点下建立,这主要是满足list类型的需要,下面会逐个介绍。

A)字典类型:
建立字典节点,并遍历字典所有数据:

node = pnode.appendChild(pnode.ownerDocument.createElement(instance[0]))
for name in list(instance[1]):
  self.simple2rest((name, instance[1][name]), node)

B)列表类型:

过程和字典类型处理方式类似,但如果一个类中有下列情况:

class mybook:
   chapters[] = …

他对应的REST应该是:

<mybook>
  <chapters>
    <chapter … >…</chapter>
    <chapter … >…</chapter>
    …
  </chapters>
</mybook>

这样就需要根据字段名称生成REST中的集合名和集合项目名:

itemname, itemsname = instance[0], instance[0] + ’s’
if instance[0][-2:].lower() == ‘es’:
  itemname, itemsname = instance[0][:-2], instance[0]
elif instance[0][:-1].lower() == ’s’:
  itemname, itemsname = instance[0][:-1], instance[0]

其他基本和字典一样

C)值类型:

首先对于列表元素数据,将列表内容作为列表集合标签的属性处理,由于tag属性不能重名,因此必须先建立单独的节点:

if force_child:
  pnode = pnode.appendChild(pnode.ownerDocument.createElement(instance[0]))

同一个值可以有两种形式存在,如:

<tag some=”…” value=”…”>或
<tag some=”…”>…</tag>

一个Tag最多只可能有一个作为TextNode内容,因此这里的处理方式是将字段名为“value”的数据处理为textnode。

if force_child or instance[0].lower() == ‘value’:
  pnode.appendChild(pnode.ownerDocument.createTextNode(str(instance[1])))
else:
  pnode.setAttribute(instance[0], str(instance[1])

★ 值类型过滤

在Json中,布尔表示为“true”和“false”,而在REST中通常会表示“1”和“0”,另外枚举的处理也需要转换为字串,比如“read”比“1”要好的多。上面都是默认用Python的str函数转换值类型,为了满足上述要求,必须做针对类型的过滤器:

ins_value = self.fmtfilters.type2str(instance[1])

class ValueFilters:
  trans_filters = None

  def type2str(self, instance):
    if self.trans_filters and self.trans_filters.has_key(type(instance)):
      return self.trans_filters[type(instance)](instance)
  return str(instance)

在简单类型转换过程中,会先查找某个类成员是否有对应的转换函数,如果有则不调用默认的obj2simple:

fmtname = ‘format_’ + name + ‘_field’
if hasattr(instance, fmtname):
  clsdict[name] = getattr(instance, fmtname)()
else:
  clsdict[name] = obj2simple(field)

 
 

Python对象转换REST、Json(上)

Filed under: Python — Rainfall @ 11:42 pm

参考资料:

http://www.json.org/

http://www.peej.co.uk/articles/rest.html

★ 背景

Representational State Transfer(REST)和JavaScript Object Notation(Json)是现在互联网应用的常见数据表示规格。因此在服务器端开发网络应用时,服务端语言与REST和Json之间的互换非常重要,既内核对象存盘为REST/Json格式,以及REST/Json格式读盘重建内核对象。下面先介绍前者。

★ 简化对象数据模型

REST/Json共同的优点就是数据模型简单,其基本数据模型由三种组成:

A)字典:包括类在内,都采用{数据名:数据值},是唯一的数据命名方式

B)数组:作为一个字典的数据值保存同类数据集合

C)简单值:包括布尔,数值,字串等,实际的数据载体

因此将Python的数据类型简化为上述三种方式是存盘的第一步,首先将Python类型分类:

LIST_TYPES = (ListType, TupleType)
COMPLEX_TYPES = (InstanceType)
DICT_TYPES = (DictType)
VALUE_TYPES = (BooleanType, StringType, LongType, IntType, FloatType)

通过递归函数扫描对象数据成员:

def obj2simple(instance):
if isinstance(instance, LIST_TYPES):
  return [obj2simple(o) for o in list(instance)]
elif isinstance(instance, COMPLEX_TYPES):
  return cls2simple(instance)
elif isinstance(instance, DICT_TYPES):
  return dict2simple(instance)
elif isinstance(instance, VALUE_TYPES):
  return instance

dict2simple函数和list2sample一致,只是简单的转换字典数据并重建新字典。稍微麻烦点的就是复杂类类型转换,首先先建立有效类成员列表:

members = [(member, getattr(instance, member)) for member in dir(instance) if not callable(getattr(instance, member)) and not member.startswith(’_')]

这个成员列表将类函数以及以’_'开头的成员(私有)排除,剩下的做法其实就是一个dict2sample过程。

ok,建立一个复杂些的测试案例:

class scls:
def asdf(self):
  pass
arr = [3, 5, 5]
n = 9
b = True
s = ’sfafds’
value = ‘xxxx’

dic = {’a':3, ‘aa’:scls()}

class cls:
def asfl(self):
  pass
i = 2
s = ‘asf’
clsarr = [2, ‘af’, scls(), scls()]
clsdic = {’a':34, ‘aa’:scls(), ‘d’:dic}
t = (4, ’ss’, dic)

转换结果:

{’i': ‘iii2′, ’s’: ‘asf’, ‘clsarr’: [2, ‘af’, {’arr’: [3, 5, 5], ‘b’: True, ’s’: ’sfafds’, ‘value’: ‘xxxx’, ‘n’: 9}, {’arr’: [3, 5, 5], ‘b’: True, ’s’: ’sfafds’, ‘value’: ‘xxxx’, ‘n’: 9}], ‘t’: [4, ’ss’, {’a': 3, ‘aa’: {’arr’: [3, 5, 5], ‘b’: True, ’s’: ’sfafds’, ‘value’: ‘xxxx’, ‘n’: 9}}], ‘clsdic’: {’a': 34, ‘aa’: {’arr’: [3, 5, 5], ‘b’: True, ’s’: ’sfafds’, ‘value’: ‘xxxx’, ‘n’: 9}, ‘d’: {’a': 3, ‘aa’: {’arr’: [3, 5, 5], ‘b’: True, ’s’: ’sfafds’, ‘value’: ‘xxxx’, ‘n’: 9}}}}

★ Json格式

通过Sample数据模型转换Json格式就简单多了,其实从前面的测试结果(str(sampleobj))看到的结果就是一个Json字串了,但是我们必须重写,因为Json对Boolean的标识和Python情况不同,另外,也不能满足对某些特殊返回形式的需要。

def simple2json(self, instance):
  if isinstance(instance, (DictType)):
    return ‘{’ + ‘,’.join([’”%s”=%s’ % (o, self.simple2json(instance[o])) for o in list(instance)]) + ‘}’
  elif isinstance(instance, ListType):
    return ‘[’ + ‘,’.join([self.simple2json(o) for o in instance]) + ‘]’
  else:
    return str(instance)

 
 

Django系列-搭建简单WebApp与EclipseIDE调试 December 14, 2006

Filed under: Python — Rainfall @ 8:44 am

★ Django简介

Django是基于Apache,使用Python语言搭建的Web服务框架,它提倡DRY原则,因此整个架构具备很高的定制能力和扩展性,提倡Web开发的组件化,关于组件化这点,随着下面更深入的介绍Model,View以及filter和tag,你一定能更深刻的理解这点。

调试是严重影响开发效率的因素之一,我一直都不能理解大把的人做了那么久的JavaScript开发,竟然从来没有用过Debug,最多就是alert。哦,跑题了 :P 所以工欲善其事,必先利其器,最后在补充一下在Eclipse中调试Django的方法。

★ 最简单的Django网站

在次之前请先确保你已经安装了所有Django所需的组件,请参考之前的Django安装介绍《Apache+Python+Django+MySql搭建应用》。

首先我们要先建立一个网站工程,比如我们在c:\pyweb目录下建立一个pysite网站,请在pyweb目录下运行:

python django-admin.py startproject pysite

django-admin.py会在此目录下建立下列文件:

pysite
   __init__.py(python的package)
   manage.py(对django-admin.py的简单封装)
   settings.py(Web网站的参数设置)
   urls.py(网站Url的映射管理)

这样最简单的一个Web网站就完成了,你可以使用runserver命令启动这个网站:

python manage.py runserver 

除非你用runserver参数指定端口,默认是8000端口。当然你只能看到一个Django缺省页面。Django-admin.py是django最强悍的军刀,它存在与“PythonInstall/Lib/site-package/DjangoInstall/bin/”下面,建议你设置到PATH环境变量中。startproject命令只是建立了网站所必须的三个文件:

manage:其实就是django-admin的封装,封装也非常简单,就是设置了本网站对应配置文件。
settings:网站运行所需的所有配置参数,它其实是override了django的默认设置“DjangoInstall/conf/global-settings.py”。
urls:django采用了正则表达式作为url匹配的条件,最先匹配就返回,因此要注意url条目的顺序。正则表达式中的捕获(Capture)则会直接传入对应的view(就是和RegExp对应的函数)中。

★ 建立网站数据(model)

一句话就可以搭建网站很方便,但用django建立数据模型更快捷。首先在pysite目录下建立一个新的应用(WebApp)。

python.exe manage.py startapp polls

django-admin会建立下列文件:

polls(应用包,可复用单元)
   __init__.py
   models.py(数据模块)
   views.py(显示视图)

打开models文件,编写下面代码:

from django.db import models
class Poll(models.Model):
    question = models.CharField(maxlength=200)
    pub_date = models.DateTimeField(’date published’)
class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(maxlength=200)
    votes = models.IntegerField()

这样就建立了polls应用的数据模型,规定了数据模型的关系,数据类型,数据名称。django会根据这些代码自动建立数据库表。建立数据库的方法就是打开settings文件,填写数据库的地址、名称、类型。在INSTALLED_APPS中增加“pysite.polls”。然后运行syncdb命令即可:

python.exe manage.py syncdb

当然数据库中是否自动建立了所有的表,包括Polls和Choices。数据模型建立就完成了,你可以运行manage.py shell来对数据模型进行测试,比如新建,修改等等,有兴趣可参考django文档。

★ 建立后台数据管理。

建立数据管理的简洁程度最让我惊讶。只需两步:

1、修改settings.py中的INSTALLED_APP,去掉那几个被注释的应用,再次运行syncdb。django会建立认证用户数据,以便进行后台管理。
2、在Poll和Choice类中增加空的Admin子类。

再次访问“http://localhost:8000/admin/”即可看到登陆界面,登陆后就可以在管理界面进行数据管理,django甚至帮你自动做了数据关联,历史记录等等。后台管理也完全可定制,有兴趣可参考django文档。

★ 建立视图(views)

写了很多,但其实到此为止我们只用了5步就建立了完整的网站数据模型,甚至包含了一个非常美观的后台管理站点。最后,就是要把数据展现出来。还记得建立应用时说的urls文件么?你可以增加下列代码:

    urlpatterns = patterns('’,
        (r’^polls/$’, ‘mysite.polls.views.index’),
        (r’^polls/(?P《poll_id》\d+)/$’, ‘mysite.polls.views.detail’),
        (r’^polls/(?P《poll_id》\d+)/results/$’, ‘mysite.polls.views.results’),
        (r’^polls/(?P《poll_id》\d+)/vote/$’, ‘mysite.polls.views.vote’),
    )

然后在views.py编写视图代码:

    def index(request):
        return HttpResponse(”Hello, world. You’re at the poll index.”)
    def detail(request, poll_id):
        return HttpResponse(”You’re looking at poll %s.” % poll_id)

这样就完成了视图映射和视图实现。很巧妙的是,匹配url时的capture会作为视图函数参数传入,这样url地址就变成了函数调用,url中就自然包含了调用参数。

★ 用简单模版改善视图

首先在pysite目录下建立templates/polls目录,并建立一个detail.html文件:

《h1》{{ poll.question }}《/h1》
{% if error_message %}{{ error_message }}{% endif %}
{% for choice in poll.choice_set.all %}
    《p》{{ forloop.counter }} {{ choice.choice }}《/p》
{% endfor %}

修改views.py的detail实现:

from django.shortcuts import render_to_response
def detail(request, poll_id):
   p = Poll.objects.get(pk=poll_id)
   return render_to_response(’polls/detail.html’, {’poll’: p})

运行一下就可以看到效果了。django通过模版实现了页面设计与开发的紧密结合,不仅如此,template是django的核心,它还可以实现模版继承、tag定制、filter定制等等,这在稍后会专门做介绍。

至此一个较完整的网站就完成了,最后再看看调试问题。

★ Eclipse调试Django

调试之前确保安装的Pydev。首先建立一个Pydev工程,默认会建立一个src目录。完成后通过import导入pysite所有文件:

src
   pysite
      polls

在Project-》Preperties中添加pysite目录为PYTHONPATH。另外,确保pydev设置了“DjangoInstall/bin”目录为Path(Windows-》Preferences)。

这样你选择manage.py文件,然后设置Debug参数为runserver即可。

不过你会发现console里面没有熟悉的django启动信息,你只要在参数中增加noreload即可:

runserver –noreload

如果没有以外,就可以设置断点进行调试了。

 
 

推荐三个Django文档 December 12, 2006

Filed under: Python — Rainfall @ 12:06 am

★ 官方文档

http://www.djangoproject.com/documentation

英文的,但读起来很顺畅,强烈建议通读一下,建议先从《Tutorial: Writing your first Django app》开始,他会叫你做一个最简单的Web应用,例子虽然简单,却涵盖了Django最重要的内容,甚至可以用一行代码搭建起后台管理系统。

Django很多设计想法确实很巧妙Model,View,Filter,Tag,Template继承等等,是一个高定制性体系,无论是否使用Django,他的很多设计思路都非常值得学习。

 

★ IBM文档

http://www.ibm.com/developerworks/cn/linux/l-django/

如果你实在不愿意阅读英文文档,这里有一个内容相似的文章。

 

★ 中文SBS

http://www.woodpecker.org.cn/obp/django/django-stepbystep/newtest/doc/

好文章,译者一直在跟进这个工作,甚至翻译了历史文档。

这里给“啄木鸟社区”做个免费的广告,一群很有理想的人们在做一件很有意义的事情。

 
 

Apache+Python+Django+MySql搭建应用 December 11, 2006

Filed under: Python — Rainfall @ 11:51 pm

前段时间一直是用的“唐吉柯德”在Python上做WebApplication,最近想做一个Web应用,由于唐吉柯德没有很好的支持Html模版,想换一个学习学习。到网上搜了一下后才知道最近Django很火,而且他的特性之一就是很好的支持模版,所以搭建了一个,这里先介绍一下搭建过程。

★ Apache (www.apache.org)

由于mod_Python对Apache最新的2.2支持有些问题,因此建议安装Apache 2.0.x。Django会基于Apache建立新的监听端口,因此安装Apache时可以不用选择默认的80端口,也不用自动启动WindowService。

★ Python (www.python.org)

没什么好说的,就是要安装Python2.4,因为mod_python现在还不支持2.5版本的Python。
需要注意,不要忘记增加Path环境变量PythonInstall/目录。

★ mod_Python (http://www.modpython.org/)

mod_Python是一个Apache的Python封装,可以让Python访问Apache,他本身是一个Apache的模块,安装完成后,会在Python/Lib/Site-Package下建立一个目录。
mod_Python最新版本是3.2.10,但是现在还没有提供WinInstall,如果你有兴趣自己build,可以用一下,我这里用的是3.2.8,安装起来很方便。只有两点需要注意:
1、选择Apache目录时,一定要选择Apache2目录,否则安装会失败
2、别忘了安装完成后,要在Apache的conf (ApacheInstall/conf/httpd.conf)中添加下面的代码:

LoadModule python_module modules/mod_python.so

mod_python.so已经安装到了ApacheInstall/modules/下面了。

★ MySql (www.mysql.org)

MySql的安装很简单,就是记得必须安装Python调用封装MySql for Python(http://sourceforge.net/project/showfiles.php?groupid=22307)。

★ Django (www.djangoproject.com)

最后一步了,Django的安装需要先把发布包下载到本地后,调用

python setup.py install

安装过程需要安装工具“setuptools-0.6c1-py2.4.egg”,这个文件并不在安装包中,你有两种方法获取:
1、调用setup.py后等待15秒后,安装过程会自动下载并安装
2、单独下载后放在和setup.py同级目录后,再运行setup.py

如果一切正常,很快就可以结束安装。但还有后续工作要做,到PythonInstall目录下,还是刚才那个Lib/Site-Package里面多了一个Django目录(版本不同可能目录略有变化,我的就是Django-0.95-py2.4.egg。把他的bin目录追加到系统Path环境变量下,因为这里面有下一步经常会用到的管理工具”Django-admin.py”。

好了,这样就万事具备了,下一步就可以开始用Django搭建简单应用了。