【问题标题】:Cascade delete of model with GenericForeignKey without using GenericRelation使用 GenericForeignKey 级联删除模型而不使用 GenericRelation
【发布时间】:2021-09-30 19:33:01
【问题描述】:

我正在创建一个可重复使用的 django 应用程序,其中包含一个带有 GenericForeignKey 的模型,我需要将其级联删除。

此模型可以附加到任何其他模型。我无法控制目标模型类,因为它在应用程序之外。这意味着我不能向其中添加 GenericRelation 字段,也不能强制用户添加它,因为目标可能在另一个第三方应用程序中。

假设我们有这样的模型(无法控制 PostPostGroup):

class Tag(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    object = GenericForeignKey()

class PostGroup(models.Model):
    title = models.CharField(max_length=255)

class Post(models.Model):
    title = models.CharField(max_length=255)
    group = models.ForeignKey(PostGroup, on_delete=models.CASCADE)

如果PostGroup查询集被删除,有没有办法删除Tag

例如不仅是post_group.delete(),还有PostGroup.objects.delete()

【问题讨论】:

    标签: django cascading-deletes generic-foreign-key django-generic-relations generic-relations


    【解决方案1】:

    您可以使用pre_delete 信号来实现:

    from django.db.models.signals import pre_delete
    from django.dispatch import receiver
    
    
    @receiver(pre_delete) # add relevant sender to signal (not mandatory)
    def post_group_deleted(sender, instance, using, **kwargs):
        # Query tags with the instance of PostGroup and delete them
        if isinstance(instance, Tag):
            return
    
        Tag.objects.filter(
            content_type=ContentType.objects.get_for_model(instance),
            object_id=instance.pk
        ).delete()
    

    参见文档here

    与 ForeignKey 不同,GenericForeignKey 不接受 on_delete 参数来自定义此行为;如果需要,您可以通过不使用 GenericRelation 来避免级联删除,并且可以通过 pre_delete 信号提供替代行为。

    【讨论】:

    • 我不能使用PostGroup,因为它在我的应用程序之外。它可以安装在其他人的项目中,并可以连接到那里的任何模型。
    • 我将您的回复编辑为实际有效。尽管如此,对于每个实例都单独调用它是非常无效的。
    • 你的问题说 - 删除 Tag 以防 PostGroup 查询集被删除,所以信号应该是发件人 PostGroup
    • 请仔细阅读。我的问题是我无法控制 Post 或 PostGroup。我无法导入它们,因为这是可重复使用的应用程序,并且这些模型不在其中。请删除发件人,以便它至少是有效的答案。
    • 谢谢。实际上不需要添加相关的发件人。正如问题所说,我无法访问发件人。我已经对其进行了测试,并且此代码在没有发件人的情况下也可以正常工作。如果有人有更有效的解决方案,我将等待此案。如果不是,将其标记为正确的。
    猜你喜欢
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 2018-01-02
    • 2021-12-08
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 2014-07-17
    相关资源
    最近更新 更多