# -*- coding: utf-8 -*-
# Akvo Reporting is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
from django.apps import apps
from django.conf import settings
from django.db.models import Max, Q, Sum
from akvo.rsr.models.tree.managers import AkvoTreeQuerySet
[docs]class ProjectQuerySet(AkvoTreeQuerySet):
[docs] def of_partner(self, organisation):
"return projects that have organisation as partner"
return self.filter(partners__exact=organisation)
[docs] def of_partners(self, organisations):
"""Return projects that have one of the organisations as partner.
*NOTE*: If any of the organisations has one or more ProjectHierarchies,
include all the projects in the hierarchies.
"""
from akvo.rsr.models import ProjectHierarchy, Project
projects = self.filter(partners__in=organisations).distinct()
hierarchies = ProjectHierarchy.objects.filter(root_project__in=projects)\
.select_related('root_project')
hierarchy_project_ids = set()
for hierarchy in hierarchies:
hierarchy_projects = hierarchy.root_project.descendants(hierarchy.max_depth)\
.values_list('id', flat=True)
hierarchy_project_ids.update(hierarchy_projects)
projects = Project.objects.filter(Q(id__in=projects) | Q(id__in=hierarchy_project_ids))
return projects
[docs] def has_location(self):
return self.filter(primary_location__isnull=False)
[docs] def published(self):
PublishingStatus = apps.get_model('rsr.publishingstatus')
return self.filter(publishingstatus__status=PublishingStatus.STATUS_PUBLISHED)
[docs] def unpublished(self):
PublishingStatus = apps.get_model('rsr.publishingstatus')
return self.filter(publishingstatus__status=PublishingStatus.STATUS_UNPUBLISHED)
[docs] def private(self):
return self.filter(is_public=False)
[docs] def public(self):
return self.filter(is_public=True)
[docs] def status_none(self):
return self.filter(iati_status__exact='6')
[docs] def status_active(self):
return self.filter(iati_status__exact='2')
[docs] def status_onhold(self):
return self.filter(iati_status__exact='1')
[docs] def status_complete(self):
return self.filter(iati_status__exact='3')
[docs] def status_not_complete(self):
return self.exclude(iati_status__exact='3')
[docs] def status_post_complete(self):
return self.filter(iati_status__exact='4')
[docs] def status_not_post_complete(self):
return self.exclude(iati_status__exact='4')
[docs] def status_cancelled(self):
return self.filter(iati_status__exact='5')
[docs] def status_not_cancelled(self):
return self.exclude(iati_status__exact='5')
[docs] def status_archived(self):
return self.filter(iati_status__exact='6')
[docs] def status_not_archived(self):
return self.exclude(iati_status__exact='6')
# aggregates
[docs] def budget_sum(self):
''' aggregates the budgets of all the projects in the QS
n.b. non-chainable, doesn't return a QS
'''
return self.aggregate(budget=Sum('budget'), )['budget'] or 0
[docs] def funds_sum(self):
''' aggregates the funds of all the projects in the QS
n.b. non-chainable, doesn't return a QS
'''
return self.aggregate(funds=Sum('funds'), )['funds'] or 0
[docs] def funds_needed_sum(self):
''' aggregates the funds of all the projects in the QS
n.b. non-chainable, doesn't return a QS
'''
return self.aggregate(funds_needed=Sum('funds_needed'), )['funds_needed'] or 0
[docs] def get_largest_value_sum(self, benchmarkname, cats=None):
if cats:
# filter finds largest "benchmarkname" value in benchmarks for categories in cats
result = self.filter(
benchmarks__name__name=benchmarkname,
benchmarks__category__name__in=cats
)
else:
# filter finds largest "benchmarkname" value in benchmarks for all categories
result = self.filter(
benchmarks__name__name=benchmarkname
)
# annotate the greatest of the "benchmarkname" values into max_value
# sum max_value for all projects
return result.annotate(max_value=Max('benchmarks__value')).aggregate(
Sum('max_value')
)['max_value__sum'] or 0 # we want to return 0 instead of an empty QS
[docs] def get_planned_water_calc(self):
"how many will get improved water"
return self.status_not_cancelled().get_largest_value_sum(
getattr(settings, 'AFFECTED_BENCHMARKNAME', 'people affected'),
['Water']
) - self.status_complete().get_largest_value_sum(
getattr(settings, 'AFFECTED_BENCHMARKNAME', 'people affected'),
['Water']
)
[docs] def get_planned_sanitation_calc(self):
"how many will get improved sanitation"
return self.status_not_cancelled().get_largest_value_sum(
getattr(settings, 'AFFECTED_BENCHMARKNAME', 'people affected'),
['Sanitation']
) - self.status_complete().get_largest_value_sum(
getattr(settings, 'AFFECTED_BENCHMARKNAME', 'people affected'),
['Sanitation']
)
[docs] def get_actual_water_calc(self):
"how many have gotten improved water"
return self.status_complete().get_largest_value_sum(
getattr(settings, 'AFFECTED_BENCHMARKNAME', 'people affected'),
['Water']
)
[docs] def get_actual_sanitation_calc(self):
"how many have gotten improved sanitation"
return self.status_complete().get_largest_value_sum(
getattr(settings, 'AFFECTED_BENCHMARKNAME', 'people affected'),
['Sanitation']
)
[docs] def all_updates(self):
"""Return ProjectUpdates for self, newest first."""
ProjectUpdate = apps.get_model('rsr.projectupdate')
return ProjectUpdate.objects.filter(project__in=self).distinct()
# The following 8 methods return organisation querysets
def _partners(self, role=None):
Organisation = apps.get_model('rsr.organisation')
if role is None:
query = Q(partnerships__project__in=self)
else:
query = Q(partnerships__iati_organisation_role=role, partnerships__project__in=self)
return Organisation.objects.filter(query).distinct()
[docs] def field_partners(self):
Partnership = apps.get_model('rsr.partnership')
return self._partners(Partnership.IATI_IMPLEMENTING_PARTNER)
[docs] def funding_partners(self):
Partnership = apps.get_model('rsr.partnership')
return self._partners(Partnership.IATI_FUNDING_PARTNER)
[docs] def support_partners(self):
Partnership = apps.get_model('rsr.partnership')
return self._partners(Partnership.IATI_ACCOUNTABLE_PARTNER)
[docs] def extending_partners(self):
Partnership = apps.get_model('rsr.partnership')
return self._partners(Partnership.IATI_EXTENDING_PARTNER)
[docs] def all_partners(self):
return self._partners()
[docs] def paying_partners(self):
Organisation = apps.get_model('rsr.organisation')
return Organisation.objects.filter(
partnerships__project__in=self,
can_create_projects=True
).distinct()
[docs] def countries(self):
"""Returns a Country queryset of the countries of these projects"""
Country = apps.get_model('rsr.country')
country_ids = []
for project in self:
for location in project.locations.all():
country_ids.append(location.country.id)
country_ids = list(set(country_ids))
return Country.objects.filter(id__in=country_ids).distinct()
[docs] def publishingstatuses(self):
PublishingStatus = apps.get_model('rsr.publishingstatus')
return PublishingStatus.objects.filter(project__in=self)
[docs] def keywords(self):
Keyword = apps.get_model('rsr.keyword')
return Keyword.objects.filter(projects__in=self).distinct()
[docs] def sectors(self):
Sector = apps.get_model('rsr', 'Sector')
return Sector.objects.filter(project__in=self).distinct()