心血来潮,实现了一个 django 的 url dispatcher,比想象中简单多了。 http://djangodispatcher.googlecode.com/svn/trunk/mapper.py http://djangodispatcher.googlecode.com/svn/trunk/test.py 实际实现功能的代码才2、30行,功能基本完整,包括分层次的url配置,和发生异常时帮助调试用的一些信息。 PS:发现最近爱上了 Test Driven.
2007年6月26日星期二
2007年5月30日星期三
Polymorphic Associations in Rails
Polymorphic Associations with SQLAlchemy SQLAlchemy 老大展示怎么用 sqlalchemy 实现 rails 的 Polymorphic Associations 顺便看了下 Rails 所谓Polymorphic Associations 的介绍,才发现其实就是我很早就介绍过的 django 的 content-type app 所干的事情,app 就是插件的意思。
标签: django, rails, sqlalchemy
2007年5月22日星期二
多重继承真是好哇
写 model 的时候发现有些东西在重复,第一反应就是写个基类,把这些重复的东西拿出来,然而 Model 类之间继承却不是那么方便的,应该会影响到 ORM 的行为。 怎么办呢?幸好 python 有多重继承。 下面就是项目中做这些重复事情的类:
class ModelMixin(object):
def save(self):
if not self.id: # creation time
if hasattr(self, 'pubdate'):
self.pubdate = datetime.now()
if hasattr(self, 'pubtime'):
self.pubtime = datetime.now()
if hasattr(self, 'updatedate'):
self.updatedate = datetime.now()
if hasattr(self, 'updatetime'):
self.updatetime = datetime.now()
if hasattr(self, 'number'): # 今天第几次发布
self.number = self.__class__.objects.filter(pubdate=datetime.now()).count()+1
if hasattr(self, 'before_save'):
self.before_save()
super(ModelMixin, self).save()
if hasattr(self, 'after_save'):
self.after_save()
注意:django 将废弃 auto_add 和 auto_now 这些东西,认为太 magic ,建议在 save 中处理,所以上面这个类就更有用了。
怎么用呢?
class Product(ModelMixin, models.Model):
pubdate = models.DateField(u'...', editable=False)
number = models.IntegerField(u'...', editable=False)
...
这样 pubdate 和 number 自然就有了相应的含义了。另外 ModelMixin 还定义了 before_save 和 after_save 的钩子,具体 model 可以在这两个方法里放点代码,比如:
def before_save(self):
self.totalprice = self.count * self.product.unitprice
...
def after_save(self):
if self._create:
p = OutProduct(postuser=self.postuser,count=1,
pubdate=self.pubdate,mainproduct=self)
p.save()
这些都是项目中直接拷出来的代码,具体意思你就慢慢猜吧,呵呵。
多重继承的实现其实是个还算复杂的过程,复杂的多重继承也会产生一些奇特的行为,不过基本上只要遵守一些良好的习惯(比如常用 super ,虽然写起来有些繁琐),了解一些多重继承的基本原理,基本上不会遇到什么奇怪的问题了。
关于 python 多重继承的实现,请看:The Python 2.3 Mehod Resolution Order
newforms 太好用了
建一个项目 newformstutorials ,建一个 app blog ,在 blog 的 models 中定义个:
class Article(models.Model):
title = models.CharField(u'标题', maxlength=255)
author = models.CharField(u'作者', maxlength=20)
hits = models.IntegerField(u'点击数', default=0, editable=False)
content = models.TextField(u'内容')
配置好数据库,把 newformstutorials.blog 加到 INSTALLED_APPS,manage.py syncdb,然后 manage.py shell ,然后:
In [1]: import django.newforms as forms In [2]: from newformstutorials.blog.models import Article In [3]: ArticleForm = forms.form_for_model(Article) In [4]: form = ArticleForm() In [5]: print unicode(form) <tr><th><label for="id_title">标题:</label></th><td><input id="id_title" type="t ext" name="title" maxlength="255" /></td></tr> <tr><th><label for="id_author">作者:</label></th><td><input id="id_author" type= "text" name="author" maxlength="20" /></td></tr> <tr><th><label for="id_content">内容:</label></th><td><textarea id="id_content" rows="10" cols="40" name="content"></textarea></td></tr> In [6]: print form.as_ul() <li><label for="id_title">标题:</label> <input id="id_title" type="text" name="t itle" maxlength="255" /></li> <li><label for="id_author">作者:</label> <input id="id_author" type="text" name= "author" maxlength="20" /></li> <li><label for="id_content">内容:</label> <textarea id="id_content" rows="10" co ls="40" name="content"></textarea></li>一个空白的 form 就这样出来了,这就是个添加文章的表单,让我们用这个表单来加点数据吧:
In [7]: form = ArticleForm({'title':'some title','author':'huangyi'})
In [8]: form.is_valid()
Out[8]: False
In [9]: form.errors
Out[9]: {'content': [u'This field is required.']}
In [10]: form = ArticleForm({'title':'some title','author':'huangyi', 'content':
'some contents...'})
In [11]: form.is_valid()
Out[11]: True
In [12]: article = form.save(commit=True)
OK,数据就这样保存了,我们再来试试数据更新的页面吧:
In [13]: ChangeForm = forms.form_for_instance(article)
In [14]: form = ChangeForm()
In [15]: print unicode(form)
<tr><th><label for="id_title">标题:</label></th><td><input id="id_title" type="t
ext" name="title" value="some title" maxlength="255" /></td></tr>
<tr><th><label for="id_author">作者:</label></th><td><input id="id_author" type=
"text" name="author" value="huangyi" maxlength="20" /></td></tr>
<tr><th><label for="id_content">内容:</label></th><td><textarea id="id_content"
rows="10" cols="40" name="content">some contents...</textarea></td></tr>
In [16]: form = ChangeForm({'title':'another title', 'author':'huangyi', 'conten
t':'other contents...'})
In [17]: form.is_valid()
Out[17]: True
In [18]: form.save()
Out[18]: <Article: Article object>
In [19]: article = Article.objects.get(id=article.id)
In [20]: article.title
Out[20]: 'another title'
2007年5月21日星期一
django newforms admin
又用 django 做了个项目,因为主要都是后台的东西,所以决定启用 django 的 newforms admin 分支!(不过这里我不是推荐大家现在就开始用 newforms admin 分支,如果没有把握,最好是抱着玩玩的态度先,我在开发过程中就改掉它好几个bug) newforms admin 分支是用 newforms 来重构 admin 模块,也顺便改变了一些设计决策,大大增强了 admin 的可定制性。首先 newforms 的应用,成功分离了 db field、form field、widget 三个部分,db field 属于 ORM ,主要负责 model 相关的事务,form field 主要处理用户输入数据的验证,widget 负责渲染ui,似乎这里面还透着 MVC 的影子呢 ;-) newforms admin中可以方便地对 widget 进行替换,怎一个爽字了得。 另外,新的 admin 把 admin 部分的定义从 model 中分离出来了,似乎写起来要麻烦点,不过好处也是显而易见的,首先是 model 定义更整洁了,其次新的 admin 设计成了一种重用性更好的形式,用得好的话还能省下不少代码呢,而且能够完成一些以前的 admin 很难完成的任务。 新 admin 的核心在于 AdminSite 和 AdminModel,AdminSite 负责一些全局性的事务,比如首页,用户登录登出改密码权限控制,和model的注册,AdminModel 负责单个 model 的相关管理页面。 这样做的好处是你可以继承这两个类,覆盖掉一些合适的方法,你基本上可以为所欲为。 比如,我在这个项目中就写了这么几个自定义的 admin 类:
class CustomAdmin(admin.ModelAdmin):
def before_save(self, request, instance, form, change=False):
pass
def save_add(self, request, model, form, post_url_continue):
def custom_save(form, commit=False):
instance = model()
new_object = forms.save_instance(form, instance,
fail_message='created', commit=False)
self.before_save(request, new_object, form)
if commit:
new_object.save()
for f in model._meta.many_to_many:
if f.name in form.cleaned_data:
setattr(new_object, f.attname, form.cleaned_data[f.name])
return new_object
form.__class__.save = custom_save
return super(CustomAdmin, self).save_add(request, model, form,
post_url_continue)
def save_change(self, request, model, form):
def custom_save(form, commit=False):
from copy import copy
new_object = forms.save_instance(form,
copy(form.original_object),
fail_message='changed', commit=False)
self.before_save(request, new_object, form, change=True)
if commit:
new_object.save()
for f in model._meta.many_to_many:
if f.name in form.cleaned_data:
setattr(new_object, f.attname, form.cleaned_data[f.name])
return new_object
form.__class__.save = custom_save
return super(CustomAdmin, self).save_change(request, model, form)
大家应该可以看得出来,这个 admin 提供了 before_save 的钩子(当然你也可以提供 after_save 不过我这里暂时只需要 before_save),你可以继承它然后在这个方法里写些代码,就得在 model 保存之前得到执行。你可能要问,为什么不直接定义 Model 的 save 方法呢?答案很简单 Model 不知道 request 和 form 的存在!
在 before_save 中你就可以做些很有意思的事情了,比如自动把 model 中某个字段设置成当前登录用户!这个定制需求其实很早就提出来了,以前的解决方案是写个 middleware 把 request 放到 threadlocal 中去,然后在 model 中通过 threadlocal 获取当前请求的 request ,能用,但是很麻烦也很丑。现在用这个 before_save 可以轻松实现:
class AutoUserAdmin(CustomAdmin):
user_field_name = 'postuser'
def before_save(self, request, instance, form, change=False):
setattr(instance, self.user_field_name, request.user)
super(AutoUserAdmin, self).before_save(request, instance, form, change)
当然你也可以继承这个 AutoUserAdmin ,写上你自己的 user_field_name ,太简单了。
还有一个常见的定制需求就是限制登录用户只能看到自己发布的信息,看不到更不能修改别人发布的信息。 在上面这个 AutoUserAdmin 的基础上做:
class RestrictUserAdmin(AutoUserAdmin):
def queryset(self, request):
queries = {self.user_field_name:request.user}
return super(RestrictUserAdmin, self).queryset(request).\
filter(**queries)
是不是超简单?呵呵。
另外别忘了 python 还支持传说中的多重继承,意味着你可以同时继承多个 admin 类,并拥有多个 admin 类的组合功能。比如我这里定制了一个支持文件上传的 admin(newforms 和 newforms admin 暂时都还没有把文件上传相关的东西加进去,只能自己写),我把它叫做 FileUploadAdmin ,现在我希望我的 admin 能同时拥有 RestrictUserAdmin 和 FileUploadAdmin 的功能,没问题:
class CommonAdmin(FileUploadAdmin, RestrictUserAdmin):
date_hierarchy = 'pubdate'
list_per_page = 15
ordering = ('-id',)
当然我还在里面定义了一些通用的(当然是对于我自己的项目来说) admin 配置。
然后怎么把这些 admin 应用到 model 上去呢?
class ProductAdmin(CommonAdmin):
list_display = ('__str__', 'type', 'unitname', 'unitprice',
'qsinfo', 'postuser', 'pubdate', 'image_view')
list_filter = ('type', 'pubdate')
)
admin.site.register(Product, ProductAdmin)
上面的代码虽然不错,不过我还是嫌麻烦,实际上我是这么写的:
admin.site.register(Product,
CommonAdmin,
list_display = ('__str__', 'type', 'unitname', 'unitprice',
'qsinfo', 'postuser', 'pubdate', 'image_view'),
list_filter = ('type', 'pubdate'),
section_name = '通用',
)
不过要让上面的代码正常运行,还需要对 django newforms admin 分支的代码做一点小改动才行,在文件 django/contrib/admin/sites.py 中大约 73 行的位置:
# TODO: Handle options的下面加上:
# it works
if options:
admin_class = type(admin_class.__name__, (admin_class,),
options)
实际上,使用 django 乃至 python 最大的快乐就是别人写的代码你都可以轻松看懂,这难道不是作为程序员最大的快乐吗? ;-)
如果你现在开始用 django newforms admin 分支的话,估计遇到的大部分问题都是和 unicode 有关(因为我遇到的就是这样的),这是因为目前 django 的开发 和 python 本身的开发一样,都处在整体向 unicode 迁移的过程之中,当前最大的矛盾就是 ORM 使用的是普通字符串(也就是 python3000中所谓字节数组),而 newforms 却开始整体使用 unicode 了,这常常带来麻烦。如果你在基于 django 最新的 svn 版本开发,那一定要看一下 Unicode 分支了,里面说到了如何使让你的程序顺利过渡到 unicode ,祝大家过渡快乐 ;-)
2007年3月18日星期日
2007年2月5日星期一
Deploying Django
Django Book Chapter 21: Deploying Django 肯定有许多人对这章的内容感兴趣 ;-) 这一章首先介绍了 django “Shared nothing”的设计哲学,这是django可扩展性的源泉。 随后介绍了他们比较偏爱的典型配置:
- 操作系统用 Linux——特别是Ubuntu。
- web 服务器用 Apache 和 mod_python。
- 数据库服务器用 PostgreSQL。
随后介绍如何配置 apache、mod_python 和你的django应用。教你如何在一个apache上部署多个django应用,如何把 mod_python 用做开发服务器,如何处理静态文件,如何处理错误等等。
随后还介绍了使用 fastcgi 方式部署 django 应用,不过这部分我不太感兴趣,就直接跳过去了。
最后还有很重要的一部分,调优,不过说来说去也还是那么几条了:
- 多买内存
- 关闭 Keep-Alive ,不过这一点只是大部分情况而已,具体还得看你网站提供的功能。
- 使用 memcached
- 积极参加各个开源产品的社区
ps: 有些日子没写blog了,刚考完,心一下就野了,什么计划都忘了,写一篇来凑凑数目 ;-)
2007年1月22日星期一
intergrate genshi with django
写了个程序,用来在 django 中使用 genshi 模版: http://huangyilib.googlecode.com/svn/trunk/mashi_django/genshi_django.py
- 配置文件中通过元组 GENSHI_TEMPLATE_DIRS 指定模版存放路径;
- 会自动到已安装的 app 下的 genshi_templates 目录找模版文件;
- DEBUG 为 True 时,启动模版的 auto_reload,否则关闭;
intergrate mako with django
写了个程序,用来在 django 中使用 mako 模版: http://huangyilib.googlecode.com/svn/trunk/mashi_django/mako_django.py
- 配置文件中通过元组 MAKO_TEMPLATE_DIRS 指定模版存放路径;
- 另外自动到所有安装过的 app 下的 mako_templates 目录下找模版;
- 模版编译后的 python 代码默认和相应模版文件放在一个目录下面,然后在模版文件的文件名后面加 ‘.py’,你可以通过配置 MAKO_MODULENAME_CALLABLE callable 对象来定义你自己的 module 文件名生成方式,这个功能来源于 mako ticket 14 ,好像这是我第一个 ticket ;-)
- 如果在配置文件中指定 MAKO_MODULE_DIR 的话,所有编译后的 python 代码都会存到这一个目录里来。
[news] django moving towards 1.0
都是些好消息 ;-)
There’s a lot of different things that “1.0” can mean. In many cases the label refers to some arbitrary measure of code maturity, but that’s usually very indistinct. There’s quite a bit of “1.0” software that’s far less robust than Django was at day 1; we could have called it “1.0” then and gotten away with it, I think.
In the context of Django, though, 1.0 has always meant something more concrete: forwards compatibility. Once we tag something as 1.0, we’re committing to maintaining API stability as described in the contributing HOWTO (http://www.djangoproject.com/documentation/contributing/#official-releases).
The last, most important, piece of the puzzle, is that we now have official ticket managers, a group of volunteers who work together to manage ticket metadata and otherwise streamline the process. Although anyone can -- and is encouraged to -- help out keeping tickets organized, these folks have volunteered to take ownership of the ticket tracker in the long term. Please welcome Chris Beaven (SmileyChris), Simon Greenhill, Michael Radziej and Gary Wilson!另外现在还有了一名专门的 release 管理员 ,并且最近发布了 django 0.95.1。
2006年12月2日星期六
django collection
Inspired by CherryPy Collection which is inspired by wsgicollection . code 代码 不知不觉又是好久没有写 blog ,最近被 javascript 和 浏览器折磨得好惨!哎,怀念漂亮的 python。这不,忙里偷闲还是要写点有意思的小程序,希望对某些人有用 ;-)
This project include two applications: the djcollection and a demo app task. REST is mostly about url dispatching, and djcollection app provide a set of generic RESTful urls for all the models of the project, djcollection app also provide a GenericCollection which uses the django generic views. the task app is for demonstrate the usage of the djcollection.
2006年10月29日星期日
django new forms and tgwidgets
2006年9月14日星期四
laying out an application
好文推荐:Django tips: laying out an application 我想这篇文章能帮助你对 django 有个全面的理解。 它对 project 和 app 的区别,和 django 中对 project 和 app 代码布局的约定有很详细的讲解,这些知识对于编写可重用可扩展的 app ,或是整合定制扩展第三方的 app 都是必不可少的。 其中还花费了一些笔墨介绍了 django 的一个很有意思的机制 signal 。它允许应用程序可以通过监听 signal ,在某些事件发生的时候获得通知并执行特点代码,并且 app 也可以编写自己的 signal。这个机制使得 app 的某些代码可以“侵入”核心框架和其他 app 的执行过程中,对于 app 的重用性是大有裨益啊! 文章剩下的部分还介绍了其他一些不成文的代码组织规范。 希望这些东西对你有用 ^_^
django 的 contribs 之 comments
comments ,顾名思义,它是用来处理用户评论的。 托 contenttypes 的福,它可以处理对任意 model 的评论!是一个通用的 comment 框架!并且它自带有相关的urls配置、templates、templatetags、控制器,可以很方便地将它们整合到项目中来。 comments 框架围绕两个关键 model 分成相对独立的两部分:Comment 和 FreeComment ,前者是一个相当复杂的评论系统,包括reviews, ratings, attached images, reputation over time, flagging of potentially bad content, user bans and groups of moderators who can remove comments 等许多功能!后者是个简单的版本,只有一些基本的评论的功能。 关于 FreeComment 部分已经有一些不错的文档了:Using Django's Free Comments , Django tips: Hacking FreeComment 。 Comment 部分虽然功能多一些,不过结合对 FreeComment 使用方法的介绍和对代码的阅读,应该搞清楚也不是难事,也许有时间有机会会去仔细研究一下。
2006年9月12日星期二
Rails/Django comparison synopsis
Rails/Django comparison synopsis (a BIG summary)
这是 django 邮件列表中的一个帖子,收集了一些比较 rails/django 的观点。
当然几乎所有人都强调的一点就是,django 和 ror 是非常相似的。
不过也许是因为 django 社区中的缘故,似乎说 django 好话的多些。
总结一下他们的意见,django 表现得好的方面主要有:
- 灵活的app,
"If you're creating a single monolithic application, Rails is pretty sweet."
"With Django you can build an app, put it on the server somewhere, and for as many sites (projects) as you like you can pull in that app, skin it and use it." - 部署,通过 mod_python 部署在 apache 上
- 文档,虽然 ror 有一本好书,不过站点上的文档比较糟糕
- 模版语言,这个主要看个人爱好,不过似乎多数人偏爱 django 的方式
- admin 界面
- admin 界面还不够灵活
- 没有内置 ajax 支持
2006年9月10日星期日
django 的 contribs 之 contenttype
上一篇blog介绍到了那个 repository ,其中 trunk/libs.common/src/common/mptt/models.py 里有一个很有意思的叫做 Node 的 model。实现了一个叫 Modified Preorder Tree Traversal 的算法,相关内容还可以参考 这个 页面。 算法细节刚才链接到的文章都讲得很详细了,吸引我注意的是代码中两个陌生的词语:ContentType, GenericForeignKey。django 文档中 model-api 中对 GenericForeignKey 完全没有涉及,add_ons 中对 contenttype 的描述也只有简单的一句:
A light framework for hooking into "types" of content, where each installed Django model is a separate content type. This is not yet documented.通过 google 也只搜到了这么 一篇文章 ,也只是泛泛而谈而已。经过研究,越发地感觉有意思了,于是写下心得,这么有意思的东西被埋没了可真可惜。 简单得说,ContentType 就是一个 model,也就是一张数据表,其中保存着当前 project 中所有 models 的元数据,具体就是 name、app_label 和 model 三个字段,其中 app_label 和 model 这两个字符串组合起来便可以唯一标识一个 model 。通过调用 django.db.models.get_model(app_label, model) 就可以获得该 model 类。 这样一个奇怪的 model 会有什么用处呢?可以设想一下,如果你需要一个和任意 model 都建立有关系的 model 时,你会怎么做?比如:用户评论! 假设你的 project 中有电影、有文章、有音乐等等内容,它们分别对应不同的 model ,而用户对它们每一种内容都可以进行评论,那么最简单的做法就是为每一种内容建立相应的评论表,比如:movie_comments, article_comments 等。不过这种做法的弊端是很明显的:首先是增加了 model 的数量也增加了代码的复杂度;而且没有扩展性,增加其他内容的话还需要增加相应的 comments 表;还有就是统计用户所有评论的时候比较麻烦,需要在多个表中进行查询。 要是我们有了一个记录了项目中所有 model 的元数据的表,表中一条记录便对应着一个 model ,那么我们只要通过一个元数据表的 id 和 一个具体数据表中的 id ,便可以找到任何 model 中的任何记录。ContentType 正是这个表(不过有个前提就是:相关 model 的主键类型必须是相同的,使用django默认的主键就ok了)。 有了 ContentType ,我们的用户评论就只需要一个 model 就可以搞定! 下面开始介绍具体做法吧,首先通过执行以下命令 >django-admin.py startproject ContentType 创建一个 project。 然后修改 settings.py ,配置合适的数据库后端。 然后通过 >cd ContentType >manage.py startapp contents 创建一个 app,修改 contents/models.py 如下:
from django.db import models from django.contrib.contenttypes.models import ContentType class Movie(models.Model): title = models.CharField(maxlength=100) class Article(models.Model): title = models.CharField(maxlength=100) class Music(models.Model): title = models.CharField(maxlength=100) class Comment(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.IntegerField() content_object = models.GenericForeignKey() title = models.CharField(maxlength=100)然后在 settings.py 的 INSTALLED_APPS 中加入: "ContentType.contents", 执行命令: >manage.py syncdb 然后执行: >manage.py shell 现在就可以好好地享受享受劳动果实了。
>>> from ContentType.contents.models import * >>> a = Article() >>> a.title = 'article1' >>> a.save() >>> m = Movie() >>> m.title = 'movie1' >>> m.save() >>> mu = Music() >>> mu.title = 'music1' >>> mu.save() >>> c = Comment() >>> c.content_object = a >>> c.title = 'comment1' >>> c.save() >>> c = Comment() >>> c.content_object = m >>> c.title = 'comment2' >>> c.save() >>> c = Comment() >>> c.content_object = mu >>> c.title = 'comment3' >>> c.save() >>> for c in Comment.objects.all(): ... print c.content_type,c.object_id ... article 1 movie 1 music 1 >>> c.content_object.title 'music1'还有一个值得提一下的地方就是 Comment 的 content_object 字段。实际上根据上面的解释它只要有 content_type 和 object_id 两个字段就够了,不过你总是需要亲自指定两个字段的值。而 GenericForeignKey 出现的目的就是要把这个过程给自动化了,只要给 content_object 赋一个对象,就会自动得根据这个对象的元数据 ,给 content_type 和 object_id 赋值了。 GenericForeignKey 的构造函数接受两个可选参数: def __init__(self, ct_field="content_type", fk_field="object_id"): 你可以在构造 GenericForeignKey 时指定另外的字段名称。 另外还有值得注意的一点就是:contenttype 的表是在 syncdb 时创建的,不过一开始其中并没有元数据,其中的数据是在需要的时候才添加上去的,正如你所想的,它使用的是get_or_create方法。
django apps repository!
最近django的邮件列表热烈讨论一个叫做 apps repository 的东西。就是建立一个保存用户提交的 app 的统一的存储中心。
我想这么一个东西的存在一定程度上是直接得益于 django 的一些优秀的设计:
在 django 中一个 project 由多个 app 组成,一个 app 由相关的 urls、views、models、templates、templatetags(自定义的模版标签) 等组成,一个 app 就是一个文件夹,一个包,一个重用单位。而 pylons 等框架是将所有 controllers (对应django的views) 放一处、 所有 models 放一处、所有 templates 放一处。相比之下,django 提供一个相对 project 更小粒度的 app 成为重用的最小单元,使得代码重用变得更为方便。
这样一个好机制其实是得益于 django 中许多细节上的设计的,比如 url dispatcher 的 include 机制,使 app 可以独立设计自己的 urls ;灵活的可扩展的 template 加载机制使 app 可以和自己的模版、自定义模版标签一起分发;...;最后还有最重要的一点原因就是:django "一块式" 的设计哲学。因为这些便利都是基于一个前提的,那就是:这些 app 使用着同一套url dispatcher,同一套模版引擎,同一套 orm 等。
目前 django 代码里面 contrib 目录下那些东西,就是些可重用的 app 。 简单如 sites 的,只有一个 models(和相关的managers); 更复杂一些如 comments 的,便连 views、templates 也都有了;还有庞大如 admin 的,甚至连自己的 urls 都有了!
貌似目前还没有推出正式的 django apps repository 吧,倒是有个兄弟公开了自己一个私有的repository:
http://svn.sourceforge.net/svnroot/django-userlibs
虽然数量还不多,不过还是有了一些很有意思的代码了 :)
希望正式的 repository 快快建立起来,希望用 app 组装 project 的日子快快到来吧!
ps:据说 ror 有个 plugin 的东西,不知是什么样的一个机制,希望有了解的朋友也介绍介绍吧. ^_^
Profile
- 黄毅
- 深圳, 广州, China
- I Love Python !
Recent Posts
Recent Comments
Tags
- 设计模式 (1)
- ajax (3)
- allegra (1)
- cherrypy (1)
- compiler (1)
- continuation (2)
- descriptor (1)
- django (17)
- dotnet (1)
- framework (2)
- functional (1)
- genshi (1)
- gtk (1)
- haskell (1)
- inkscape (1)
- IronPython (2)
- javascript (1)
- libevent (1)
- mako (1)
- metaclass (4)
- mochikit (1)
- network (1)
- newforms (1)
- orm (1)
- others (18)
- paste (1)
- PEAK (1)
- pickle (1)
- ply (1)
- pocoo (1)
- pypy (3)
- python (38)
- python3000 (3)
- rails (2)
- REST (3)
- sqlalchemy (3)
- stackless (3)
- turbogears (1)
- tutorial (1)
- vim (1)
- web (11)
- wsgi (1)