最近一段时间一直在忙着ORM的优化,其中有几点:
1.增加__table_args__的配置。它和__tablename__一样是定义在Model类中的,可以用来增加在执行Table时添加新的一些参数,如果你使用mysql,可以如下定义:
class Todo(Model):
__table_args__ = dict( mysql_engine='InnoDB', mysql_charset='utf8')
这样将在建表时,向Table中添加这样的信息。上面的代码将以InnoDB和utf8编码来创建todo表。
2.增加OnInit类方法的调用。这个方法是交给用户来定义的,可以用来执行在执行完Table之后的一些初始化操作,它将在建表之前。比如:
@classmethod
def OnInit(cls):
Index('my_indx', cls.c.title, cls.c.owner, unique=True)
这样将创建以title, owner的索引,并且索引不允许重复。目前只支持索引的创建。对于简单的索引,是可以在定义Field时直接设置index=True来创建的,并不需要这种方式。这种方式可以认为就是为了创建多个字段的联合索引。
3.考虑缺省order_by的实现。但是想用户完全可以在Model中定义相应的方法来实现,类似于django的Manager的东西,比如:
class Todo(Model):
@classmethod
def files(cls):
return cls.all().order_by(cls.c.title.desc())
然后在使用时可以通过Todo.files()来返回按title降序排列的结果。所以使用这种方法倒是不一定要支持缺省order_by的配置项。不过有这个配置项的好处就是当需要实现通用的查询时,它可以自动生效。不过也可以考虑把结果集当成一个参数传给配置功能,总之还是有方法。
4.最重要的一个特性。增加表的注册,并且注册的表不一定是一个Model,而是一个模块名的形式,如以下两种都是正确的注册方式:
set_model(Model, tablename='user')
set_model('uliweb.contrib.auth.models.User', tablename='user')
这样注册之后,你就可以通过使用真正的表名来得到对应的Model类对象了。通过:
User = get_model('user')
这种方式首先可以使用在关系的定义中,如:
Reference('user')
ManyToMany('user')
对于关系定义,它可以根据表名自动导入对应的Model。而对于在程序中想直接使用某个Model,则可以通过get_model()来获取。
但是这种get_model()的方式要依赖于set_model()的注册过程。注册有几种方式:
1. 在导入Model文件时,随着Model的class的创建自动会调用set_model()来注册,因此只要正常导入相应的模块,就可以使用get_model()方法了。这种情况下,对通常的开发没有什么影响,用户甚至不必使用这种方式。
2. 由框架来注入。也就是uliweb来实现。这种方式首先要求将Model信息写入到settings.ini中,比如:
[MODELS]
user = 'uliweb.contrib.auth.models.User'
这样当uliweb在启动时可以自动采集注册信息。然后在orm这个app的__init__.py中执行真正的注册工作,通过调用set_model()方法。这时,注册的就不是Model了,而是字符串形式的信息。
然后在某个地方,如views.py中使用get_model()或导入models.py时,就可以自动生效了。
你可能会问,这有什么用呢?一般不都是直接导入来使用吗?完全够用了。
的确,一般的程序的确是根本用不上。但是Uliweb是一个框架,它要考虑代码的复用和替换的问题。考虑一下,在你的models.py可能需要对User表进行处理,那么你会去导入它。但是有可能这个User表不适合你的应用了,你怎么办?并且这个User表不是你自已写的,而是框架或别人提供的,别人可能还要依赖于这个表。因此简单的直接修改并不一定是好办法,因为它可能不受你的控制。重新写一个可能是好办法,但是因为直接导入的原因,比如你是通过:
from uliweb.contrib.auth.models import User
这可是直接hard code了,所以重新写必然还要修改导入的代码。那么要解决这个问题,可以采用的一种办法就是将外部依赖的内容配置化,和java中的注入依赖有些象。也就是我在定义自已的东西时,可能需要外部的东西,那么我并不直接导入,而是通过一种获取的方式来得到。这样工并不需要知道外部的组件的实际位置,这件事由框架来完成。因此uliweb现在实现的get_model就是为了实现这一配置化而设计的。
其实现在,象bind,expose都已经是可以配置化的了,都可以放在settings.ini中。如果完全配置化,将可以减少启动时的导入处理,并且替换会很容易。
暂时没有评论