PynamoDB使用save方法仅新增更新creation_datetime、每次更新修改last_update_datetime方案
解决方案
你遇到的问题核心是default_for_new仅在首次实例化模型且未给对应字段传值时生效,如果你是直接构造对象做upsert操作、或是实例化时未从数据库加载已有creation_datetime值就调用save,就会触发默认值重新生成,导致该字段被更新。可以用以下两种成熟方案实现需求:
方案1:重写抽象基类的save方法(兼容性最强,适配所有场景)
直接在你的抽象时间模型里重写save方法,自动判断对象是否为新建状态,对应更新时间字段:
from pynamodb.models import Model from pynamodb.attributes import UTCDateTimeAttribute from datetime import datetime def current_datetime(): return datetime.now() class AbstractDateTimeModel(Model): creation_datetime = UTCDateTimeAttribute(null=True) last_update_datetime = UTCDateTimeAttribute(null=True) class Meta(object): abstract = True def save(self, *args, **kwargs): # 仅当对象不存在于数据库时才更新创建时间 if not self.exists(): self.creation_datetime = current_datetime() # 每次保存都更新最后修改时间 self.last_update_datetime = current_datetime() return super().save(*args, **kwargs)
后续所有继承这个抽象类的模型,直接调用save()方法就会自动处理两个时间字段的更新逻辑,不需要额外写代码。
方案2:用update操作替代save(性能更高,适合更新场景)
如果是明确的更新场景,不要全量调用save方法,直接用PynamoDB的update接口指定要更新的字段,完全不会触碰creation_datetime字段:
# 先查询到要更新的对象 item = YourModel.get(hash_key="xxx", range_key="yyy") # 仅更新指定字段和最后修改时间 item.update(actions=[ YourModel.target_field.set("new_value"), YourModel.last_update_datetime.set(current_datetime()) ])
这种方式不需要先全量加载对象属性再保存,也不会有字段误覆盖的风险,性能比重写save里调用exists()要高。
原写法适用场景说明
如果你每次更新对象的流程都是「先调用get从数据库拿到已有对象 -> 修改对应字段 -> 调用save」,那原来的写法本身不会有问题,因为get到的对象已经有creation_datetime的有效值,不会触发default_for_new的默认值生成逻辑,不会被覆盖。
内容的提问来源于stack exchange,提问作者suresh
相关产品推荐
相关产品推荐

