【问题标题】:Aggregate data using the ORM使用 ORM 聚合数据
【发布时间】:2011-02-14 19:02:15
【问题描述】:

这里是 Django/Python 菜鸟!

这是我的模型:

class Match(models.Model):
    date = models.DateTimeField()
    court = models.ForeignKey(Court)
    players = models.ManyToManyField(User, through='Participant')

class Participant(models.Model):
    match = models.ForeignKey(Match)
    userid = models.ForeignKey(User)
    games_won = models.IntegerField()

class Court(models.Model):
    location_name = models.CharField(max_length=100)
    number = models.IntegerField()

我目前的看法是:

def index(request):
    matches_list = Participant.objects.all()
    return render_to_response('squash/base_matches.html', {'matches_list': matches_list}, context_instance = RequestContext(request))
    return HttpResponse(output)

我在数据库中的数据如下所示:

[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

我想做的是:

[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  

这意味着我需要按 match_id 分组。我尝试在我的模板中执行以下操作,但它只聚合了 match_id、日期和时间。我需要能够格式化其余的数据。在前面提到的表格结构中。

{% regroup matches_list by match as matches_group %}
<ul>
{% for event in matches_group %}
    <li>{{ event.grouper }}
    <ul>
        {% for item in blah.list %}
        <li>{{ item.date }}</li>
        {% endfor %}
    </ul>
    </li>
{% endfor %}
</ul>

这里有什么建议吗?

更新:我用matches_list = Participant.objects.values('match').annotate(total=Count('match')) 进行了测试,我相信这就是让我聚合的原因。但是我不知道如何在模板中提取正确的字段。例如:

{% for matches in matches_list %}
<p>{{ matches.match.id }}</p>
{% endfor %}

这给了我 3 个条目(我可以看到 3 个

的),但没有打印出来。不知道我需要为{{ matches.match.id }}做什么

【问题讨论】:

  • 如何阻止有超过 2 个人的 match_id?如何确定谁是player1,谁是player2?
  • 我还没有任何内置控件来执行此操作,因此输入这些控件的管理员只需要知道输入两个人即可。 player1和player2的顺序无关紧要,只需要第一个玩家,然后是第二个玩家。

标签: python django django-orm


【解决方案1】:

您的表格显示“数据库中的数据”与您的模型不匹配,所以我有点困惑。

但是按照您的模型,这里根本不需要聚合,因为您在 Participant 模型上直接有一个 matches_won 字段(我假设这是您需要显示的数据)。您可以简单地通过迭代 matches_list 来做到这一点(为清楚起见省略了格式):

{% for match in matches_list %}
    {{ match.id }}
    {{ match.date }}
    {{ match.players.all.0.userid.username }}
    {{ match.players.all.1.userid.username }}
    {{ match.players.all.0.games_won }}
    {{ match.players.all.1.games_won }}
    {{ match.court.location_name }}
    {{ match.court.number }}
{% endfor %}

编辑但我不明白您为什么从参与者列表开始,并称其为matches_list。从匹配列表开始,然后上面的代码将起作用。

【讨论】:

  • 首先,我需要从 Matches 模型中提取匹配 id,所以我需要使用 match.match.id 而不是 match.id。第二个“数据库中的数据”是三个模型的非规范化视图。我试图实现的逻辑非常类似于如何设置:stackoverflow.com/questions/4773214/… 所以需要发生的是,对于每个具有匹配 ID 的条目(让我们以匹配 id #1 为例),它需要将这些数据聚合成一个行(所以在我的情况下,应该是 3 行而不是 6 行)
  • 啊,明白了。将matches_list 切换为Match.objects.all 这适用于ID 和日期。什么不起作用是 {{ match.players.all.0.userid.username }}{{ match.players.all.0.games_won }} Hmmmmm
【解决方案2】:

我建议另一种数据结构。不是每次匹配有两行,而是每次匹配有一行。那么您的数据结构基本上就是您想要的结果“视图”。显然,获胜者将是一个计算出来的列/值。

那么您的 django 模型可能如下所示:

class Match(models.Model):
    player_1 = models.ForeignKey(auth.User)
    score_1 = models.PositiveIntegerField(null=True, blank=True)
    player_2 = models.ForeignKey(auth.USer)
    score_2 = models.PositiveIntegerField(null=True, blank=True)
    court = models.ForeignKey(Court)
    date = models.DateField()

    @property
    def winner(self):
        "None means not played yet, or a draw."
        if self.score_1 > self.score_2:
            return self.player_1
        if self.score_1 < self.score_2:
            return self.player_2

    @property
    def is_draw(self):
        return self.score_1 == self.score_2 and self.score_1 is not None


class Location(models.Model):
    name = models.CharField()

class Court(models.Model):
    location = models.ForeignKey(Location)
    number = models.PositiveIntegerField()

【讨论】:

  • 马修,很有趣。我不熟悉@property 标签?是否有它的文档,所以我了解它是如何工作的?我会对此进行测试,看看它是否在此期间有效。
  • 好的,现在可以了。我不得不将player_1 = models.ForeignKey(auth.User) 更改为models.ForeignKey(User, related_name='player_1'),并且对于 player2 也是如此。谢谢!我现在唯一的问题是我想强制它使 player_1 和 player_2 不能相同。
  • @name 意味着 name 是一个装饰器:有一个用于 python 装饰器的谷歌。以这种方式使用,@property 将方法转换为某种只读属性。这基本上意味着您可以调用单个参数方法(以 self 作为参数),作为 obj.method,而不是 obj.method()。不过,这并没有真正做到公正。
猜你喜欢
  • 2021-12-13
  • 2017-07-31
  • 2019-11-15
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多