说我有这样的模型:
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)
但我很确定这是错误的做法。
答案 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.Prefetch
和prefetch_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)
我认为最后一个例子是我能提出的最优化的版本。