ajoute une implémentation générique de RequestQuerySet.total_cost()

L'implémentation otpimisée n'est utilisée que si le backend est
postgresql.
This commit is contained in:
Benjamin Dauvergne 2012-07-19 17:08:29 +02:00
parent 6804fa2376
commit 8ad4840833
2 changed files with 42 additions and 20 deletions

View File

@ -8,7 +8,7 @@ import os.path
import datetime
import decimal
from django.db import models, transaction
from django.db import models, transaction, connections
from django.utils.translation import ugettext_lazy as _, string_concat
from django.core import validators
from django.core.exceptions import ValidationError
@ -84,25 +84,44 @@ def minimum_delivery_timedelta():
class RequestQueryset(utils.QuerySet):
def total_cost(self):
cost_function1 = '({1}.ppp * {0}.nb_pages + {1}.ppd)*{0}.copies'.format(
Request._meta.db_table, profile.Profile._meta.db_table)
cost_function2 = '''SELECT SUM(({1}.ppp * {0}.nb_pages + {1}.ppd)*{0}.copies) FROM {1}, {2}
WHERE {1}.id = {2}.profileoptionchoice_id AND {2}.request_id = {0}.id'''.format(
Request._meta.db_table, profile.ProfileOptionChoice._meta.db_table,
Request._meta.get_field('choices').rel.through._meta.db_table)
qs1 = self \
.prefetch_related(None) \
.select_related(depth=0) \
.extra(select={
'base_profile_estimated_cost' : cost_function1,
'choices_estimated_cost': cost_function2
})
qs1.query.join((Request._meta.db_table, profile.Profile._meta.db_table,
Request._meta.get_field('base_profile').column,
profile.Profile._meta.get_field('id').column))
zero = decimal.Decimal(0)
return sum([r.cost or ((r.base_profile_estimated_cost or zero)+(r.choices_estimated_cost or zero)) for r in qs1])
# special case for Postgres so that it is fast in production
if utils.qs_use_postgres(self):
cost_function1 = '({1}.ppp * {0}.nb_pages + {1}.ppd)*{0}.copies'.format(
Request._meta.db_table, profile.Profile._meta.db_table)
cost_function2 = '''SELECT SUM(({1}.ppp * {0}.nb_pages + {1}.ppd)*{0}.copies) FROM {1}, {2}
WHERE {1}.id = {2}.profileoptionchoice_id AND {2}.request_id = {0}.id'''.format(
Request._meta.db_table, profile.ProfileOptionChoice._meta.db_table,
Request._meta.get_field('choices').rel.through._meta.db_table)
qs1 = self \
.prefetch_related(None) \
.select_related(depth=0) \
.extra(select={
'base_profile_estimated_cost' : cost_function1,
'choices_estimated_cost': cost_function2
})
qs1.query.join((Request._meta.db_table, profile.Profile._meta.db_table,
Request._meta.get_field('base_profile').column,
profile.Profile._meta.get_field('id').column))
return sum([r.cost or ((r.base_profile_estimated_cost or zero)+(r.choices_estimated_cost or zero)) for r in qs1])
else:
# generic implementation working everywhere
qs = self.select_related(depth=0) \
.select_related('base_profile') \
.prefetch_related(None) \
.prefetch_related('choices') \
.only('nb_pages', 'copies', 'base_profile__ppp',
'base_profile__ppd', 'choices__ppp', 'choices__ppd')
total_cost = zero
for r in qs:
ppp = r.base_profile.ppp
ppd = r.base_profile.ppd
for c in r.choices.all():
ppp += c.ppp
ppd += c.ppd
total_cost += ((r.nb_pages * ppp) + ppd) * r.copies
return total_cost
class Request(models.Model):
COPYRIGHT_CHOICES = (

View File

@ -6,7 +6,7 @@ import time
import django.core.cache
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
from django.db import models
from django.db import models, connections
from django.db.models import query
def get_next_workable_day(today=None, hours=0, days=2, increment_hours=0, increment_days=1):
@ -205,3 +205,6 @@ class QuerySet(models.query.QuerySet):
@classmethod
def as_manager(cls, ManagerClass=QuerySetManager):
return ManagerClass(cls)
def qs_use_postgres(qs):
return hasattr(connections[qs._db or 'default'], 'pg_version')