Iterate over all foreign key related children of django abstract model

I am trying to iterate all foreign key related models for a given django model. There are potentially 13 different models that can have a foreign key relationship, but they all inherit the same abstract base class. I want to iterate over all of them in one loop to change a field owned by 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 tells me that clusteringrecord_set is invalid. Is there a way to replicate all of the provider-related children of this class? otherwise I am using 13 different loops to do this and in gross violation of the DRY methodology.

As it happens, this base class applies to all 13 models that can use ClusteringWIP as a foreign key, so simply repeating all related (regardless of class) will do the same thing, so if that happens, the best way to do it. by all means let me know. But I would still be interested to know the answer to this question, regardless of future use.

Also, in my travels looking for this answer, I stumbled upon the django pre_delete signal , which seems to be more consistent with what I'm trying to do here (this negates the "cluster_comment" field of any related models when ClusteringWIP is deleted). If someone can show me an example of how this can be used to accomplish my task, I would be very grateful.

Thank.

+3


source to share


1 answer


You can use the subclass () method of 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 that to iterate over your objects.

For the pre_delete signal, your application must have a signal.py file that looks like this:



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

      

Using the ClusteringWIP :: on_pre_delete method, for example:

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

      

+2


source







All Articles