写通用的回复类, 原本打算做成一个独立的基类
class ReplyBase(object):
_REPLY_REALTED_CLS = None
_REPLY_CLS = None
mc_reply_id_by_rid = McLimitA(
"ReplyIdBy%sId:%%s"%_REPLY_RCLS.Meta.table.title(),
128
)
...
写下来以后, 忽然想到
"ReplyIdBy%sId:%%s"%_REPLY_RCLS.Meta.table.title(),
在基类定义的时候就被确定了, 不好搞
这样下去就只有用Meta Class
不过正如 洪教授 所言 ( http://www.infoq.com/cn/interviews/douban-hqn )
Meta Class 是种黑魔法, 正派人士都很畏惧它.
虽然有部YY小说, 标题叫做"魔本是道", 不过这也就是纯属意淫, 估计连本实体书都没有.
正如我昨天说过的 做人需要一点演技( http://www.douban.com/note/101804926/ )
写代码也不能太暴露内心的邪恶念头.
decorator, 正如其名, 装饰器, "装"是核心词, 是我圣教中人, 行走江湖必备的技能.
好吧, 过去我常常以"张教主"自诩, 不过一晃也有很多年没进行官方的正式声明了.
江湖儿女江湖老,昏昏灯火忆平生.
言归正传, 先来做一个小实验, 用函数动态添加一个基类
class C(object):
def x(self):
return self.__class__
class B(object):
pass
class A(B):
pass
def main():
print "A.__bases__ before", A.__bases__
A.__bases__ = tuple(list(A.__bases__)+[C, ])
print "A.__bases__ after", A.__bases__
print "A().x()", A().x()
输出是
A.__bases__ before (<class '__main__.B'>,)
A.__bases__ after (<class '__main__.B'>, <class '__main__.C'>)
A().x() <class '__main__.A'>
人体试验很成功, 我很开心
当然, 我这里有些细节懒得交代了, 我是工科生, 不是理科生, 我只追求可以work的solution, 不考究背后theory. 何况我本科文凭中还有"医学"两个字符.
医学是只看结果不问过程的.
不过, 如果你遇到什么问题, 可以从这里开始探索 http://blog.donews.com/limodou/archive/2005/01/06/227676.aspx
说了这么多, 还是直接上代码吧, 代码是很无趣. 就像武功秘籍一样.
找秘籍的人永远很多, 炼成的永远很少.
这还是精简演示版, 很多接口没做.
如果说Meta Class是基因改造, class decorator就像是整容手术了. 下面正式开工
=================================================
#!/usr/bin/env python
#coding:utf-8
from init_db import McModel, McCacheA, McCache, Model, mc, cursor_by_table, McLimitA
from const.man import STATE_DEL, STATE_APPLY, STATE_ACTIVE, STATE_BAN
class ReplyMixin(object):
def new_reply(self, man_id, txt, state=STATE_ACTIVE):
rid = self.id
self.reply_count += 1
self.save()
s = self._REPLY_CLS(rid=rid, man_id=man_id, state=state)
s.txt = txt
s.save()
self.mc_reply_id_by_rid.delete(rid)
return s
def reply_list(self, offset, limit):
return self._REPLY_CLS.mc_get_list(
self.reply_id_list(offset, limit)
)
def mixin_reply(reply_cls):
"""
@mixin_reply(XxxReply)
class Xxx(McModel):
pass
"""
def _(cls):
cls.__bases__ = tuple(list(cls.__bases__)+[ReplyMixin, ])
cls.mc_reply_id_by_rid = McLimitA(
"ReplyIdBy%sId#%%s"%cls.Meta.table.title(),
128
)
cls._REPLY_CLS = reply_cls
cls.reply_id_list = cls.mc_reply_id_by_rid("{self.id}")(
reply_id_list
)
return cls
return _
def reply_id_list(self, offset, limit):
c = self._REPLY_CLS.raw_sql(
"select id from " +
self._REPLY_CLS.Meta.table +
" where rid=%s and state>%s order by create_time limit %s offset %s",
self.id, STATE_APPLY, limit, offset
)
return [i for i, in c.fetchall()]
=============================
同时为了统一管理, 迁移原来的一些reply函数到新代码上, 但是保留原接口
=============================
--- mysite/model/review.py (revision 3071)
+++ mysite/model/review.py (working copy)
+from reply import mixin_reply
class ReviewReply(McModel):
pass
+@mixin_reply(ReviewReply)
class Review(McModel):
txt = review_txt.property
def review_reply_by_review_id(id, offset, limit):
- return ReviewReply.mc_get_list(
- review_reply_id_by_review_id(id, offset, limit)
+ return Review(id).reply_list(
+ offset, limit
)
def review_reply_new(review_id, man_id, txt, state=STATE_ACTIVE):
r = Review.mc_get(review_id)
- if r:
- r.reply_count += 1
- r.save()
- s = ReviewReply(rid=review_id, man_id=man_id, state=state)
- s.txt = txt
- s.save()
- mc_review_reply_id_by_review_id.delete(s.id)
- return s
+ return r.new_reply(man_id,txt,state)