分类目录归档:编程

JdbcTemplate之BeanPropertyRowMapper

Spring的JdbcTemplate无疑极大的简化了JDBC操作。只是查询出的数据都直接放在MAP里。想要直接从数据库里直接查询出对象的朋友不免要有些失望。

这写天本想给JdbcTemplate做个扩展,让JdbcTemplate自动绑定对象。等写得差不多的时候,很不幸的发现自己只是重复造轮子而已。Spring已经自带了比较完善的解决方案,通过BeanPropertyRowMapper自动绑定数据库的列到对象。BeanPropertyRowMapper的绑定规则是,FiledName相同的绑定,如果绑定失败,将尝试将hiVik转换成hi_vik查找数据库的列。

如果需要查询出一个包含YouVO对象的List只需要做如下操作就可以了。

List objList = DbHelper.getJdbcTemplate().query(sql, new Object[]{}, new BeanPropertyRowMapper(YouVO.class));

java的类ROR框架Play!

Play!一个类ROR的java框架。和Grails不同的是,Play!没有用Groovy等脚本技术进行扩展。直接使用java技术,这对java程序员来说要亲切很多,而且推广阻力也相应的会小不少。

最近简单的了解Play!,感觉确实是挺有意思的一个东西。Play!作为ROR“仿制品”,在开发思想方面和ROR还是比较接近。Play!本身提供了不少开发相关的辅助命令。使用命令创建出的新工程直接就可以运行了。相比之下,基于ssh的开发,光是脚手架的搭建就得费不少事。

数据模型方面使用JPA定义数据对象,直接从对象生成数据库。这点和django比较像,这也是比较符合我开发习惯的一个做法。

模板方面和Django类似,支持模板的继承。Django模板的继承给我的体验很好。jsp页面虽然可以使用include实现复用,但对于结构相似的页面依旧需要重复的include。Sitemesh虽然可以实现类似django模板的功能但看到那繁琐的配置我就撤了。

总的来说Play!给我的印象还是挺不错的,希望在日后的工作中可以用到。

其他

Play!的FAQ里有一个解答让我挺印象深刻的。其中有关于为什么使用不符合java规范的play做包名的说明。play!本身就是一个平台,运行在play!上的东西都将是符合play!规范的,所以不必为play这个包名而计较。play!专注于web的敏捷开发,为了适应web敏捷的需要一些无伤大雅的“另类”做法也是未尝不可的。想自己在某些情况下对代码还是有些所谓的“洁癖”。在django开发的时候喜欢在自己的app外面还要另外加一层包,而这种做法在一定程度上是不符合django做法的(django的app名必须唯一,即使上层的包名不同也没用)。

url_helper简化Django的url配置

django的url采用正则表达式进行配置,虽然强大却也广为诟病。反对者们认为django的url配置过于繁琐,且不支持默认的路由功能。

我倒觉得还好,只是如果觉得不爽,为什么不自己小小的hack一下,反正也就几行代码的事。

在这个背景下,我整了这个url_helper,利用url_helper可以简化配置和实现url的默认路由。所谓的url_helper其实就只有url_helper.py一个文件,使用的时候只想要import就可以。

url_helper的具体用法请参考具体的例子:

url_helper下载/范例

下面对使用方法做个简单的说明。

url的默认路由

from url_helper import execute, url_
import views
urlpatterns += patterns('',
    url(r'^(?P.*)', execute, {'views': views}),
)

在urls.py里增加如下配置,其中views为需要进行路由的views模块。url的规则为 /action/param1/param2/…/ 。

例如:

#/edit/4/
def edit(request, n="id"):
    html = """ edit object: %s""" % n
    return HttpResponse(html)

在没有指定action的时候默认使用的action为index。

提供函数url_简化url配置

仿照ROR的做法,参数用”:”标识。

例如:

url_(r’/space/:username/:tag/’, views.url_), 对应的django url配置为url(r’^space/(?P<username>[^/]+)/(?P<tag>[^/]+)/$’, views.url_),

#url_(r’/space/:username/:tag/’, views.url_),
#/space/vicalloy/just/
def url_(request, username, tag):
    html = """ username: %s 
tag: %s""" % (username, tag) return HttpResponse(html)

url_helper的完整代码

就如前面说的,代码非常少。不过实际应用的话,应当还需要做一些扩展。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from django import http
from django.conf.urls.defaults import url
import re
def execute(request, urls, views):
    """
    urls [methodName/]param1/param2/.../
    methodName default index
    """
    def get_method(views, methodName):
        try:
            return getattr(views, methodName)
        except Exception, e:
            return None
    method = None
    params = [e for e in urls.split("/") if e]
    params.reverse()
    if params:
        method = get_method(views, params.pop())
    if not method:
        method = get_method(views, 'index')
    if not method:
        raise http.Http404('The requested admin page does not exist.')
    return method(request, *params)
def url_(*args,**dic):
    regex = args[0]
    if regex[0] == "/":
        regex = regex[1:]
    regex = '^' + regex
    regex = regex + '$'
    regex = re.sub(":[^/]+",
            lambda matchobj: "(?P<%s>[^/]+)" % matchobj.group(0)[1:],
            regex)
    return url(regex, *args[1:], **dic)

