使用我当前的示例

时间:2016-06-10 02:45:20

标签: django

说我有这样的模型:

class Alert(models.Model):
    datetime_alert = models.DateTimeField()
    alert_type = models.ForeignKey(Alert_Type, on_delete=models.CASCADE)
    dismissed = models.BooleanField(default=False)
    datetime_dismissed = models.DateTimeField(null=True)
    auid = models.CharField(max_length=64, unique=True)
    objects = Get_Or_None_Manager()

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

class Entity_To_Alert_Map(models.Model):
    entity = models.ForeignKey(Entity)
    alert = models.ForeignKey(Alert, related_name='Entity_To_Alert_Map')
    relationship = models.ForeignKey(Entity_To_Alert_Relationship,
                                     on_delete=models.CASCADE)

class Entity_To_Alert_Relationship(models.Model):
    relationship_label = models.CharField(max_length=45, unique=True)

这个想法是通过使用Entity_Associated_With_the_Alert完成的映射,可以将警报与许多实体相关联。据我了解,Alert.objects.prefetch_related('Entity_To_Alert_Map')将获取与其与Entity_To_Alert_Map的多个匹配关联的Alert对象(一个Alert可能有多个实体映射到它)。但跑完后:

for alert in Alert.objects.prefetch_related('Entity_To_Alert_Map'):
    print alert.Entity_To_Alert_Map

我明白了:

My_App.Entity_To_Alert_Map.None

使用数据库验证我可以确认Entity_To_Alert_Map确实具有有效条目。有人可以帮我理解预取的工作原理吗?

只是为了澄清,这是我正在尝试重新创建的内容:

for alert in Alert.objects.filter(dismissed=False).prefetch_related('Entity_To_Alert_Map'):
    alert_d = {}
    alert_d['datetime'] = str(alert.datetime_alert)
    alert_d['entities'] = []
    for related_entity in Entity_To_Alert_Map.objects.filter(alert=alert).select_related().all():
        entity = {}
        entity['type'] = related_entity.entity.entity_type.entity_type_label
        entity['label'] = related_entity.entity.label

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

但我很确定这是错误的做法。

1 个答案:

答案 0 :(得分:2)

我将推荐使用关于M2M关系的直通模型来实现这一点。

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)

对于你正在尝试重新创建的内容,我猜它相当接近,但我认为你的prefetch_related调用没有任何改进,这是一个简单的例子:

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)

这是一个更好的解决方案,使用django.db.models.Prefetch类来完成所有这一行,尽管理解起来有点复杂。我建议您阅读django.db.models.Prefetchprefetch_related(...)以了解其工作原理。

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)

我认为最后一个例子是我能提出的最优化的版本。