2014-01-22 18 views
0

我创建了一个模型,指的是第三方包内的模型--Celery(CrontabSchedule和PeriodicTask)。我的模型(我们称之为ScheduledRun)将包含PeriodicTask的外键。如何清理Django孤儿外键值?

我知道如果我删除一个外键本身级联删除将发生,并且指向该外键的父母也将被删除。 (除非被on_delete覆盖...)

但是由于我在PeriodicTask的FK指向ScheduledRun的情况,当我删除ScheduledRun时,PeriodicTask不会被自动删除。 (也不应该是因为可能有其他模型指向这个外键!)

那么我怎样才能清理孤儿的PeriodicTasks - 即当没有模型实例指向它时。

我可以添加一个post_delete信号,并检查它这样(这个例子中删除不与周期性任务了有关外来CrontabSchedules:

# periodictask below is actually a related periodictask_set, 
# but in Django you refer to the empty set as 'periodictask=None' 
CrontabSchedule.objects.filter(id=instance.crontab.id, 
           periodictask=None).delete() 

但我不能保证不会有其他相关的关系,可能会导致级联下降。

我能继承表PeriodicTask作为ScheduledRun ....但宁可不集成了紧密的第三方模型。

这几乎就像我想要一个.delete(do_not_cascade = True),并且如果它由于约束而失败,则忽略失败。如果成功了,那它就是一个孤儿。 on_delete = DO_NOTHING与此类似,但我只希望它只在上暂时为作为单个删除的范围,我不想修改第三方包。

是否有其他更好的方法来处理这个问题?

回答

0

这是我的解决方案...似乎它可能足够强大。我的目标是只删除外键值,如果没有其他模型实例仍然引用它。

所以,我会尽量为删除基于各相关的密钥值是无:

# This is a class method to my ScheduledRun class that has 
# a foreign key to a PeriodicTask. PeriodicTask has a 
# FK to a CrontabSchedule, which I'd like to "trim" 
# if nothing points to that FK anymore. 
@classmethod 
def _post_delete(cls, instance, **kwargs): 
    instance.periodic_task.delete() 
    # Delete the crontab if no other tasks point to it. 
    # This could cause a cascade if we don't check all related... 
    filter = dict(id=instance.crontab.id) 
    for related in instance.crontab._meta.get_all_related_objects(): 
     filter[related.var_name] = None 
    assert('id' in filter) 
    assert('schedule' in filter) 
    assert('periodictask' in filter) 
    CrontabSchedule.objects.filter(**filter).delete() 

这将是更容易,如果我可以说:

instance.crontab.delete(NO_CASCADE=True)