推广使用信号

时间:2018-03-20 21:53:39

标签: python django django-cms django-signals

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

一个小故事

在完成我的应用程序的设计之后,使用(诚实地令人印象深刻)PlaceholderFields我注意到,如果我删除了包含其中一个字段的模型,它将留下它的后面的' s删除生成它的模型实例后插件/占位符。这令我感到惊讶,所以我联系了他们,根据django-cms的开发团队:

  

根据设计,django CMS PlaceholderField不会为您删除插件。   如果要删除占位符内容并在删除引用它的对象时删除占位符本身,可以通过在占位符实例上调用clear()方法然后调用delete()方法< / p>

因此,在删除模型之前预计会发生这种情况,我首先想到的是使用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

我希望这可以毫无问题地工作,但是当我从[placeholder].delete()接收方调用的方法中调用pre_delete方法时,我会遇到一些奇怪的行为。

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

我使用django / django-cms相对较新,所以我可能会忽视某些事情或者从根本上误解导致这种循环的原因,但是有没有办法实现我的目标。&#39 ;我试图使用pre_delete信号做到这里?或者我这样做不好?

任何建议都将不胜感激。

1 个答案:

答案 0 :(得分:0)

经过几天的斗争,我相信我找到了一种自动删除占位符和第三方应用模型的方法。

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

此外,我需要处理也包含自己占位符的子FK对象。经过多次试验和错误后,确保删除子对象占位符的最佳行动方案(我可以找到)如下:

  • 定义执行迭代删除的查询集。 (非理想,但只能确保执行以下步骤)

    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()
    

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

注意:这对我来说似乎不直观,但删除placeholders后需要删除模型本身,至少在对象中有子关系的情况下删除。

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

我完全没想到。 idk如果这是删除占位符的预期功能,但确实如此。由于占位符在删除对象( by design )之前仍然包含在数据库中,因此在调用super(...).delete()

之后处理它的删除应该没有问题

如果任何人有更好的解决方案来解决这个问题,请随时发表评论,让我知道我的愚蠢行为。 这是我在运行调试器和跟踪删除过程几个小时之后想出的最好的结果。