[Answered ]-Understanding prefetch_related with my current example

2👍

I’m going to recommend and give a rough example of implementing this using a through model on the M2M relation.

class Alert(models.Model):
    datetime_alert = models.DateTimeField()
    dismissed = models.BooleanField(default=False)
    datetime_dismissed = models.DateTimeField(null=True)
    auid = models.CharField(max_length=64, unique=True)
    entities = models.ManyToManyField(to='Entity', through='AlertEntity')


class Entity(models.Model):
    label = models.CharField(max_length=255, unique=True)


class AlertEntityRelationship(models.Model):
    permission_label = models.CharField(max_length=45, unique=True)


class AlertEntity(models.Model):
    entity = models.ForeignKey(Entity)
    alert = models.ForeignKey(Alert)
    alertentityrelationship = models.ForeignKey(AlertEntityRelationship, on_delete=models.CASCADE)

And for what you’re trying to recreate I guess it’s fairly close, but I don’t think you are getting any improvement out of your prefetch_related call, here’s a naive example:

for alert in Alert.objects.filter(dismissed=False):
    alert_d = {}
    alert_d['datetime'] = str(alert.datetime_alert)
    alert_d['entities'] = []
    for related_entity in alert.alertalertentity_set.filter().select_related('alert', 'entity'):
        entity = {}
        entity['type'] = related_entity.entity.entity_type.entity_type_label  # Don't know where you're getting entity_type from
        entity['label'] = related_entity.entity.label

        alert_d['entities'].append(entity)
    response_data['alerts'].append(alert_d)

Here is a much better solution using the django.db.models.Prefetch class to do it all one line, though it is a bit more complicated to understand. I recommend reading the django.db.models.Prefetch and prefetch_related(...) to understand how it works.

for alert in Alert.objects.filter(dismissed=False).prefetch_related(Prefetch(lookup='alertentity_set', queryset=AlertEntity.objects.filter().select_related('entity'), to_attr='prefetched_alertentity_list'):
    alert_d = {}
    alert_d['datetime'] = str(alert.datetime_alert)
    alert_d['entities'] = []
    for related_entity in alert.prefetched_alertentity_list:
        entity = {}
        entity['type'] = related_entity.entity.entity_type.entity_type_label  # Don't know where you're getting entity_type from
        entity['label'] = related_entity.entity.label

        alert_d['entities'].append(entity)
    response_data['alerts'].append(alert_d)

I think this last example is the most optimized version I can come up with.

Leave a comment