如何在Django ORM中进行多次连接和聚合?
我是Django/Python/ORM的新手!我对ORM中的连接(joins)有点搞不清楚。
这是我的模型:
class Courts(models.Model):
id = models.AutoField(primary_key=True)
location_name = models.CharField(max_length=100)
number = models.IntegerField()
def __unicode__(self):
return "%s %s %s" % (self.id, self.location_name, self.number)
class Matches(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateTimeField()
court = models.ForeignKey(Courts)
def __unicode__(self):
return "%s %s" % (self.id, self.date)
class Participants(models.Model):
id = models.AutoField(primary_key=True)
match = models.ForeignKey(Matches)
userid = models.ForeignKey(User)
games_won = models.IntegerField()
def __unicode__(self):
return "%s %s %s" % (self.id, self.games_won, self.userid)
第一步是把所有的“参与记录”整理成下面这样的输出:
[match_id] [date] [userid] [games_won] [court_location_name] [court_number]
1 01-01-2011 mike 6 Queen 5
1 01-01-2011 chris 4 Queen 5
2 01-02-2011 bob 3 Queen 6
2 01-02-2011 joe 4 Queen 6
3 01-03-2011 jessie 5 Queen 2
3 01-03-2011 john 5 Queen 2
我应该写什么样的ORM脚本来实现这个?我对ORM中简单的连接是怎么工作的都很困惑,更别提要把三个表结合在一起了。
接下来,我想把数据汇总成最终看起来像这样的格式:
[match_id] [date] [player1] [player2] [p1wins] [p2wins] [game_winner] [court_location_name] [court_number]
1 01-01-2011 mike chris 6 4 mike Queen 5
2 01-02-2011 bob joe 3 4 joe Queen 6
3 01-03-2011 jessie john 5 5 draw Queen 2
这会改变我在视图中写的ORM脚本吗?这是我需要放在视图里还是模板里呢?
更新:
我想我可以使用 select_related()。所以我试了 Participants.objects.select_related(),然后得到了这个SQL语句:
SELECT "squash_participants"."id", "squash_participants"."match_id", "squash_participants"."userid_id", "squash_participants"."games_won", "squash_matches"."id", "squash_matches"."date", "squash_matches"."court_id", "squash_courts"."id", "squash_courts"."location_name", "squash_courts"."number", "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "squash_participants" INNER JOIN "squash_matches" ON ("squash_participants"."match_id" = "squash_matches"."id") INNER JOIN "squash_courts" ON ("squash_matches"."court_id" = "squash_courts"."id") INNER JOIN "auth_user" ON ("squash_participants"."userid_id" = "auth_user"."id"
这看起来更像我想要的结果。现在我不知道怎么把这些数据提取到模板里。
更新2:
我的视图是这样的:
def index(request):
matches_list = Participants.objects.all()
return render_to_response('squash/base_matches.html', {'matches_list': matches_list}, context_instance =
RequestContext(request))
return HttpResponse(output)
而我的模板是这样的:
{% for matches in matches_list %}
<tr>
<td>{{ matches.id }}</td>
<td>{{ matches.date|date:"d-m-Y" }}</td>
<td>{{ matches.date|date:"G:i" }}</td>
</tr>
{% endfor %}
它能正确显示所有的 Participants.id
,但比如说比赛的ID、日期或场地却没有显示出来。
1 个回答
你提到的有几个“事情”:
- 定义“id”这个主字段其实没必要,反而会让人困惑,因为Django会自动生成它。
- 给你的模型起名字时,最好用单数形式(比如用Match而不是Matches等)。这样做可以让Django更好地处理单数和复数的关系。这也很合理,因为Match这个类的对象代表的是一场比赛,而不是多场比赛;如果要处理多场比赛,你可以用模型管理器:Match.objects。
- 你的“Participants”模型实际上是一个中间的多对多关系表,你可以在“Matches”模型中明确声明这一点,具体可以参考这里。
关于你的JOIN问题,我支持S. Lott的观点,我在StackOverflow上看到过 - 在Django中不应该考虑JOIN,因为Django的ORM(“O”代表“对象” - 把SQL映射到对象上并不是一件简单的事)并不是这样工作的。你应该专注于完成你的工作,只有在确实需要的情况下,比如性能问题,才考虑使用JOIN。
最后,关于你的问题的答案:
Participants.objects.all()
:-)
你可以通过使用select_related()来提高性能,如果需要的话,还可以使用order_by()来进行排序。
至于聚合,其他人可能会给出一个简单的解决方案,但我现在看不到。不过,你可以在“Matches”模型中添加这个:
players = models.ManyToManyField(User, through='Participants')
然后你可以用最简单的方式获取比赛:
Matches.objects.all()
这样返回的每个元素都会有“players”属性。
更新:
要把数据传递给模板,你只需要把它添加到模板渲染的上下文中:
http://docs.djangoproject.com/en/1.2/ref/templates/api/#rendering-a-context
这可以通过使用render_to_response这个快捷函数来简化。