开发者

Aggregate data using the ORM

Django/Python noob here!

Here are my models:

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()

My view is currently:

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)

My data in the database looks like the following:

[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

What I want to be able to do is:

[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  

Which means I need to group by match_id. I've tried doing something like the following in my template, but it only aggregates the match_id, date and time. I need to be able to format the rest of the data. In a table structure like preposed right before.

{% 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>
{% endf开发者_开发技巧or %}
</ul>

Any advice here?

UPDATE: I tested with matches_list = Participant.objects.values('match').annotate(total=Count('match')) and I believe this is what gets me the aggregation. However I don't know how to pull the correct fields out of it in the template. For example:

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

This gives me 3 entries (I can see 3

's) but nothing gets printed out. Not sure what I need to do for {{ matches.match.id }}


Your table showing 'data in the database' doesn't match your models, so I'm a bit confused.

But going by your models, there's no aggregation needed here at all, since you have a matches_won field directly on the Participant model (I assume that's the data you need to display). You can do it simply by iterating through matches_list (formatting omitted for clarity):

{% 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 %}

Edit But I don't understand why you're starting from a list of Participants, and calling that matches_list. Start from a list of matches, then the above code will work.


I'd suggest an alternate data structure. Instead of having two rows per match, have one row per match. Then your data structure is basically what you want as the results 'view'. Obviously, winner would be a calculated column/value.

Then your django models can look like:

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()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