1

我正在使用 Django 3 和 Python 3.8。我有以下型号...

class Coop(models.Model):
    objects = CoopManager()
    name = models.CharField(max_length=250, null=False)
    types = models.ManyToManyField(CoopType, blank=False)
    addresses = models.ManyToManyField(Address)
    enabled = models.BooleanField(default=True, null=False)
    phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
    email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
    web_site = models.TextField()

注意“电话”和“电子邮件”外键列。一旦它们成为孤儿,是否有任何 Django/Python 特定的方法可以自动删除 ContactMethod 记录?也就是说,如果我有我的模型,其中填充了两列,然后运行

coop.phone = None
coop.save(update_fields=['phone'])

有什么东西会自动删除孤立的记录吗?或者我猜想实现这一目标的标准方法是什么?我正在运行 MySql 8 db,但我更愿意排除特定于 DB 的解决方案。

4

1 回答 1

1

您可以定义 Django 信号,但 Django 信号并不总是运行。尤其是当您进行执行批量更新或批量删除的 ORM 调用时。例如,如果您使用with设置所有s的email和/或,那么它将不会运行信号,因此某些s 可以在没有触发信号的情况下被孤立。phoneCoopenabled=FalseCoop.objects.filter(enabled=False).update(email=None, phone=None)post_saveContactMethod

即使您可以使用信号,也可能不是一个好主意。也可以在没有 ORM 查询的情况下更新数据库,例如数据库管理员通过PhpMyAdmin前端。因此,即使在 Django 中是可能的,这也意味着人们仍然可以通过另一种方式孤立对象。此外,这样的信号会同时处理一个ContactMethod,这比批量ContactMethod删除s更昂贵。

您可以创建一个可以定期运行的管理命令[Django-doc],例如每天一次。您可以在您的定义这样的管理命令app

app/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            remove_orphan_contactmethod.py
    urls.py
    views.py

在 中app/management/commands/remove_orphan_contactmethod.py,您可以检测并移除这些ContactMethod对象:

from django.core.management.base import BaseCommand, CommandError
from app.models import ContactMethod

class Command(BaseCommand):
    help = 'Remove ContactMethods not referenced through email or phone'

    def handle(self, *args, **options):
        items = ContactMethod.objects.filter(
            contact_phone=None, contact_email=None
        ).delete()
        number = items.get('app.ContactMethod', 0)
        self.stdout.write(self.style.SUCCESS(f'Removed {number} ContactMethod object(s)'))

然后你可以运行:

python3 manage.py remove_orphan_contactmethods

运行命令。例如,您可以指定一个cronjob [wiki]或其他一些重复任务机制来以特定频率执行此命令。

于 2020-08-12T16:30:08.533 回答