如何解决如何在Django模型中违反约束时增加唯一时间戳?
作为使用TimescaleDB的一部分,这需要一个时间戳作为主键(SensorReading中的时间),我需要处理不同传感器值使用相同时间戳的情况。一种优雅的解决方案可能是涂抹冲突时间戳记(在碰撞时添加一微秒)。
对于以下模型,如何以健壮和高效的方式解决此问题?
class Sensor(models.Model):
name = models.CharField(max_length=50)
class SensorReading(models.Model):
time = models.DateTimeField(primary_key=True,default=datetime.now)
sensor = models.ForeignKey(Sensor,on_delete=models.CASCADE)
value = models.FloatField()
P.S。这是一种解决方法,因为Django不支持复合主键。否则,可以将传感器和时间戳设置为复合主键。
解决方法
为了使用 timescale db,我创建了一个虚拟主键字段,它欺骗了 Django 并将复合键值表示为单个 json 元组。
您可以在此处查看代码示例 - https://github.com/viewflow/cookbook/tree/v2/timescale_db
,我发现的一个解决方案是在模型保存调用周围使用try / except块。尝试添加传感器读数,该读数在大多数情况下都会成功,但是如果发生碰撞,请处理该错误。确保引发异常正是由于该冲突,然后将时间戳增加一微秒(最小分辨率)。然后重复尝试保存传感器读数。首先,由于碰撞概率低,这几乎总会成功。下面是经过测试以递归处理时间戳增加直到成功的代码。
class SensorReading(models.Model):
time = models.DateTimeField(primary_key=True,default=datetime.now)
sensor = models.ForeignKey(Sensor,on_delete=models.CASCADE)
value = models.FloatField()
def save(self,*args,**kwargs):
self.save_increment_time_on_duplicate(*args,**kwargs)
def save_increment_time_on_duplicate(self,**kwargs):
try:
super().save(*args,**kwargs)
except IntegrityError as exception:
if all (k in exception.args[0] for k in ("Key","time","already exists")):
self.time = str(parse_datetime(self.time) + timedelta(microseconds=1))
self.save_increment_time_on_duplicate(*args,**kwargs)
更健壮的实现可能还会在中止之前添加最大尝试次数。
,一般来说,我建议至少从 Django 中获取该传感器表的表管理,使用 psycopg2 或其他驱动程序进行插入,并在 Sensor,time
上创建适当的主键,然后公开表(或它上面的一个视图)作为它可以读取的 Django 模型,如果需要,可以使用连接。这些应该写一次,所以你不应该处理更新,这通常是它需要非复合主键的原因。在某个时候,Django 真的应该开始支持复合主键了,可惜他们没有。
其他方法可能有效,但它们可能根本无法很好地扩展。因此,如果您关心摄取率,我可能会尝试不同的方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。