如何使用django ORM进行多个连接和聚合?

Bes*_*sto 2 python database django

Django/Python/ORM noob在这里!我很难绕过ORM的工作方式.

这是我的模特:

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)
Run Code Online (Sandbox Code Playgroud)

第一步是将所有"参与"放入输出中,如下所示:

[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
Run Code Online (Sandbox Code Playgroud)

我会写什么ORM脚本来获取它?我很难理解简单连接如何与ORM一起工作,更不用说组合3个表了.

接下来,我想要聚合数据,以便最终看起来像这样:

[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  
Run Code Online (Sandbox Code Playgroud)

这会改变我写的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"
Run Code Online (Sandbox Code Playgroud)

这看起来更像是我想要实现的目标.现在我无法弄清楚如何将数据从这里拿到模板中.

UPDATE2:

我的观点如下:

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)
Run Code Online (Sandbox Code Playgroud)

我的模板看起来像这样:

{% 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 %}
Run Code Online (Sandbox Code Playgroud)

它正确呈现所有Participants.ids,但不会带来比赛ID,日期或法院.

Tom*_*ski 5

那里有几个"东西":

  1. 定义"id"主要字段是不必要的,因此令人困惑,Django会自动生成它们
  2. 使用单数形式命名模型(即匹配而不是匹配等)是一种很好的做法 - 这样你就可以让Django提供适当的单数和复数处理.它也是合乎逻辑的,因为类Ma​​tch的对象代表单个匹配,而不是它们中的一些 - 对于多个匹配,您使用模型管理器:Match.objects
  3. 您的"参与者"模型实际上是中间的ManyToMany表,您可以在"匹配"模型中明确声明,例如HERE

现在,关于你的JOIN问题,我的第二个是我曾经在StackOverflow上读过的S.Lott的方法 - 你不应该考虑Django中的JOIN,因为这不是Django ORM("O"代表"对象" - 和映射的方式SQL对象不是一块蛋糕).您应该专注于完成工作,并且在合理的情况下使用JOIN ,例如性能问题.

最后,回答你的问题:

Participants.objects.all()
Run Code Online (Sandbox Code Playgroud)

:-)

通过使用select_related(),您可以获得更好的性能,如果需要,您也可以使用order_by()来应用排序.

至于聚合,其他人可能会提供一个单线解决方案,我目前看不到,但现在你可以将其添加到"匹配"模型:

players = models.ManyToManyField(User, through='Participants')
Run Code Online (Sandbox Code Playgroud)

然后你可以用最简单的方式获取匹配:

Matches.objects.all()
Run Code Online (Sandbox Code Playgroud)

然后返回集合的每个元素都将具有"player"属性.

更新:

要将数据传递给模板,只需将其添加到模板渲染上下文中:

http://docs.djangoproject.com/en/1.2/ref/templates/api/#rendering-a-context

这可以使用render_to_response快捷键功能进行简化.