迭代抽象django模型中所有与外键相关的子项

时间:2014-09-04 16:05:57

标签: python django python-2.7

我正在尝试迭代给定django模型的所有外键相关模型。可能有13种不同的模型可能具有外键关系,但它们都继承了相同的抽象基类。我想在一个循环中遍历所有这些,以修改属于父类的字段。我的代码看起来像。

class ClusteringRecord(models.Model):
    """
    An abstract class to hold data that is repeated from model to model
    """

    wip = models.ForeignKey(
        ClusteringWIP, null=True, on_delete = models.SET_NULL)
    cluster_comment = models.CharField(max_length=1000, null=True, blank=True)

    class Meta:
        abstract = True


class ClusteringNPIRecord(ClusteringRecord):
    """Django Model object representing an NPI record that was not able to be
    clustered by automatic clustering logic in the database.
    """

    npi_id = models.CharField(max_length=1000, null=True)
    npi_number = models.CharField(max_length=1000, null=True)


class ClusteringDEARecord(ClusteringRecord):
    """Django Model object representing a DEA record that was not able to be
    clustered by automatic clustering logic in the database.
    """

    dea_id = models.CharField(max_length=1000, null=True)
    dea_number = models.CharField(max_length=1000, null=True)

我想要使用的代码如下所示:

def cancel_and_return(request, list_type, wip_id):
    """
    destroys lock object and returns user to most recent version of worklist
    :param request:
    :param wip_id: pk of current ClusteringWIP
    :return: HTTP redirect to worklist home
    """
    wip = ClusteringWIP.objects.select_related().get(pk=wip_id)
    for record in wip.clusteringrecord_set.all():
        record.cluster_comment = None
        record.save()
    wip.delete()

然而它告诉我clusteringrecord_set无效。有没有办法迭代这个与提供者相关的类的所有子节点?否则我使用13个不同的for循环来实现这一目标,并公然违反DRY方法。

实际上,这个基类适用于可能使用ClusteringWIP作为外键的所有13个模型,因此简单地遍历所有相关(无论类)将完成相同的事情,所以如果这恰好是通过各种方式让我知道最好的方法。但我仍然很想知道上述问题的答案,无论将来的用法如何。

此外,在我寻找这个答案的旅行中,我偶然发现了一个django pre_delete信号,这个信号似乎更符合我在这里尝试做的事情(即无效的'cluster_comment'字段关于删除ClusteringWIP的相关模型)如果有人可以告诉我如何使用它来完成我的任务,我将非常感激。

谢谢。

1 个答案:

答案 0 :(得分:3)

您可以使用ClusteringRecord的子类()方法。例如:

@classmethod
def related_set(cls, wip):
  classes = cls.__subclasses__()
  return sum([c.objects.filter(wip=wip).all() for c in classes], [])

并使用它来迭代你的对象。

对于pre_delete信号,你需要在你的应用程序中有一个signals.py文件,它看起来像这样:

from django.db.models.signals import pre_delete, post_delete
from django.dispatch import receiver

from myapp.models import ClusteringWIP

@receiver(pre_delete, sender=ClusteringWIP)
def on_instance_delete(sender, instance, **kwargs):
    instance.on_pre_delete()

使用ClusteringWIP :: on_pre_delete方法:

def on_pre_delete(self):
  for record in ClusteringRecord.related_set(self):
    record.cluster_comment = None
    record.save()