.save() 只是一堆一个接一个地执行的信号。这是来自the documentation的流程的简化版本:
发出预保存信号。 [...]
预处理数据。 [...] 大多数字段不进行预处理 [...] 仅用于具有特殊行为的字段 [...]
文档还没有包含所有字段的列表
“特殊行为。”
为数据库准备数据。 要求每个字段以可写入到
数据库。大多数字段不需要数据准备 [...] 整数和字符串是
“准备写”作为 Python 对象 [...] 复杂的数据类型通常
需要一些修改。 [...]
将数据插入数据库。 [...]
发出保存后信号。 [...]
在您的情况下,您在该过程的中间没有做任何事情。您只需要在模型已保存后执行此操作。所以不需要使用信号。
现在您真正要问的是如何确保最终执行任务。嗯:
- 我很确定你可以用 celery 解决这个问题
- 您应该将应用程序连接到单个数据库(如果可以的话),不要在本地保存内容然后更新服务器,这可能会变得很丑。
但是,如果您确实认为互联网很可能会出现故障或类似情况,并且您确定没有更好的方法来链接您的应用,我建议您添加一个跟踪更新内容的新模型。像这样的:
class Track(models.Model):
modelname = models.CharField(max_length=20)
f_pk = models.IntegerField()
sent = models.BooleanField()
def get_obj(self):
try:
# we want to do modelname.objects.get(pk=self.f_pk), so:
return getattr( getattr(self.modelname, 'objects'), 'get')(pk=self.f_pk)
except:
return False
请注意,我没有将它链接到某个模型,而是为它提供了工具来获取任何你该死的模型。然后,对于您要跟踪的每个模型,添加以下内容:
class myModel(models.Model):
...
def save(self, *args, **kwargs):
super(Model, self).save(*args, **kwargs)
t = Track(modelname=self.__class__.__name__, f_pk=self.pk, sent=False)
t.save()
然后安排一个任务,将 Track 对象与 sent=False 并尝试保存它们:
unsent = Track.objects.filter(sent=False)
for t in unsent:
obj = t.get_obj()
# check if this object exists on the server too
# if so:
t.sent = True
t.save()
附言
还记得我说过事情会变得丑陋吗?自从我发布这篇文章以来已经有一段时间了,我已经知道如何了。请注意我如何使用 pk 和模型名称来确定模型是否保存在两个位置,对吗? 但是,pk 是(默认情况下在 django 中)一个自动递增的字段。如果应用程序在两个地方运行,或者即使您在本地运行它并且发生了一次错误,那么 pks 很快就会不同步。
假设我保存了一次对象,它在本地和服务器上的 pk 均为 1。
local server
name pk ++ name pk
obj1 1 ++ obj1 1
然后我保存了另一个,但互联网中断了。
local server
name pk ++ name pk
obj1 1 ++ obj1 1
obj2 2 ++
下次启动时,我添加了一个新对象,但这发生在计划任务运行之前。所以现在我的本地数据库有 3 个对象,我的服务器有 2 个,它们有不同的 pk,明白了吗?
local server
name pk ++ name pk
obj1 1 ++ obj1 1
obj2 2 ++ obj3 2
obj3 3 ++
在计划的任务运行之后,我们将拥有这个:
local server
name pk ++ name pk
obj1 1 ++ obj1 1
obj2 2 ++ obj3 2
obj3 3 ++ obj2 3
看看这有多容易失控?为了解决这个问题,每个被跟踪的模型必须拥有某种唯一标识符,并且您需要以某种方式告诉Track 模型如何遵循它。真是头疼。最好不要在本地保存东西,而是将所有内容链接在一起