You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Peewee字段更新后自动恢复默认值问题排查求助

Peewee模型字段意外重置问题分析与解决

问题场景

原始Peewee模型:

db = SqliteDatabase(Settings.stats_conf_database_location)

class ActivityTracker(Model):
    date = DateField(unique=True)
    activity_time_curr = IntegerField(default=0)  # active seconds today
    activity_time_max = IntegerField()   # max active seconds today

    class Meta:
        database = db

添加新字段并完成迁移:

blocked = BooleanField(default=False)

执行以下更新语句后,10-30秒内blocked会自动恢复为0,activity_time_curr也会回滚到旧值:

ActivityTracker.update(blocked=True).where(ActivityTracker.date == datetime.today()).execute()

该问题在多台Windows设备的大量进程中均出现,期间无其他代码执行。

排查到的相关代码

activity_tracker_obj, created = ActivityTracker.get_or_create(date=_datetime.date.today(),
                                                           defaults={'activity_time_curr': 0,
                                                                     'activity_time_max': max_working_seconds_today,
                                                                     'blocked': False})
InstaPyLimits.activity_tracker_obj = activity_tracker_obj  # 全局存储当日记录对象

def update_daily_activity(time):
    activity_tracker = InstaPyLimits.activity_tracker_obj
    new_time = activity_tracker.activity_time_curr + time
    activity_tracker.activity_time_curr = new_time
    activity_tracker.save()

疑问解答

为什么activity_tracker.save()会重置blocked值为0?

全局变量InstaPyLimits.activity_tracker_obj是程序启动(或首次调用get_or_create)时加载到内存的对象,它的blocked值是当时从数据库读取的旧值(或创建时的默认False)。当你用SQL语句直接更新数据库后,内存里的这个对象并没有同步最新的数据库状态。后续调用save()时,Peewee会将内存对象的所有字段值全量写入数据库,这就把已经被更新为True的blocked又覆盖成了旧的False(SQLite中布尔值以0/1存储,所以显示为0)。

为什么使用旧值?

因为全局存储的对象和数据库状态已经脱节,没有重新从数据库拉取最新数据,一直持有初始化时的旧字段值。

是否需要重新从数据库获取对象?

是的,这是解决问题的核心思路之一,也可以采用其他更高效的原子更新方式。

解决方案

方案1:每次更新前重新获取最新对象

修改update_daily_activity函数,每次操作都基于数据库最新数据:

def update_daily_activity(time):
    # 从数据库重新拉取当日最新记录
    activity_tracker = ActivityTracker.get(ActivityTracker.date == _datetime.date.today())
    new_time = activity_tracker.activity_time_curr + time
    activity_tracker.activity_time_curr = new_time
    activity_tracker.save()

方案2:使用原子更新(推荐)

直接通过SQL语句完成累加操作,无需加载对象到内存,完全不会影响其他字段:

def update_daily_activity(time):
    ActivityTracker.update(
        activity_time_curr=ActivityTracker.activity_time_curr + time
    ).where(
        ActivityTracker.date == _datetime.date.today()
    ).execute()

方案3:刷新全局对象的数据库状态

如果必须保留全局对象,在修改前先同步最新数据:

def update_daily_activity(time):
    activity_tracker = InstaPyLimits.activity_tracker_obj
    # 从数据库重新加载所有字段的最新值
    activity_tracker.refresh_from_db()
    new_time = activity_tracker.activity_time_curr + time
    activity_tracker.activity_time_curr = new_time
    activity_tracker.save()

内容的提问来源于stack exchange,提问作者Si si

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:57:38