[Django]增强的创建app的命令

简介

下载地址

虽然django的admin漂亮的实现了CRUD,不过在有时候admin并不是这么好用。然后开始进行手写CRUD,接着发现自己又陷入了重复操作中。相比而言Ruby自动生成的添加删除功能就好不少,你生成的基础框架是可以扩展的。

为了减少手动书写CRUD的工作量,我写了一个扩展的startapp command。使用这个命令会自动生成 list/new/edit 的操作和html文件(这样修改起来就方便多了)。

使用说明

如需要在其他工程使用该命令,只需要将项目中的django_extensions文件夹复制到其他工程的app目录,并在settings.py里把django_extensions添加到app列表里。该扩展命令为create_app,使用方法和django官方的startapp一致(如:manage.py create_app blog)。

命令演示

为了方便演示,该扩展命令包含了一个演示工程(hidjango)。下面的步骤是windows平台(因为用了几个bat)。

  1. 运行\hidjango\scripts\create_app.bat。根据提示输入app的名称,如blog。
  2. 打开\hidjango\settings.py,在app列表里添加 hidjango.blog 。
  3. 运行\hidjango\scripts\syncdb.bat,初始化数据库。
  4. 修改\hidjango\urls.py,添加app的映射 (r’^’, include(‘hidjango.blog.urls’)),
  5. 运行\hidjango\scripts\runserver.bat启动开发服务器。
  6. 在浏览器输入http://127.0.0.1:7000/访问页面,并可以实现完整的添加删除操作。

注:

  • command的py代码大部分都是从django-command-extensions(http://code.google.com/p/django-command-extensions)里复制过来的,我只做了少部分的修改。
  • 该命令还比较简单,还有很多可以扩展的地方。比如app_name不一定和model_name相同等。

模板文件预览:

/django_extensions/conf/app_template/
|~templates/
| `~{{ app_name }}/
|   |-base.html
|   |-edit.html
|   |-list.html
|   `-new.html
|~templatetags/
| `-__init__.py
|-__init__.py
|-admin.py
|-forms.py
|-models.py
|-tests.py
|-urls.py
`-views.py

django-tagging的使用方法

django使用app机制来实现组件的重用,充分的利用已有的app可以极大的简化开发工作。目前django下的app虽然还不够丰富,却也还是有部分不错的。django-tagging就是一个不错的app。

现在tag的应用非常广泛,tag基本上成了各网站的必备项目之一,django-tagging就是一个提供tag功能的app。django-tagging提供的功能非常丰富,使用起来却十分简单。下面我就介绍一些常用的用法,让大家对该app有个基本的了解,更详细的介绍还是老老实实的去看django-tagging的使用说明吧:)。

tagging.fields.TagField

我们先定义一个数据库模型Widget,下面的范例都用Widget来进行说明

class Widget(models.Model):
   name = models.CharField(max_length=50)
   tags = TagField()

就如上面的代码,只要在数据库模型中增加tags字段就可以为该对象提供tag支持了。tags被映射为CharField,在为对象添加tag时为,英文逗号分割的字符串如:

Widget(name='hello', tags='test,hi,hello')

这样就为新建立的对象添加了test hi hello三个tag了。

获取某个tag下的所有对象的代码如下:

    #取出所有属于TAG hi的对象
    tag = get_object_or_404(Tag, name='hi')
    widgets = TaggedItem.objects.get_by_model(Widget, tag)

如要取出Widget用到的所有tag的代码为:

    tags = Widget.tags.all()

提升pystardict对stardict字典文件的加载速度

stardict是linux下使用最广的字段程序,在广大网友的贡献下,stardict的字典文件可是相当的丰富。pystardict是一个读取startdict字典文件的python库。
前些天在邮件列表看到有人提到用pystardict加载stardict的字典文件速度慢的问题。加载字段文件时需要解析字段的索引文件(.idx)取出所有的单词信息。但python未提供指针,处理速度远比不上c。
我尝试用正则表达式对索引解析部分的代码进行重写,经测试,速度应当能提高3/5的样子。感觉依旧不是太理想,不知道是否还有什么别的办法。
我将改动后的代码生成了一个patch发给pystardict的作者,不知道是否会被采用。
下面是idx解析的关键代码(idx的结构确实是非常的简单):

        import re
        rawstr = r"""([\d\D]+?\x00[\d\D]{8})"""
        matchstr = self._file
        match_obj = re.findall(rawstr, matchstr)
        for e in match_obj:
            c = e.find('\x00')
            record_tuple = unpack('!%sc1x%sL' % (c, idx_offset_format), e)
            word, cords = ''.join(record_tuple[:c]), record_tuple[c:]
            self._idx[word] = cords

附件:提高了字典加载速度的pystardict

后记

今天收到原作者的邮件,我提交的patch已经接收了,新的pystardict已经更新过。不过他用的是我早些提交的patch。那个patch里,我unpack的时候没有做跳过\x00的处理,所以要稍微丑点。

