假設我有一個模型,其中包含一個Things表和一個名為ThingRelations. 它不應該是可以洗掉Thing的時候有ThingRelations指向它,而當沒有更多ThingRelations指向給定的Thing,它應該被洗掉。我目前正在嘗試用signals.post_delete這樣的方式實作它:
from django.db import models
class ThingRelation(models.Model):
first_thing = models.ForeignKey('Thing', on_delete=models.PROTECT)
second_thing = models.ForeignKey('Thing', on_delete=models.PROTECT)
class Thing(models.Model):
name = CharField(max_length=260)
@receiver(models.signals.post_delete, sender=ThingRelation)
def check_relation_and_delete(sender, instance, *args, **kwargs):
for thing_id in [instance.first_thing, instance.second_thing]:
first_thing_match = ThingRelation.objects.filter(first_thing=thing_id).exists()
second_thing_match = ThingRelation.objects.filter(second_thing=thing_id).exists()
if not first_thing_match and not second_thing_match:
Thing.objects.get(pk=thing_id).delete()
這是查找和洗掉孤立的最有效方法Things嗎?一般來說,我對資料庫很陌生,但是在一次洗掉許多物件時Things,每次洗掉的表(可能很大)過濾四次會不會很ThingRelation慢?是否有某種 SQL 或 Django 功能可以使此代碼不會在批量操作中為每個物件運行?
uj5u.com熱心網友回復:
signals.py 不是為批量操作而設計的。此外,它們通常被認為是一種反模式,因為在您嘗試除錯某些邏輯時難以跟蹤它們。
我寧愿建議您在這里嘗試常規方法。一個可能對你有幫助的例子:
def remove_orphaned_things():
orphaned_things = Thing.objects.filter(
~Q(id__in=ThingRelation.objects.values_list('first_thing_id').filter(
first_thing_id=OuterRef('pk')
) | ~Q(id__in=ThingRelation.objects.values_list('second_thing_id').filter(
second_thing_id=OuterRef('pk')
)
).delete()
此功能洗掉所有孤立Thing的。所以剩下的就是我們需要正確呼叫它。
最簡單直接的方法是將其組織成無盡的while-true例程,sleep并將其作為守護程式運行。例如:
from datetime import time
from django.core.management import BaseCommand
# Also some import of `remove_orphaned_things`
class Command(BaseCommand):
def handle(self, *args, **options):
while True:
remove_orphaned_things()
time.sleep(300)
所以它幾乎每 5 分鐘執行一次。它可以以supervisor(更好)或tmux(更糟)之類的方式運行,因此您可以確定它始終在運行。
更好的方法是使用類似的東西periodic來編排它。這是一個安裝指南(您還需要 RabbitMQ)和一個如何組織它的小例子:
@dramatiq.actor(periodic=cron('*/5 * * * *'), max_retries=0)
def remove_orphaned_things():
# Exact the same code of `remove_orphaned_things`
祝你好運!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/389618.html
