使用信号一般化删除占位符字段 django-cms

Generalizing deletion of placeholderfield django-cms with signals

我目前在 django-cms 工作,并在我的几个模型中使用 PlaceholderField。因此,我想概括这个过程以避免必须覆盖每个模型的删除,并为每种类型的对象添加一个专门的管理器来处理删除。

一点背景故事:

在稍微设计我的应用程序并使用(老实说令人印象深刻的)PlaceholderFields 之后,我注意到如果我删除了一个包含这些字段之一的模型,它会留下它的 plugins/placeholder 删除生成它的模型实例后。这让我很吃惊,所以我联系了他们,根据 django-cms 的开发团队:

By design, the django CMS PlaceholderField does not handle deletion of the plugins for you. If you would like to clear the placeholder content and remove the placeholder itself when the object that references it is deleted, you can do so by calling the clear() method on the placeholder instance and then the delete() method

因此,由于预计这会在删除模型之前发生,我的第一个想法是使用 django 提供的 pre_delete 信号。所以我设置了以下内容:

我的问题

models.py


 class SimplifiedCase(models.Model):

     #... fields/methods ...
    my_placeholder_instance= PlaceholderField('reading_content')  # ****** the placeholder 

    #define local method for clearing placeholderfields for this object 
    def cleanup_placeholders(self):
        # remove any child plugins of this placeholder
        self.my_placeholder_instance.clear()

        # remove the placeholder itself
        self.my_placeholder_instance.delete()  


# link the reciever to the section
signals.pre_delete.connect(clear_placeholderfields, sender=SimplifiedCase)

signals.py


# create a generalized reciever 
#(expecting multiple models to contain placeholders so generalizing the process)
def clear_placeholderfields(sender, instance, **kwargs):
    instance.cleanup_placeholders()  # calls the newly defined cleanup method in the model

我原以为它可以正常工作,但是当我从 pre_delete 接收器调用的方法中调用 [placeholder].delete() 方法时,我得到了一些奇怪的行为。

出于某种原因,在我的 cleanup_placeholders 方法中调用占位符的 delete() 方法时,它会再次触发父级的 pre_delete 方法。导致递归循环

我对使用 django/django-cms 比较陌生,所以可能我忽略了某些东西或从根本上误解了导致此循环的原因,但是有没有办法使用pre_delete 信号?还是我做得不好?

如有任何建议,我们将不胜感激。

经过几天的努力,我相信我找到了一种自动删除占位符和第 3 方应用程序模型的方法。

尝试失败: - 由于我的问题中提到的递归,信号没有用,这是由占位符的所有相关模型在处理连接模型的 pre_delete 事件期间触发 pre_delete 事件引起的。

此外,我还需要处理 child FK-objects,它们也包含自己的占位符。经过反复试验,确保删除 child objects 的占位符的最佳行动方案(我能找到)如下:

  • 定义一个执行迭代删除的查询集。 (non-ideal,但只能保证后面步骤的执行)

    class IterativeDeletion_Manager(models.Manager):
        def get_queryset(self):
            return IterativeDeletion_QuerySet(self.model, using=self._db)
    
        def delete(self, *args, **kwargs):
            return self.get_queryset().delete(*args, **kwargs)
    
    class IterativeDeletion_QuerySet(models.QuerySet):
    
        def delete(self, *args, **kwargs):
    
            with transaction.atomic():
    
                # attempting to prevent 'bulk delete' which ignores overridden delete
                for obj in self:
                    obj.delete()
    
  • 设置包含 PlaceholderField 的模型以使用新定义的管理器。

  • 覆盖任何包含占位符字段的模型的删除方法,以处理占位符的删除 AFTER 连接模型的删除。 (即非官方 post_delete 活动)

    class ModelWithPlaceholder(models.Model):
    
        objects = IterativeDeletion_Manager()
    
        # the placeholder
        placeholder_content = PlaceholderField('slotname_for_placeholder')
    
        def delete(self, *args, **kwargs):
    
            # ideally there would be a method to get all fields of 'placeholderfield' type to populate this
            placeholders = [self.placeholder_content]
    
            # if there are any FK relations to this model, set the child's 
            # queryset to use iterative deletion as well, and manually 
            # call queryset delete in the parent (as follows)
    
            #self.child_models_related_name.delete()
    
            # delete the object
            super(ModelWithPlaceholder,self).delete(*args, **kwargs)
    
            # clear, and delete the placeholders for this object 
            # ( must be after the object's deletion )
            for ph in placeholders:
                ph.clear()
                ph.delete()
    

使用此方法,我已验证每个 object 的 child PlaceholderField 与 object 一起使用管理界面、查询集删除、直接删除删除。 (至少在我的使用案例中)

注意:这对我来说似乎不直观,但是 placeholders 的删除需要在删除模型本身之后发生,至少在具有 child关系中的object被删除。

这是因为调用 placeholder.delete() 会触发删除所有与包含 PlaceholderField 的 deleted-model 相关的模型。

我完全没想到。 idk 如果这是删除占位符的预期功能,但确实如此。由于占位符在删除 object 之前仍包含在数据库中( 设计 ),因此在调用 [= 之后处理它的删除应该没有问题20=]

如果有人对此问题有更好的解决方案,请随时发表评论并让我知道我的愚蠢行为。 这是我在通过调试器和跟踪删除过程数小时 运行 后所能想到的最好结果。