<p>这两个问题我都想好了。此解决方案实际上在sqlddl中强制使用所需的触发器和默认时间戳。</p>
<p>首先,我们定义一个便利类来包装触发器的SQL。对于<code>peewee.Node</code>对象,有一种更合适的方法来实现这一点,但我没有时间为这个项目深入研究所有这些内容。这个<code>Trigger</code>类只提供字符串格式,以输出正确的sql来创建触发器。</p>
<pre><code>class Trigger(object):
"""Trigger template wrapper for use with peewee ORM."""
_template = """
{create} {name} {when} {trigger_op}
on {tablename}
begin
{op} {tablename} {sql} where {pk} = {old_new}.{pk};
end;
"""
def __init__(self, table, name, when, trigger_op, op, sql, safe=True):
self.create = 'create trigger' + (' if not exists' if safe else '')
self.tablename = table._meta.name
self.pk = table._meta.primary_key.name
self.name = name
self.when = when
self.trigger_op = trigger_op
self.op = op
self.sql = sql
self.old_new = 'new' if trigger_op.lower() == 'insert' else 'old'
def __str__(self):
return self._template.format(**self.__dict__)
</code></pre>
<p>接下来,我们定义一个继承<code>BaseModel</code>的类<code>TriggerTable</code>。这个类重写默认的<code>create_table</code>,以便在创建表之后创建触发器。如果任何触发器未能创建,则整个创建操作都将回滚。</p>
^{pr2}$
<p>下一步是创建一个类<code>BetterDateTimeField</code>。如果<code>default</code>实例变量设置为<code>datetime.datetime.now</code>函数,则此<code>Field</code>对象重写默认的<code>__ddl__</code>以附加一个“default current}时间戳”字符串。当然有更好的方法可以做到这一点,但这一个抓住了基本的用例。</p>
<pre><code>class BetterDateTimeField(pw.DateTimeField):
"""Propogate defaults to database layer."""
def __ddl__(self, column_type):
"""Return a list of Node instances that defines the column."""
ddl = super(BetterDateTimeField, self).__ddl__(column_type)
if self.default == datetime.datetime.now:
ddl.append(pw.SQL('DEFAULT current_timestamp'))
return ddl
</code></pre>
<p>最后,我们定义了新的和改进的<code>KeyValuePair</code>模型,其中包含了触发器和日期时间字段的改进。我们通过创建表来结束Python代码。</p>
<pre><code>class KeyValuePair(TriggerTable):
"""DurableHashMap entries are key-value pairs."""
key = pw.FixedCharField(primary_key=True, max_length=255)
val = pw.TextField(null=False)
fup = BetterDateTimeField(
verbose_name='first_updated', null=False, default=datetime.datetime.now)
lup = BetterDateTimeField(
verbose_name='last_updated', null=False, default=datetime.datetime.now)
@classmethod
def triggers(cls):
return (
cls.new_trigger(
'kvp_first_insert', 'after', 'insert', 'update',
'set lup = current_timestamp'),
cls.new_trigger(
'kvp_last_udpated', 'after', 'update', 'update',
'set lup = current_timestamp')
)
KeyValuePair.create_table()
</code></pre>
<p>现在模式已正确创建:</p>
<pre><code>sqlite> .schema keyvaluepair
CREATE TABLE "keyvaluepair" ("key" CHAR(255) NOT NULL PRIMARY KEY, "val" TEXT NOT NULL, "fup" DATETIME NOT NULL DEFAULT current_timestamp, "lup" DATETIME NOT NULL DEFAULT current_timestamp);
CREATE TRIGGER kvp_first_insert after insert
on keyvaluepair
begin
update keyvaluepair set lup = current_timestamp where key = new.key;
end;
CREATE TRIGGER kvp_last_udpated after update
on keyvaluepair
begin
update keyvaluepair set lup = current_timestamp where key = old.key;
end;
sqlite> insert into keyvaluepair (key, val) values ('test', 'test-value');
sqlite> select * from keyvaluepair;
test|test-value|2015-12-07 21:58:05|2015-12-07 21:58:05
sqlite> update keyvaluepair set val = 'test-value-two' where key = 'test';
sqlite> select * from keyvaluepair;
test|test-value-two|2015-12-07 21:58:05|2015-12-07 21:58:22
</code></pre>