calculated fields with foreign keys

2012-09-20 Thread kloetpatra
Hi!
I have the following models:

class Player(models.Model):
name = models.CharField('Name', max_length=40)
pub_date = models.DateTimeField('date added', 
default=datetime.datetime.now)
def __unicode__(self):
return self.name
def goals(self):
g = 0
ms1 = Match.objects.filter(opp1=self)
ms2 = Match.objects.filter(opp2=self)
for m in ms1:
g += m.opp1_goals
for m in ms2:
g += m.opp2_goals
return g

class Match(models.Model):
opp1 = models.ForeignKey(Player)
opp2 = models.ForeignKey(Player)
opp1_goals = models.IntegerField("Goals P1")
opp2_goals = models.IntegerField("Goals P2")
pub_date = models.DateTimeField('date published', 
default=datetime.datetime.now)

The problem is when I want to display a statistics overview with all 
players there will be 2 DB-Queries per player only to get the "goals" 
property.
And I got more "calculated fields" like number of won matches, number of 
lost matches, etc...
There are 364 Match entries and 46 Players.
At my overview page I got over 2000 SQL queries which take over 6 seconds 
to load the page.

How can I speed up the process?
I don't want to save those "calculated values" in the database.

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/django-users/-/RsK3HmYOBBwJ.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.



reduce number of DB-Queries

2012-09-21 Thread kloetpatra
Hi!
I have the following models:

class Player(models.Model):
name = models.CharField('Name', max_length=40)
 
def __unicode__(self):
return self.name
 
def goals(self):
g = 0
ms = Match.objects.select_related().filter( 
Q(opp1=self)|Q(opp2=self) )
for m in ms:
if (m.opp1==self):
g += m.opp1_goals
else:
g += m.opp2_goals
return g

def matches_won(self):
ms = Match.objects.filter( (Q(opp1=self) & 
Q(opp1_goals__gt=F('opp2_goals'))) |
(Q(opp2=self) & Q(opp2_goals__gt=F('opp1_goals'))) ).count()
return ms
 
def matches_draw(self):
ms = Match.objects.filter( (Q(opp1=self) & 
Q(opp1_goals__exact=F('opp2_goals'))) |
(Q(opp2=self) & Q(opp2_goals__exact=F('opp1_goals'))) ).count()
return ms

def match_points(self):
p = 0
p += 3 * self.matches_won()
p += 1 * self.matches_draw()
return p

def matches_played(self):
return Match.objects.filter(Q(opp1=self) | Q(opp2=self)).count()


class Match(models.Model):
class Meta:
verbose_name_plural = "Matches"
opp1 = models.ForeignKey(Player, related_name="player1")
opp2 = models.ForeignKey(Player, related_name="player2")
opp1_goals = models.IntegerField("Goals P1")
opp2_goals = models.IntegerField("Goals P2")
 
def __unicode__(self):
return "%s %d:%d %s"%(self.opp1.name, self.opp1_goals, 
self.opp2_goals, self.opp2.name)

My problem is when want to display overall player statistics I get about 
1200 DB-Queries.
This is because for each player there will be 5 Queries due to matches_won, 
matches_draw, goals, matches_played functions.
How is it possible to retrieve those "calculated properties" without having 
so much queries?

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/django-users/-/-ki6lNP0IDAJ.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.



Re: reduce number of DB-Queries

2012-09-21 Thread kloetpatra
Wow thanks!
That's really going fast now.
I would have never come to that idea :)

One more question:
Is this how you meant to set the instance variable or did you mean in 
another way?

def __init__(self, *args, **kwargs):
super(Player, self).__init__(*args, **kwargs)
self.matches = Match.objects.select_related().filter( Q(opp1=self) 
| Q(opp2=self) )

On Friday, September 21, 2012 11:15:34 AM UTC+2, Martin J. Laubach wrote:
>
> My problem is when want to display overall player statistics I get about 
>> 1200 DB-Queries.
>> This is because for each player there will be 5 Queries due to 
>> matches_won, matches_draw, goals, matches_played functions.
>>
>
>   First easy optimisation: keep  Match.objects.select_related().filter( 
> Q(opp1=self)|Q(opp2=self)) in an instance variable and use that QuerySet 
> as base of all your calculations. Do NOT add additional filters for 
> matches_draw/matches_won/matches_played, instead iterate over the results 
> and do the calculations in Python. That way the QuerySet result will be 
> cached the first time you're iterating over it and won't result in any more 
> database accesses later on.
>
>Cheers,
>
> mjl
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/django-users/-/crAR4nXZyugJ.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.



Re: reduce number of DB-Queries

2012-09-21 Thread kloetpatra
I think aggregation can't be used because the calculations are  a bit more 
complex than just the sum/average/count/min/max of one field.

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/django-users/-/P2aCE_gXHgYJ.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.