简体   繁体   English

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

[英]Iterating through all foreign key related children of an abstract django model

I am trying to iterate through all foreign key related models for a given django model. 我试图迭代给定django模型的所有外键相关模型。 There are potentially 13 different models that might have foreign key relationships but they all inherit the same abstract base class. 可能有13种不同的模型可能具有外键关系,但它们都继承了相同的抽象基类。 I want to iterate through all of them in one loop to modify a field that belongs to the parent class. 我想在一个循环中遍历所有这些,以修改属于父类的字段。 My code looks like. 我的代码看起来像。

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)

The code I want to use looks like this: 我想要使​​用的代码如下所示:

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

however it is telling me that clusteringrecord_set is not valid. 但它告诉我clusteringrecord_set无效。 Is there a way to iterate through all of the children of this class related to the provider? 有没有办法迭代这个与提供者相关的类的所有子节点? otherwise I am using 13 different for loops to accomplish this and flagrantly violating DRY methodology. 否则我使用13个不同的for循环来实现这一点并公然违反DRY方法。

As it happens, this base class applies to all of the 13 models that could be using ClusteringWIP as a foreign key so simply iterating through all related (regardless of class) would accomplish the same thing, so if this happens to be the best way to do that, by all means let me know. 实际上,这个基类适用于可能使用ClusteringWIP作为外键的所有13个模型,因此简单地遍历所有相关(无论类)将完成相同的事情,所以如果这恰好是最好的方法这样做,请务必告诉我。 But I would still be curious to know the answer to the above question regardless for future usages. 但我仍然很想知道上述问题的答案,无论将来的用法如何。

Also, In my travels looking for this answer I have stumbled across a django pre_delete signal that seems to be more along the lines of what I am attempting to do here (that is nullify 'cluster_comment' field of any related models on deletion of a ClusteringWIP) If someone could show me an example on how this might be used to accomplish my task I would be very thankful. 此外,在我寻找这个答案的旅行中,我偶然发现了一个django pre_delete信号, 这个信号似乎更符合我在这里尝试做的事情(即删除了ClusteringWIP时,任何相关模型的'cluster_comment'字段无效如果有人能告诉我一个如何用它来完成我的任务的例子,我将非常感激。

Thank you. 谢谢。

You could use the subclass () method of the ClusteringRecord. 您可以使用ClusteringRecord的subclass ()方法。 For example: 例如:

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

And use this to iterate over your objects. 并使用它来迭代你的对象。

For the pre_delete signal, you need to have a signals.py file in your application, that could look like that: 对于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()

With the ClusteringWIP::on_pre_delete method like so: 使用ClusteringWIP :: on_pre_delete方法如下:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM