2014-01-22 15 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)