GoogleCode上的SpringSide2vik项目建好了

本想将代码先整理下,不过似乎也没多少整理的必要。为项目新添加了netbeans的项目配置文件,这样使用netbeans的用户也可以方便的打开工程了。另外还做了个简单的视频演示,空间太烂,似乎要花挺久才能下载完。
项目地址:http://code.google.com/p/springside2vik/
视频演示:http://vik.haoluobo.com/static/springside2vik/springside2vik.htm

完成对老照片的调整,Django版本升级到1.0

今天完成了对老照片的调整,将Django的版本升级到了1.0。1.0版本的Django相比以前版本相比最大的变化就是那个newforms了。不过好在我在newforms出来不久就直接切换过去了,这次升级只需要在import的时候将newforms改成forms就可以。
admin也是0.96到1.0变化比较大的。不过老照片本来就不太依赖admin,所以我只修改了admin的url映射部分,保证admin后台可以正常打开。以后如果需要用到admin,再对admin部分进行调整。
由于我需要对用户上传的图片进行编辑,因此没有使用Django默认的上传处理。文件上传的变动给我带来了不少麻烦。以前从request.files里取出的文件是个map,但在新版本中变成了一个对象。这个对象虽然提供了files的相关接口,但却又不全,导致PIL无法正常处理。为此我增加了一个临时文件。先将用户上传的文件保存到临时文件再进行处理。在网上看到有用户遇到了和我同样的问题,不知Django在日后的版本中是否会修正。
至于目录的调整,我将那个碍眼的apps给去掉,把所有的文件放到oldphoto这个包下。
此外对项目的配置文件做了一些调整,将默认的数据库改为sqlite,保证程序可以在不做任何设置的情况下直接用manage.py runserver跑起来。
最后再将项目地址贴一下:
http://code.google.com/p/oldphoto/
将项目从SVN中取下后,依次运行scripts目录里的syncdb.bat、runserver.bat就可以跑起来了。当然,那些有些必备的环境还是需要的,python(>=2.4)+django(>=1.0)+PIL。

后记

本来休整工作还包括部分重构以及i18n等,不过在完成Django的升级后就开始没多少兴趣了。由于代码比较老,里面不少东西在现在看来都有更好的处理方式,如果全部都改工作量有点大,只是改部分打打补丁又没多少意思。或许那天重新写个自己看得顺眼点的新项目。

Google App Engine学习日志(三)不写了-_-,最后写点感受

    又整了几天的GAE,感觉也没什么好写的了。除了API部分和Django有些不同,其他的开发基本和Django差不多,边查手册变写也没啥问题(感觉Google的手册写的不是太好)。数据库部分感觉一些不是太习惯,自的管理后台比Django差太多,想手动编辑数据非常麻烦。数据库的变更也是一个麻烦事。新加属性后必须将数据库里的数据全部取出来重新put(保存)一次,不然所有用到该字段的地方都会查不出任何的东西。

Google App Engine学习日志(二)选个葫芦,开始自己的新工程

    GAE的API手册厚厚的一叠,如果要全部看完再动手,那估计还不得看完热情就已经跑光了。将GAE的入门手册看完后,我决定先找个范例工程,然后开始照葫芦画瓢。
    最终锁定了两个工程OnlyPy和Rietveld。
OnlyPy
    OnlyPy是国人用GAE写的一个Blog系统。我简单的看了下它的代码,还比较简单,挺具有参考价值的。
项目地址:http://code.google.com/p/onlypy/
演示站点(作者的Blog):http://onlypython.appspot.com/
Rietveld
    从Google内部开源出来的代码审核工具,据说是蟒爹的作品(Guido)。有了Google和蟒爹做招牌,这东西自然要多看两眼了。只是这东西的代码量并不太少,而且将非常多的代码都写在同一个文件里,阅读起来挺不爽的。
项目地址:http://code.google.com/p/rietveld/
演示站点:http://codereview.appspot.com/

选择好葫芦后就要开始画了。我根据以往的习惯,将项目的目录结构整理好,然后今天的工作先到此结束,改天继续。
整理好的项目结构如下。
/myProject/google apps/haoluobo/
|~haoluobo/将站点的主要文件都丢到haoluobo这个包下
| |~portal/我习惯将首页信息放到portal目录,然后将顶层的所有url转发给portal.urls
| | |+templatetags/
| | |-__init__.py
| | |-urls.py
| | `-views.py
| `-__init__.py
|~script/将些常用的命令写成bat,这样直接双击就可以执行了(可以偷懒一点点)。
| |-clear_tmp.bat*
| |-runserver.bat*
| |-runserver_with_clear.bat*
| `-update.bat*
|+static/程序用到的静态文件
|+templates/模板文件
|~vik/放自己通用工具的目录,目前还没啥内容
| |~utils/
| | |~gae/
| | | |-__init__.py
| | | `-webutils.py
| | `-__init__.py
| `-__init__.py
|-app.yaml
|-django.zip
|-haoluobo_bootstrap.py
|-index.yaml
|-settings.py
|-tags
`-urls.py