我有两个模型(简化):
class Place(OrderedModel):
name = models.CharField(max_length=100)
class Team(models.Model):
name = models.CharField(max_length=100)
places = models.ManyToManyField(Place, blank=True)
假设有Place
的十个实例。但只有Team
的五个实例。我想按Place
中的条目顺序返回一个布尔值列表,其中True
表示Team.places
包含该位置,False
(显然)表示它没有吨。 Team.places
字段没有特定的顺序。
在以下示例中,Team
包含前四个Place
个对象的实例,最后一个包含places
字段:
[True, True, True, True, False, False, False, False, False, True]
我在Team模型上使用此方法解决了这个问题:
class Team(models.Model):
...
def done(self):
"""
Returns a list of Booleans, one for each place
in order. True means that the team has found the
place. False, that they have not.
"""
places = Place.objects.all()
return [p in self.places.all() for p in places]
它有效,但似乎非常低效。它使(我相信)两个不同的SQL查询,然后是列表理解。有没有更有效的方法来解决这个问题?
我最终这样做了:
def done(self):
"""
Returns a list of Booleans, one for each place
in order. True means that the team has found the
place. False, that they have not.
"""
sql = '''SELECT P.id, (TP.id IS NOT NULL) AS done
FROM qrgame_place P
LEFT OUTER JOIN qrgame_team_places TP
ON P.id = TP.place_id AND TP.team_id = %s'''
places = Place.objects.raw(sql, [self.id])
for p in places:
yield bool(p.done)
答案 0 :(得分:1)
您需要此SQL查询:
SELECT P.id, (TP.id IS NOT NULL) AS done
FROM myapp_place P
LEFT OUTER JOIN myapp_team_places TP
ON P.id = TP.place_id AND TP.team_id = %s
(您还需要添加ORDER BY
子句以按照您想要的顺序返回Place
个对象,但由于我看不到您模型的那部分,我不能告诉那个条款应该是什么样的。)
我不知道如何使用Django的对象关系映射系统表达此查询,但您始终可以使用raw SQL query运行它:
>>> sql = ''' ... as above ... '''
>>> places = Place.objects.raw(sql, [team.id])
>>> for p in places:
... print p.id, bool(p.done)
...
1 True
2 True
3 False
答案 1 :(得分:1)
更优化的解决方案是:
def done(self):
places = Place.objects.values_list('pk', flat=True)
team_places = self.places.values_list('pk', flat=True)
return [place in team_places for place in places]