简体   繁体   中英

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. There are potentially 13 different models that might have foreign key relationships but they all inherit the same abstract base class. 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. 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.

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. 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.

Thank you.

You could use the subclass () method of the ClusteringRecord. 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:

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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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