【问题标题】:Iterating through all foreign key related children of an abstract django model遍历抽象 django 模型的所有外键相关子项
【发布时间】:2014-09-04 16:05:57
【问题描述】:

我正在尝试遍历给定 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)如果有人可以向我展示如何使用它来完成我的任务的示例,我将非常感激。

谢谢。

【问题讨论】:

  • 在 Django 中定义抽象模型时,添加class Metaabstract = True 以防止 Django 创建数据库表。见docs.djangoproject.com/en/dev/topics/db/models/…
  • 是的,我在我的实际代码中有这个,只是这里没有。 (否则 .clusteringdata_set.all() 不会抛出错误,而是不会迭代任何东西(理想的))感谢@Joren 的提醒,我现在已将其编辑到我的原始帖子中。
  • 关于 pre_delete 信号,我选择重写 .delete() 函数,因为这似乎比在模型本身以外的地方处理信号更透明和可维护。

标签: python django python-2.7


【解决方案1】:

您可以使用 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()

【讨论】:

  • 哇,这个答案非常清晰透彻。比我所希望的还要多。谢谢@axelcdv!
猜你喜欢
  • 2010-11-04
  • 2018-04-22
  • 2011-11-23
  • 2016-04-19
  • 1970-01-01
  • 2016-06-24
  • 2012-05-07
  • 2011-01-15
  • 1970-01-01
相关资源
最近更新 更多