1

我有这两个模型(简化):

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)

假设有 10 个实例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)
4

2 回答 2

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 的对象关系映射系统来表达这个查询,但你总是可以使用原始 SQL 查询来运行它:

>>> 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
于 2013-04-09T11:35:56.023 回答
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]
于 2013-04-09T14:29:00.860 回答