/psp/models.py
Python | 4721 lines | 4699 code | 1 blank | 21 comment | 6 complexity | 4ed341d9c73fe68daafddd46b79d14cc MD5 | raw file
Possible License(s): BSD-3-Clause
- #coding=utf-8
- #suppress 'too many' lines warning
- #pylint: disable-msg=C0302
- """
- copyright (c) 2009, paketka@gmail.com et. al
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the <ORGANIZATION> nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- """
- import datetime
- import re
- from django.shortcuts import get_object_or_404
- from django.db import models
- from django.db.models import Q
- from django.http import Http404
- from django.utils.translation import ugettext as _
- from django.db.models.signals import pre_save
- from django.contrib.localflavor.us.models import PhoneNumberField
- from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
- from django.core.exceptions import FieldError
- from django.db import connection
- from common.models import AutoSlug, makeSlug
- import settings
- from django.core.urlresolvers import reverse
- from GChartWrapper import Pie3D
- from utils.charts import Votes, Accordance, get_percents
- def term_to_id(term):
- """
- Function term_to_id(term)
- Retrieves a primary key from term instance of TermOfOffice class.
- If term is integer function just returns the term value.
- Returns term's instance key
- """
- if type(term) == type(0):
- term = get_object_or_404(TermOfOffice, id = term)
- return term.id
- else:
- return term.id
- def person_to_id(person):
- """
- Function person_to_id(person)
- Retrieves a primary key from person instance of Person class.
- If person is integer function just returns the person value.
- Returns person's instance primary key
- """
- if type(person) == type(0):
- return person
- else:
- return person.id
- def group_to_id(group):
- """
- Function group_to_id(group)
- Retrieves a primary key from person instance of Group class.
- If group is integer function just returns the group value.
- Returns group's instance primary key
- """
- if type(group) == type(0):
- return group
- else:
- return group.id
- def poll_to_id(poll):
- """
- Function poll_to_id(poll)
- Retrieves a primary key from poll instance of Poll class.
- If poll is integer function just returns the poll value.
- Returns poll's instance primary key
- """
- if type(poll) == type(0):
- return poll
- else:
- return poll.id
- class TermOfOffice(AutoSlug):
- """
- Class TermOfOffice(AutoSlug)
- The TermOfOffice represents a period of parliament between two pools.
- There are several attributes:
- yearStart - the first electoral year (string)
- yearEnd - the last electoral year (string)
- slug - string (yearStart_yearEnd), autogenerated from
- yearStart, yearEnd
- termId - term ID assigned at psp.cz site
- """
- yearStart = models.CharField(_("Start Year"), max_length = 4)
- yearEnd = models.CharField(_("End Year"), max_length = 4)
- slug = models.SlugField(db_index = True, unique = True)
- termId = models.CharField(_("Term Id"), max_length = 4)
- slugs = {
- 'slug' : ('yearStart', 'yearEnd', ),
- }
-
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Term of Office")
- verbose_name_plural = _("Terms of Office")
-
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- def isComplete(self):
- """
- Method isComplete()
- Method returns true if the given term instance is complete.
- The complete term instance has yearEnd attribute filled in. It
- actually means the given electoral term is over.
- Returns True if term is complete (over)
- """
- return self.yearEnd != ''
- def getStart(self):
- """
- Method getStart()
- Returns yearStart attribute as integer.
- Returns yearEnd attribute as integer.
- """
- return int(self.yearStart)
- def getEnd(self):
- """
- Method getEnd()
- Method returns yearEnd attribute as integer. If there is no
- yearEnd set yet, which happens for current terms, the method
- will return the current year instead.
- Returns yearEnd attribute as integer, if there is no yearEnd
- attribute set, function will return a current year.
- """
- if self.yearEnd == '':
- return datetime.datetime.today().year
- else:
- return int(self.yearEnd)
- def getStartDate(self):
- """
- Method getStartDate()
- We have to create faked start date of given term, it will be Jan 1 of
- the yearStart.
- Returns datetime.date(int(yearEnd), day = 1, month = 1)
- """
- retVal = datetime.date(
- day = 1,
- month = 1,
- year = self.getStart()
- )
- return retVal
-
- def getEndDate(self):
- """
- Method getEndDate()
- We have to create faked end date of given term, it will be Dec 31
- of the yearEnd.
- Returns datetime.date(int(yearStart), day = 31, month = 12)
- """
- retVal = datetime.date(
- day = 31,
- month = 12,
- year = self.getEnd()
- )
- return retVal
- def getRange(self):
- """
- Method getRange()
- Method returns a date range represeting given term instance
- as a tupple of two datetime.date instances, represeting
- (lowerBound, upperBound)
- Returns a tupple (self.getStartDate(), self.getEndDate())
- """
- return (self.getStartDate(), self.getEndDate(),)
- def getTermsList(self):
- """
- Method getTermsList()
- Returns list of terms rendered to .html tags. It's optimized for views
- which are using using ui-jquery .css. It renders links to terms, which
- are other than 'self'.
-
- Method is used in templates. It follows DRY principle, but violates
- MVC model - the presentation logic is implemented here.
- Returns list of strings with .html tags.
- """
- retVal = []
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- for t in TermOfOffice.objects.all():
- url = u''
- content = '%d - %d' % (t.getStart(), t.getEnd())
- if t == self:
- url = u'<span>%s</span>' % content
- url += u'<span class="ui-icon ui-icon-triangle-1-w"></span>'
- else:
- url = u'<a href="%s">%s</a>' % (
- reverse('term_tab',
- args = [
- str(t.getStart()),
- str(t.getEnd())
- ]
- ),
- content,
- )
- retVal.append(url)
- return retVal
- @staticmethod
- def get_term_or_404(start, end):
- """
- Static method get_term_or_404(start, end)
- Returns a TermOfOffice instance for given start, end year range. If
- there is no such term in DB, function (method) will raise Http404
- exception.
- The mandatory arguments start, end can be either strings or
- integer numbers:
- start - start year for term
- end - end year fo term
- Returns matching TermOfOffice instance or raises Http404
- """
- retVal = None
- if type(start) != type(''):
- start = str(start)
- if type(end) != type(''):
- end = str(end)
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- retVal = TermOfOffice.objects.get(yearStart = start, yearEnd = end)
- except ObjectDoesNotExist:
- if (int(start) <= int(end)):
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- retVal = TermOfOffice.objects.get(
- yearStart = start,
- yearEnd = ''
- )
- except ObjectDoesNotExist:
- raise Http404
- else:
- raise Http404
- return retVal
- @staticmethod
- def get_term_for_date(date):
- """
- Static method get_term_for_date(date)
- Returns the term for date. The mandatory argument date is a
- datetime.date object.
- Returns instance of TermOfOffice class.
- """
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- for t in TermOfOffice.objects.all().order_by('-id'):
- if date >= t.getStartDate() and date <= t.getEndDate():
- return t
- return None
-
- pre_save.connect(makeSlug, TermOfOffice)
- class Division(AutoSlug):
- """
- Class Division(AutoSlug)
- Division class represents an electoral area. The contains these attributes:
- term - link (ForeignKey) to term instance the particular division
- is bound to
- name - the division name (i.e. 'Karlovarsky kraj')
- icon - image icon (currently unused)
- slug - slug field (autogenerated from name)
- """
- term = models.ForeignKey(TermOfOffice)
- name = models.CharField(_("Division Name"), max_length = 20)
- icon = models.ImageField(_("Division Symbol"),
- upload_to = settings.SYMBOLS,
- blank = True
- )
- divId = models.CharField(_("Division Id"), max_length = 10)
- slug = models.SlugField(db_index = True, unique = True)
- slugs = {
- 'slug' : ('name', )
- }
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Division")
- verbose_name_plural = _("Divisions")
- unique_together = (('term', 'divId',),)
- def getName(self):
- """
- Method getName()
- Method strips 'Volebni kraj' string from data, which are stored in DB.
-
- Returns the division name.
- """
- pattern = re.compile(u'.*Volební\s*kraj(?P<name>.*)', re.U)
- match = pattern.match(self.name)
- retVal = u''
- if match:
- retVal += match.group('name')
- else:
- retVal = self.name
-
- return retVal.strip()
-
- pre_save.connect(makeSlug, Division)
- #suppress warning too many public methods
- #pylint: disable-msg=R0904
- class PersonManager(models.Manager):
- """
- Class PersonManager
- PersonManager provides predefined select to retrieve Person instances from DB.
- Depending on method used the Person instance might be extended by extra attributes
- (see method descriptions further down).
- The PersonManager is a default manager for Person class.
- """
- def createPersonFromRow(self, row):
- """
- Method createPersonFromRow
- Method creates an instance of Person class from row, fetched from DB.
- The row is list, which represents the row retrieved. The method expects
- row argument to contain at least 14 elements. The order of elements
- in array is as follows:
- 0 - integer representinf Person's instance primary key
- 1 - mpId string representing person's key at psp.cz
- 2 - name (unicode string)
- 3 - surname (unicode string)
- 4 - title prepended before first name (unicode string)
- 5 - title, which follows sutname (unicode string)
- 6 - birthDate (datetime.date instance)
- 7 - email (string)
- 8 - office address (string)
- 9 - regionOffice address (office located at MP's home town)
- 10 - MP's phone (string)
- 11 - slug, which is a parameter to construct link (string)
- 12 - homePage/blog link to blog (string)
- 13 - link to profile at http://nasipolitici.cz
- Returns instance of Person class
- """
- person = self.model(
- id = row[0], #primary Key
- mpId = row[1], #mpId
- name = row[2], #name
- surname = row[3], #surname
- title = row[4], #title
- titleLast = row[5], #titleLast
- birthDate = row[6], #birthDate
- email = row[7], #email
- office = row[8], #office
- regionOffice = row[9], #regionOffice
- phone = row[10], #phone number
- slug = row[11], # slug field
- homePage = row[12], # homePage/blogField
- nasiPoliticiUrl = row[13]
- )
-
- return person
- def commonSelect(self, where, orderBy, desc, term = None):
- """
- Method commonSelect(where, orderBy, desc, term = None)
- Retrieves a list of Person objects matching the query. The application
- should never use commonSelect() directly. It should use commonSelect()
- wrappers instead:
- getPersons(), getPersonsOrderByName(),getPersonsOrderByAge(),
- getPersonsOrderByDivision(), getPersonsOrderByParty(),
- getPersonsOrderByAbsences(), getPerson()
- All these methods are explained further in the text.
- The arguments are parts of SELECT command:
- where - is optional WHERE clause (it can be an empty string)
- order - by is order by statement
- desc - is boolean flag if true the order will be descendant
- term - optional argument, if no term is passed, all MPs are
- selected.
- Besides standard attribute the Person instance is extended by some
- more:
- detail - an instance of PersonDetail class
- divisionName - the name of electoral division the MP comes
- from
- partyName - the name of party the MP is member of
- votes - is an instance of Votes class. It wraps up the
- vote stats for given MP in term.
- terms - in case no term was specified, this attribute contains
- list of all terms the MP was member of parliament.
- Returns list of Person objects extended by few attributes (see above).
- """
- #suppress too many branches refactore warning
- #pylint: disable-msg=R0912
- retVal = []
- select = ''
- termId = None
- if orderBy != None and orderBy != '':
- if desc:
- orderBy += ' DESC'
- else:
- orderBy += ' ASC'
- if term != None:
- termId = term_to_id(term)
- select = u"""
- SELECT DISTINCT person.id,
- person.mpId,
- person.name,
- person.surname,
- person.title,
- person.titleLast,
- person.birthDate,
- person.email,
- person.office,
- person.regionOffice,
- person.phone,
- person.slug,
- person.homePage,
- person.nasiPoliticiUrl,
- detail.id,
- division.id,
- party.id,
- SUM(votes.absences) + SUM(votes.excused) AS absences,
- SUM(votes.absences) + SUM(votes.excused) +
- SUM(votes.votes_refrains) +
- SUM(votes.votes_aye) +
- SUM(votes.votes_nay) AS total,
- SUM(votes.votes_aye) AS votesAye,
- SUM(votes.votes_nay) AS votesNay,
- SUM(votes.votes_refrains) AS refrains,
- SUM(votes.absences) AS unexcAbs,
- SUM(votes.excused) AS excsdAbs
- FROM psp_person AS person
- INNER JOIN psp_group AS parlament ON parlament.type LIKE 'PARLAMENT' AND
- parlament.term_id = %d
- INNER JOIN psp_group AS party ON party.type LIKE 'KLUB' AND
- party.term_id = %d
- INNER JOIN psp_membership AS partymship ON
- partymship.group_id = party.id AND
- partymship.post LIKE '%%%%len' AND
- partymship.person_id = person.id
- INNER JOIN psp_membership AS parlmship ON
- parlmship.group_id = parlament.id AND
- parlmship.post LIKE 'poslan%%%%' AND
- parlmship.person_id = person.id
- INNER JOIN psp_persondetail AS detail ON
- detail.person_id = person.id AND
- detail.term_id = %d
- INNER JOIN psp_division AS division ON
- division.id = detail.region_id
- INNER JOIN psp_votestats AS votes ON
- votes.person_id = person.id AND
- votes.term_id = %d
- %s
- GROUP BY person.id %s;
- """
- select = select % (termId, termId, termId, termId, where, orderBy)
- else:
- select = u"""
- SELECT person.id,
- person.mpId,
- person.name,
- person.surname,
- person.title,
- person.titleLast,
- person.birthDate,
- person.email,
- person.office,
- person.regionOffice,
- person.phone,
- person.slug,
- person.homePage,
- person.nasiPoliticiUrl,
- detail.id,
- division.id,
- party.id,
- SUM(votes.absences) + SUM(votes.excused) AS absences,
- SUM(votes.absences) + SUM(votes.excused) +
- SUM(votes.votes_refrains) +
- SUM(votes.votes_aye) +
- SUM(votes.votes_nay) AS total,
- SUM(votes.votes_aye) AS votesAye,
- SUM(votes.votes_nay) AS votesNay,
- SUM(votes.votes_refrains) AS refrains,
- SUM(votes.absences) AS unexcAbs,
- SUM(votes.excused) AS excsdAbs
- FROM psp_person AS person
- INNER JOIN psp_group AS party ON party.type LIKE 'KLUB'
- INNER JOIN psp_membership AS partymship ON
- partymship.group_id = party.id AND
- partymship.post LIKE '_len' AND
- partymship.person_id = person.id
- INNER JOIN psp_persondetail AS detail ON
- detail.person_id = person.id
- INNER JOIN psp_division AS division ON
- division.id = detail.region_id
- INNER JOIN psp_votestats AS votes ON
- votes.person_id = person.id
- %s
- GROUP BY person.id %s;
- """
- select = select % (where, orderBy)
- cursor = connection.cursor()
- cursor.execute(select)
- for row in cursor.fetchall():
- mp = self.createPersonFromRow(row)
- # row[14] - missed polls
- # row[15] - total number of all polls
- mp.votes = Votes(
- vAye = row[19],
- vNay = row[20],
- vRefrains = row[21],
- absences = row[22],
- excused = row[23]
- )
- mp.detail = None
- #suppress 'Exception does not do anything' warning
- #pylint: disable-msg=W0704
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mp.detail = PersonDetail.objects.get(id = row[14])
- except ObjectDoesNotExist:
- pass
- mp.divisionName = ''
- #suppress 'Exception does not do anything' warning
- #pylint: disable-msg=W0704
- try:
- # row[12] division ID
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mp.divisionName = Division.objects.get(id = row[15]).getName()
- except ObjectDoesNotExist:
- pass
- mp.partyName = ''
- #suppress 'Exception does not do anything' warning
- #pylint: disable-msg=W0704
- try:
- # row[13] party club id
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mp.partyGroup = Group.objects.get(id = row[16])
- mp.partyName = mp.partyGroup.getPartyName()
- except ObjectDoesNotExist:
- pass
- mp.terms = []
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- for mship in Membership.objects.filter(
- person = mp,
- group__type = 'PARLAMENT'
- ).order_by('group__term__id'):
- mp.terms.append(mship.group.term)
-
- mp.term = term
- if term != None:
- mp.terms.append(term)
- mp.age = term.getStart() - mp.birthDate.year
- else:
- try:
- t = mp.terms[len(mp.terms) - 1]
- mp.age = t.getStart() - mp.birthDate.year
- except IndexError:
- mp.age = 0
- retVal.append(mp)
- return retVal
- def getPersons(self, desc = False, term = None):
- """
- Method getPersons(desc = False, term = None)
- Method uses commonSelect() to retrieve list of persons. The persons are
- ordered by surname, name in ascendant order by default. If no term
- argument is used function retrieves list of all MPs, otherwise it
- fetches list of MPs for particular term only. All arguments are optional:
- desc - false on default (the MPs will be ordered in ascendant
- order by surname, name)
- term - if no term is specified then all MPs are retrieved,
- each MP will have extra attribute terms, which
- a list of all terms he/she was working as MP.
- Returns list of MPs ordered by surname, name
- """
- orderBy = 'ORDER BY person.surname, person.name'
- return self.commonSelect( where = '',
- orderBy = orderBy,
- desc = desc,
- term = term
- )
- def getPersonsOrderByName(self, desc = False, term = None):
- """
- Method getPersonsOrderByName(desc = False, term = None)
- Method uses commonSelect() to retrieve list of persons. The persons are
- ordered by name, surname in ascendant order by default. If no term
- argument is used function retrieves list of all MPs, otherwise it
- fetches list of MPs for particular term only. All arguments are optional:
- desc - false on default (the MPs will be ordered in ascendant
- order by surname, name)
- term - if no term is specified then all MPs are retrieved,
- each MP will have extra attribute terms, which
- a list of all terms he/she was working as MP.
- Returns list of MPs ordered by name, surname
- """
- orderBy = 'ORDER BY person.name, person.surname'
- return self.commonSelect( where = '',
- orderBy = orderBy,
- desc = desc,
- term = term
- )
- def getPersonsOrderByAge(self, desc = False, term = None):
- """
- Method getPersonsOrderByAge(desc = False, term = None)
- Uses commonSelect() to retreive list of person objects. Objects are
- ordered by age. The age is computed with respect to the begining of
- given term. If no term is given then the recent term the MP was in
- parliament is used. By default the MPs are ordered in ascendant
- order. The optional arguments are as follows:
- desc - default False, (descendant/ascendant) order
- term - if no term is specified then all MPs are retrieved,
- each MP will have extra attribute terms, which
- a list of all terms he/she was working as MP.
- Returns list of MPs ordered by age in ascendant order by default.
- """
- orderBy = 'ORDER BY person.birthDate, person.surname, person.name'
- retVal = self.commonSelect( where = '',
- orderBy = orderBy,
- desc = desc,
- term = term
- )
- #We need to sort by age here, age is computed with respect to the
- #start of parliementar membership.
- if desc:
- retVal.sort(lambda a, b: a.age - b.age)
- else:
- retVal.sort(lambda a, b: b.age - a.age)
-
- return retVal
- def getPersonsOrderByDivision(self, desc = False, term = None):
- """
- Method getPersonsOrderByAge(desc = False, term = None)
- Uses commonSelect() to retrieve list of MPs (person objects) ordered by
- division name. The defaut sort order is ascendant. If no term is
- specified MPs for all terms are retrieved. The optional arguments are:
- desc - default False, (descendant/ascendant) order
- term - if no term is specified then all MPs are retrieved,
- each MP will have extra attribute terms, which
- a list of all terms he/she was working as MP.
- Returns list of MPs ordered by division in ascendant order by default.
- """
- orderBy = 'ORDER BY division.name, person.surname, person.name'
- return self.commonSelect( where = '',
- orderBy = orderBy,
- desc = desc,
- term = term
- )
- def getPersonsOrderByParty(self, desc = False, term = None):
- """
- Method getPersonsOrderByParty(desc = False, term = None)
- Uses commonSelect() to retrieve the list of MPs (person objects) ordered
- by the name of party club they are member of. The default sort order
- is ascendant. If no term is specified MPs for all terms are retreived.
- The optional arguments are as follows:
- desc - default False, (descendant/ascendant) order
- term - if no term is specified then all MPs are retrieved,
- each MP will have extra attribute terms, which
- a list of all terms he/she was working as MP.
- Returns list of MPs ordered by their party name in ascendant order.
- """
- orderBy = 'ORDER BY party.name, person.surname, person.name'
- return self.commonSelect( where = '',
- orderBy = orderBy,
- desc = desc,
- term = term
- )
-
- def getPersonsOrderByAbsences(self, desc = False, term = None):
- """
- Method getPersonsOrderByAbsences(desc, term)
- Uses commonSelect() to retreive list of MPs (person objects) ordered
- by absences. The default sort order is ascendant (from the least
- absences to the most absences). If no term is specified MPs for all
- terms are retrieved. The optional arguments are as follows:
- desc - default False, (descendant/ascendant) order
- term - if no term is specified then all MPs are retrieved,
- each MP will have extra attribute terms, which
- a list of all terms he/she was working as MP.
- Returns list of MPs ordered by absences in ascendant order.
- """
- orderBy = 'ORDER BY absences'
- retVal = self.commonSelect( where = '',
- orderBy = orderBy,
- desc = desc,
- term = term
- )
- #we need to sort by computed absences, which are in relative values,
- #the DB select sorts by absolute values, which are misleading
- #we need to keep 2 decimal places presition, therefore we mult by 100
- if desc:
- retVal.sort(
- lambda a, b: int(a.votes.totalAbsencesPerc * 100) - \
- int(b.votes.totalAbsencesPerc * 100)
- )
- else:
- retVal.sort(
- lambda a, b: int(b.votes.totalAbsencesPerc * 100) - \
- int(a.votes.totalAbsencesPerc * 100)
- )
-
- return retVal
- def getPerson(self, person, term = None):
- """
- Method getPerson(person, term)
- Uses commonSelect() to retrieve a single MP (Person object). If no term
- is specified all data from all terms the particular person was member
- of parlament are retrieved. The mandatory person argument can be any of
- these below:
- integer - primary key for Person object
- string - slug defining MP
- person - instance of Person class
- If no term is specified the person will be extended by attribute terms,
- which is a list of all terms the person was active MP.
- Returns Person object or raises ObjectDoesNotExist exception, if no
- such MP can be found.
- """
- where = None
- if type(person) == type(0):
- where = 'WHERE person.id = %d' % person
- elif type(person) == type(u'') or type(person) == type(''):
- where = 'WHERE person.slug = "%s"' % person
- else:
- where = 'WHERE person.id = %d' % person.id
- #suppress 'redefining built-in list' warning
- #pylint: disable-msg=W0622
- list = self.commonSelect( where = where,
- orderBy = '',
- desc = False,
- term = term
- )
- if len(list) != 1:
- raise ObjectDoesNotExist
- return list[0]
-
- def getSlackers(self, dayStart, dayEnd = None, desc = True,
- colName = 'totalAbsences'):
- """
- Method getSlackers(dayStart, dayEnd = None, desc = True,
- colName = 'totalAbsences')
- Returns list of Person objects (MPs) ordered by their absences at
- polls for given date (date range). The only mandatory argument is
- dayStart, which defines desired day we want to retrieve list for.
- The rest of arguments is optional:
- dayEnd - if used, then dayStart, dayEnd range is defined
- desc - default value is true, which means the persons
- will be ordered in descendant order (from the
- biggest slackers toward the biggest hardworkers,
- with no absences)
- colName - the default value is 'totalAbsences' which means
- the MPs will be ordered by totalAbsences column.
- In fact you can use any column name you like:
- absences - unexcused absences
- excused - excused absences
- votesRefrain
- votesAye
- votesNay
- Returns list of MPs ordered by their absences.
- """
- select = None
- order = None
- if desc:
- order = 'DESC'
- else:
- order = 'ASC'
- if dayEnd == None:
- select = """
- SELECT id personId,
- mpId AS personMpId,
- name AS personName,
- surname AS personSurname,
- title AS personTitle,
- titleLast AS personTitleLast,
- birthDate AS personBirthDate,
- email AS personEmail,
- office AS personOffice,
- regionOffice AS personRegionOffice,
- phone AS personPhone,
- slug AS personSlug,
- homePage AS personHomePage,
- nasiPoliticiUrl AS personNasiPoliticiUrl,
- absences,
- excused,
- votesAye,
- votesNay,
- votesRefrain,
- (absences + excused) AS totalAbsences FROM (
- SELECT mp.id AS id,
- mp.mpId AS mpId,
- mp.name AS name,
- mp.surname AS surname,
- mp.title AS title,
- mp.titleLast AS titleLast,
- mp.birthDate AS birthDate,
- mp.email AS email,
- mp.office AS office,
- mp.regionOffice AS regionOffice,
- mp.phone AS phone,
- mp.slug AS slug,
- mp.homePage AS homePage,
- mp.nasiPoliticiUrl AS nasiPoliticiUrl,
- SUM(mpds.absences) AS absences,
- SUM(mpds.excused) AS excused,
- SUM(mpds.votes_aye) AS votesAye,
- SUM(mpds.votes_nay) AS votesNay,
- SUM(mpds.votes_refrain) AS votesRefrain
- FROM psp_mpdaystats AS mpds
- INNER JOIN psp_person AS mp ON
- mp.id = mpds.person_id
- WHERE mpds.date = '%d-%02d-%02d'
- GROUP BY id
- ) GROUP BY id ORDER BY %s %s;
- """
- select = select % ( dayStart.year, dayStart.month, dayStart.day,
- colName, order
- )
- else:
- select = """
- SELECT id personId,
- mpId AS personMpId,
- name AS personName,
- surname AS personSurname,
- title AS personTitle,
- titleLast AS personTitleLast,
- birthDate AS personBirthDate,
- email AS personEmail,
- office AS personOffice,
- regionOffice AS personRegionOffice,
- phone AS personPhone,
- slug AS personSlug,
- homePage AS personHomePage,
- nasiPoliticiUrl AS personNasiPoliticiUrl,
- absences,
- excused,
- votesAye,
- votesNay,
- votesRefrain,
- (absences + excused) AS totalAbsences FROM (
- SELECT mp.id AS id,
- mp.mpId AS mpId,
- mp.name AS name,
- mp.surname AS surname,
- mp.title AS title,
- mp.titleLast AS titleLast,
- mp.birthDate AS birthDate,
- mp.email AS email,
- mp.office AS office,
- mp.regionOffice AS regionOffice,
- mp.phone AS phone,
- mp.slug AS slug,
- mp.homePage AS homePage,
- mp.nasiPoliticiUrl AS nasiPoliticiUrl,
- SUM(mpds.absences) AS absences,
- SUM(mpds.excused) AS excused,
- SUM(mpds.votes_aye) AS votesAye,
- SUM(mpds.votes_nay) AS votesNay,
- SUM(mpds.votes_refrain) AS votesRefrain
- FROM psp_mpdaystats AS mpds
- INNER JOIN psp_person AS mp ON
- mp.id = mpds.person_id
- WHERE mpds.date
- BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d'
- GROUP BY id
- ) GROUP BY id ORDER BY %s %s;
- """
- select = select % ( dayStart.year, dayStart.month, dayStart.day,
- dayEnd.year, dayEnd.month, dayEnd.day,
- colName, order
- )
- cursor = connection.cursor()
- cursor.execute(select)
- retVal = []
- for row in cursor.fetchall():
- mp = self.createPersonFromRow(row)
- mp.votes = Votes(
- vAye = row[17],
- vNay = row[16],
- vRefrains = row[18],
- absences = row[14],
- excused = row[15],
- sDate = dayStart,
- eDate = dayEnd
- )
- retVal.append(mp)
-
- return retVal
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def countPersonsForDay(self, date):
- """
- Method countPersonsForDay(date)
- Requires date argument, which is an instance of datetime.date object.
- It defines the day we want to count all MPs. The method is used to
- render charts.
- Returns the number of MPs for particular day.
- """
- select = """
- SELECT DISTINCT person.id
- FROM psp_person AS person
- INNER JOIN psp_group AS party ON party.type LIKE 'KLUB'
- INNER JOIN psp_membership AS partymship ON
- partymship.group_id = party.id AND
- partymship.post LIKE 'člen' AND
- partymship.person_id = person.id AND
- ((partymship.end IS NULL AND
- partymship.start <= '%d-%02d-%02d'
- ) OR (
- '%d-%02d-%02d' BETWEEN partymship.start AND
- partymship.end
- ))
- GROUP BY person.id;
- """
- select = select % ( date.year, date.month, date.day,
- date.year, date.month, date.day
- )
- cursor = connection.cursor()
- cursor.execute(select)
- return len(cursor.fetchall())
- def getRebels(self, dayStart, dayEnd = None, desc = True, colName = 'same'):
- """
- Method getRebels(dayStart, dayEnd = None, desc = True, colName = 'same')
- Retrieves the list of MPs ordered by poll divergence. Rebels are MPs
- who are voting against majority of their own party club. The higher
- divergence in poll results between particular MP and his/her club the
- bigger rebel MP is. The only mandatory argument is dayStart, which is
- an instance of datetime.date class. The other arguments are optional:
- dayEnd - if defined then the list of MPs is retrieved for
- day range <dayStart, dayEnd>
- orderDesc - by default the rebels (those who diverge most)
- will be at the begining of the list.
- colName - by default we are ordering by 'same' column, other
- possible (reasonable values are):
- activeSame
- Same vs. Active - in case of accordance of MP's we need to distinguish
- between rebels and active rebels. Rebels are all MP's whose results
- differ with majority vote of theri party club including absences - MP's
- absences are also included into calculation. The activeSame column,
- ignore does not include polls, where particular MP was not present,
- only polls, where given MP was actively participating in, these will
- be included, thus we call them active - actively voting against
- majority of party club.
- Returns list of MPs ordered by result divergence between them and their
- party club.
- """
- select = None
- order = None
- if desc:
- order = 'DESC'
- else:
- order = 'ASC'
- activeParm = '\n'
- if dayEnd != None:
- select = """
- SELECT
- person.id,
- person.mpId,
- person.name,
- person.surname,
- person.title,
- person.titleLast,
- person.birthDate,
- person.email,
- person.office,
- person.regionOffice,
- person.phone,
- person.slug,
- person.homePage,
- person.nasiPoliticiUrl,
- pgroup.id AS id,
- SUM( CASE
- WHEN gstats.result = mpvote.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(1) AS total,
- SUM( CASE
- WHEN mpvote.result IN ('A', 'N', 'Z') THEN
- CASE
- WHEN gstats.result = mpvote.result THEN 1
- ELSE 0
- END
- ELSE 0
- END
- ) AS activeSame,
- SUM( CASE
- WHEN mpvote.result IN ('A', 'N', 'Z') THEN 1
- ELSE 0
- END
- ) AS activeTotal
- FROM psp_person AS person,
- psp_membership AS mship,
- psp_group AS pgroup,
- psp_groupstats AS gstats,
- psp_mpvote AS mpvote,
- psp_poll AS poll
- WHERE pgroup.type LIKE 'KLUB' AND
- mship.group_id = pgroup.id AND
- mship.person_id = person.id AND
- mship.post LIKE '%%%%len' AND
- --we will handle lower bound first
- (('%d-%02d-%02d' BETWEEN mship.start AND mship.end) OR
- ('%d-%02d-%02d' > mship.start AND mship.end IS NULL)) AND
- --we will handle upper bound next
- (('%d-%02d-%02d' BETWEEN mship.start AND mship.end) OR
- ('%d-%02d-%02d' > mship.start AND mship.end IS NULL)) AND
- mpvote.poll_id = poll.id AND mpvote.person_id = person.id AND %s
- gstats.poll_id = poll.id AND gstats.group_id = pgroup.id AND
- poll.date BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d'
- GROUP BY person.id
- ORDER BY %s %s;
- """
- select = select % ( dayStart.year, dayStart.month, dayStart.day,
- dayStart.year, dayStart.month, dayStart.day,
- dayEnd.year, dayEnd.month, dayEnd.day,
- dayEnd.year, dayEnd.month, dayEnd.day,
- activeParm,
- dayStart.year, dayStart.month, dayStart.day,
- dayEnd.year, dayEnd.month, dayEnd.day,
- colName, order
- )
- else:
- select = """
- SELECT
- person.id,
- person.mpId,
- person.name,
- person.surname,
- person.title,
- person.titleLast,
- person.birthDate,
- person.email,
- person.office,
- person.regionOffice,
- person.phone,
- person.slug,
- person.homePage,
- person.nasiPoliticiUrl,
- pgroup.id,
- SUM( CASE
- WHEN gstats.result = mpvote.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(1) AS total,
- SUM( CASE
- WHEN mpvote.result IN ('A', 'N', 'Z') THEN
- CASE
- WHEN gstats.result = mpvote.result THEN 1
- ELSE 0
- END
- ELSE 0
- END
- ) AS activeSame,
- SUM( CASE
- WHEN mpvote.result IN ('A', 'N', 'Z') THEN 1
- ELSE 0
- END
- ) AS activeTotal
- FROM psp_person AS person,
- psp_membership AS mship,
- psp_group AS pgroup,
- psp_groupstats AS gstats,
- psp_mpvote AS mpvote,
- psp_poll AS poll
- WHERE pgroup.type LIKE 'KLUB' AND
- mship.group_id = pgroup.id AND
- mship.person_id = person.id AND
- mship.post LIKE '%%%%len' AND
- (('%d-%02d-%02d' BETWEEN mship.start AND mship.end) OR
- ('%d-%02d-%02d' > mship.start AND mship.end IS NULL)) AND
- mpvote.poll_id = poll.id AND mpvote.person_id = person.id AND %s
- gstats.poll_id = poll.id AND gstats.group_id = pgroup.id AND
- poll.date = '%d-%02d-%02d'
- GROUP BY person.id
- ORDER BY %s %s;
- """
- select = select % ( dayStart.year, dayStart.month, dayStart.day,
- dayStart.year, dayStart.month, dayStart.day,
- activeParm,
- dayStart.year, dayStart.month, dayStart.day,
- colName, order
- )
- cursor = connection.cursor()
- cursor.execute(select)
- retVal = []
- for row in cursor.fetchall():
- mp = self.createPersonFromRow(row)
- mp.party = Group.objects.get(id = row[14])
- mp.accordance = Accordance(
- same = row[15],
- diff = row[16] - row[15],
- sDate = dayStart,
- eDate = dayEnd
- )
-
- #if MP was not present at all, then pretend
- #100% activeAccordance
- if row[17] == 0 and row[18] == 0:
- mp.activeAccordance = Accordance(
- same = 10,
- diff = 0,
- sDate = dayStart,
- eDate = dayEnd
- )
- else:
- mp.activeAccordance = Accordance(
- same = row[17],
- diff = row[18] - row[17],
- sDate = dayStart,
- eDate = dayEnd
- )
- retVal.append(mp)
-
- return retVal
- class Person(AutoSlug):
- """
- Class Person(AutoSlug)
- Person instances represent MPs. The default manager for class is
- PersonManager. There are just few attributes fetched from
- person table in DB:
- mpId - MP's ID (primary key) at psp.cz
- name - MP's name
- surname - MP's surname
- title - title in front of name
- titleLast - title after the person's name
- birthDate - birth date
- email
- homePage - URLField with link to MP's blog/homepage
- office - address to office
- regionOffice - region office address
- phone,
- slug - slug field is composed of name and surname on instance save
- i.e. josef_novak
- nasiPoliticiUrl - link to MP's profile at www.nasipolitici.cz
- The rest of attributes are volatile - they are computed by select and
- added to instance.
- """
- mpId = models.CharField(
- _("MP ID"), unique = True, max_length = 10, db_index = True
- )
- name = models.CharField(_("Name"), max_length = 30)
- surname = models.CharField(_("Surname"), max_length = 30)
- title = models.CharField(_("Title"), max_length = 10, blank = True)
- titleLast = models.CharField(
- _("Title after Name"), max_length = 10, blank = True
- )
- birthDate = models.DateField(_("Birthdate"))
- email = models.EmailField(_("Email"))
- homePage = models.URLField(
- _("Homepage"), blank = True, verify_exists = False
- )
- office = models.CharField(_("Office"), max_length = 40)
- regionOffice = models.CharField(
- _("Electoral Ward Office"), max_length = 60
- )
- phone = PhoneNumberField(_("Phone Number"))
- slug = models.SlugField(db_index = True, unique = True)
- nasiPoliticiUrl = models.CharField(
- _("Link to NasiPolitici site"), max_length = 120, blank = True
- )
- slugs = {
- 'slug' : ('name', 'surname', 'title', 'titleLast')
- }
- votes = None
- objects = PersonManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("MP")
- verbose_name_plural = _("MPs")
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
-
- @property
- def sex(self):
- """
- Property sex
- There are two values possible:
- 'F' - for woman
- 'M' - for man
- The value is derrived from name.
- """
- retVal = ''
- #suppress 'no endswith member' warning
- #pylint: disable-msg=E1101
- try:
- retVal = self._sex
- except AttributeError:
- #suppress warning 'Attribute _sex defined outside of init'
- #pylint: disable-msg=W0201
- if self.name.endswith('a') and \
- not self.surname.endswith(u'ý'):
- #suppress warning 'Attribute _sex defined outside of init'
- #pylint: disable-msg=W0201
- self._sex = 'F'
- else:
- self._sex = 'M'
- retVal = self._sex
- return retVal
-
- def getTermLinks(self, currentTerm = None):
- """
- Method getTermLinks(currentTerm = None)
- Method renders a html elements with links, to MP's profiles for each term.
- If optional parameter currentTerm is used then the matching term will
- be just listed, no link will be generated for it.
- Returns list of html elements - links to terms
- """
- retVal = []
- url = u''
- for parlMship in self.getParlMemberships():
- url = u''
- term = parlMship.group.term
- content = '%d - %d' % (term.getStart(), term.getEnd(),)
- if currentTerm != None and term == currentTerm:
- url = u'<span>%s</span>' % content
- url += u'<span class="ui-icon ui-icon-triangle-1-w"></span>'
- else:
- url = u'<a href="%s">%s</a>' % (
- reverse('show_mp_term', args = [
- self.slug,
- str(term.getStart()),
- str(term.getEnd())
- ]),
- content
- )
- retVal.append(url)
-
- return retVal
-
- def getParlMemberships(self):
- """
- Method getParlMemberships()
- Returns a django.query.queryset instance with all MP's memberships in
- group type 'PARLAMENT'. This is the easiest way to find out all terms
- the given MP was working in PARLAMENT.
- Returns a queryset
- """
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- retVal = self.membership_set.filter(
- group__type__iexact = 'PARLAMENT',
- post__iregex = '.*POSLAN.*'
- )
- return retVal
- def getGroups(self, term):
- """
- Method getGroups(term)
- Method returns a django.queryset instance, which retrieves all
- memberships except the membership in group 'PARLAMENT' for given MP in
- chosen term. The term is mandatory parameter.
- Returns a queryset
- """
- retVal = []
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- if term != None:
- retVal = self.membership_set.filter(
- ~Q(group__type__iexact = 'PARLAMENT'),
- group__term = term,
- post__iregex = u'.len'
- )
- else:
- retVal = self.membership_set.filter(
- ~Q(group__type__iexact = 'PARLAMENT'),
- post__iregex = u'.len'
- )
- return retVal
- def getMshipsForDateRange(self, dateStart, dateEnd = None):
- """
- Method getMshipsForDateRange(dateStart, dateEnd = None)
- Method returns django.query.queryset instance, which will retrieve all
- MP's membership in groups except group PARLAMENT in given date range
- defined by <dateStart, dateEnd>. Both arguments are instances of
- datetime.date class. If no dateEnd is specified method will return MP's
- membership for given date specified by dateStart.
- Returns a django.query.queryset instance
- """
-
- retVal = None
- term = TermOfOffice.get_term_for_date(dateStart)
- if dateEnd == None:
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- try:
- retVal = self.membership_set.filter(
- ~Q(group__type__iexact = 'PARLAMENT'),
- Q(start__lte = dateStart, end__gte = dateStart)|
- Q(start__lte = dateStart, end = None),
- group__term = term
- )
- except FieldError:
- retVal = self.membership_set.filter(
- ~Q(group__type__iexact = 'PARLAMENT'),
- start__lte = dateStart,
- end = None,
- group__term = term
- )
- else:
- try:
- #suppress 'no membership_set member' warning
- retVal = self.membership_set.filter( #pylint: disable-msg=E1101
- ~Q(group__type__iexact = 'PARLAMENT'),
- Q(start__lt = dateEnd) |
- Q(start__lte = dateStart, end__gte = dateEnd) |
- Q(end__range = (dateStart, dateEnd)),
- group__term = term
- )
- except FieldError:
- #suppress 'no membership_set member' warning
- retVal = self.membership_set.filter( #pylint: disable-msg=E1101
- ~Q(group__type__iexact = 'PARLAMENT'),
- Q(start__lt = dateEnd) |
- Q(start__lte = dateStart, end = None),
- group__term = term
- )
- return retVal
- def getPartyClub(self, date):
- """
- Method getPartyClub(date)
- Method returns the group instance of type 'KLUB' (which is a party club
- the MP is member of) for single date. The date is mandatory parameter -
- the instance of datetime.date class.
- Returns group instance of type 'KLUB'
- """
- t = TermOfOffice.get_term_for_date(date)
- retVal = None
- try:
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- partyMship = self.membership_set.get(
- group__type__iexact = 'KLUB',
- group__term = t,
- post__iregex = u'.len',
- start__lte = date,
- end__gte = date
- )
- retVal = partyMship.group
- except ObjectDoesNotExist:
- #suppress 'no membership_set member' warning
- try:
- partyMship = self.membership_set.get(#pylint: disable-msg=E1101
- group__type__iexact = 'KLUB',
- group__term = t,
- post__iregex = u'.len',
- end = None
- )
- retVal = partyMship.group
- except MultipleObjectsReturned:
- #suppress 'no membership_set member' warning
- partyMship = \
- self.membership_set.filter(#pylint: disable-msg=E1101
- group__type__iexact = 'KLUB',
- group__term = t,
- post__iregex = u'.len',
- end = None
- ).order_by('-start')
- retVal = partyMship[0].group
- except MultipleObjectsReturned:
- partyMship = self.membership_set.filter(
- group__type__iexact = 'KLUB',
- group__term = t,
- post__iregex = u'.len',
- start__lte = date,
- end__gte = date
- )
- retVal = partyMship[0].group
- return retVal
- def getPartyMships(self, term):
- """
- Method getPartyMships(term)
- Method retrieves all memberships in party clubs for given MP in chosen term.
- The term is mandatory argument - instance of TermOfOffice class.
- Returns a django.query.queryset instance
- """
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- retVal = self.membership_set.filter(
- group__term = term,
- group__type__iexact = 'KLUB'
- ).order_by('start')
- return retVal
- def getAccordanceCharts(self, group, dateStart, dateEnd = None):
- """
- Method getAccordanceCharts(group, dateStart, dateEnd = None)
-
- Returns a tupple, which consists of two pieCharts describing MP's
- accordances with group. The first tupple member describes accordance
- with group - the date include all meetings in given period. The second
- chart in tupple does not cover polls, where particular MP was not
- present. The arguments are as follows:
- group - the group (either instance or id) we want to get
- accordance chart for
- dateStart - instance of datetime.date class
- dateEnd - optional argument in case we want to
- get accodance charts for period
- <dateStart, dateEnd>
- Returns tupple (accordanceChart, activeAccordanceChart)
- """
- mp = self.getAccordanceWithGroup(
- group = group,
- dateStart = dateStart,
- dateEnd = dateEnd
- )
- if mp == None:
- return (None, None,)
- groupAccordance = mp.accordance.getChart()
- title = None
- if group.type == 'KLUB':
- title = _('%s. %s shoda s %s') % (
- mp.name[0], mp.surname, group.getPartyName()
- )
- else:
- title = _('%s. %s shoda s %s') % (
- mp.name[0], mp.surname, group.name
- )
- groupAccordance.title(title)
- groupAccordance.size(330, 80)
- activeGroupAccordance = mp.activeAccordance.getChart()
- title = None
- if group.type == 'KLUB':
- title = _('%s. %s - aktivní shoda s %s') % (
- mp.name[0], mp.surname, group.getPartyName()
- )
- else:
- title = _('%s. %s - acktiví shoda s %s') % (
- mp.name[0], mp.surname, group.name
- )
- activeGroupAccordance.title(title)
- activeGroupAccordance.size(330, 80)
- return (groupAccordance, activeGroupAccordance,)
-
- def getAccordanceWithGroup(self, group, dateStart = None, dateEnd = None):
- """
- Method getAccordanceWithGroup(group, dateStart, dateEnd = None)
- Retrieves a poll accordance data for MP with group. Person object is
- extended by two 'accordance' attributes. Accordance attribute is the
- instance of Accordance class. The arguments are as follows:
- group - group to compute accordance with
- dayStart - date object defining start day
- dayEnd - date object defining end day, it is optional
- parameter, if no dayEnd is specified, then accordance
- for desired dayStart date is retreived only.
- The new two attributes added to self instance are:
- accordance - MP's poll accordance with group
- activeAccordance - MP's poll accordance with group (only
- polls, where MP is present are counted)
- Returns self extended by two new attributes - accordance and
- activeAccordance. Both attribute are instances of Accordance class.
- """
- groupId = group_to_id(group)
- select = None
- if dateEnd == None and dateStart == None:
- try:
- dateStart = Membership.objects.filter(
- group__id = groupId
- ).order_by('start')[0].start
- dateEnd = Membership.objects.filter(
- group__id = groupId,
- end = None
- )
- if len(dateEnd) == 0:
- dateEnd = Membership.objects.filter(
- group__id = groupId
- ).order_by('-end')[0].end
- else:
- dateEnd = datetime.date.today()
- except IndexError:
- return None
-
- if dateEnd != None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result <> vote.result THEN 1
- ELSE 0
- END
- ) AS different,
- SUM(
- CASE
- WHEN gs.result == vote.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(
- CASE
- WHEN vote.result IN ('A', 'N', 'Z') AND
- gs.result != vote.result THEN 1
- ELSE 0
- END
- ) AS activeDifferent,
- SUM(
- CASE
- WHEN vote.result IN ('A', 'N', 'Z') AND
- gs.result == vote.result THEN 1
- ELSE 0
- END
- ) AS activeSame
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS vote ON
- poll.id = vote.poll_id AND
- vote.person_id = %d
- INNER JOIN psp_groupstats AS gs ON
- poll.id = gs.poll_id AND
- gs.group_id = %d
- WHERE poll.date BETWEEN '%d-%02d-%02d' AND
- '%d-%02d-%02d';
- """
- #suppressing 'Person has no attribute id' warning
- select = select % ( self.id,#pylint: disable-msg=E1101
- groupId,
- dateStart.year, dateStart.month, dateStart.day,
- dateEnd.year, dateEnd.month, dateEnd.day,
- )
- else:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result <> vote.result THEN 1
- ELSE 0
- END
- ) AS different,
- SUM(
- CASE
- WHEN gs.result == vote.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(
- CASE
- WHEN vote.result IN ('A', 'N', 'Z') AND
- gs.result != vote.result THEN 1
- ELSE 0
- END
- ) AS activeDifferent,
- SUM(
- CASE
- WHEN vote.result IN ('A', 'N', 'Z') AND
- gs.result == vote.result THEN 1
- ELSE 0
- END
- ) AS activeSame
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS vote ON
- poll.id = vote.poll_id AND
- vote.person_id = %d
- INNER JOIN psp_groupstats AS gs ON
- poll.id = gs.poll_id AND
- gs.group_id = %d
- WHERE poll.date = '%d-%02d-%02d';
- """
- #suppressing 'Person has no attribute id' warning
- select = select % ( self.id,#pylint: disable-msg=E1101
- groupId,
- dateStart.year, dateStart.month, dateStart.day,
- )
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- if len(rows) != 1:
- return None
- row = rows[0]
- #suppress warning 'Attribute _sex defined outside of init'
- #pylint: disable-msg=W0201
- self.accordance = Accordance(
- diff = row[0],
- same = row[1],
- sDate = dateStart,
- eDate = dateEnd
- )
- #if MP was not present at all, then pretend
- #100% activeAccordance
- if row[2] == 0 and row[3] == 0:
- #suppress warning 'Attribute _sex defined outside of init'
- #pylint: disable-msg=W0201
- self.activeAccordance = Accordance(
- diff = 0,
- same = 10,
- sDate = dateStart,
- eDate = dateEnd
- )
- else:
- #suppress warning 'Attribute _sex defined outside of init'
- #pylint: disable-msg=W0201
- self.activeAccordance = Accordance(
- diff = row[2],
- same = row[3],
- sDate = dateStart,
- eDate = dateEnd
- )
- return self
- def getPersonWithStats(self, dayStart, dayEnd = None):
- """
- Method getPersonWithStats(dayStart, dateEnd = None)
- Retrives statistics for person. The person will be extended by
- attribute votes, which is instance of Votes class. The arguments
- are as follows:
- dayStart - instance of datetime.date class with desired
- day we want to gather stats for
- dayEnd - optional, if specified then <dateStart, dateEnd>
- range is used instead of single day.
- Returns a self object extended by votes attribute (the instance
- of Votes class).
- """
- #save cycles in case the votes attribute already exists
- if self.votes != None and\
- self.votes.startDate == dayStart and self.votes.endDate == dayEnd:
- return self
- if dayEnd == None:
- select = """
- SELECT SUM(
- CASE
- WHEN vote.result = 'M' THEN 1
- ELSE 0
- END
- ) AS excs,
- SUM(
- CASE
- WHEN vote.result = '0' OR
- vote.result = 'X' THEN 1
- ELSE 0
- END
- ) AS abs,
- SUM(
- CASE
- WHEN vote.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM (
- CASE
- WHEN vote.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM (
- CASE
- WHEN vote.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS vote ON
- poll.id = vote.poll_id AND
- vote.person_id = %d
- WHERE poll.date = '%d-%02d-%02d';
- """
- select = select % (
- #suppressing 'Person has no attribute id' warning
- self.id,#pylint: disable-msg=E1101
- dayStart.year, dayStart.month, dayStart.day
- )
- else:
- select = """
- SELECT SUM(
- CASE
- WHEN vote.result = 'M' THEN 1
- ELSE 0
- END
- ) AS excs,
- SUM(
- CASE
- WHEN vote.result = '0' OR
- vote.result = 'X' THEN 1
- ELSE 0
- END
- ) AS abs,
- SUM(
- CASE
- WHEN vote.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM (
- CASE
- WHEN vote.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM (
- CASE
- WHEN vote.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS vote ON
- poll.id = vote.poll_id AND
- vote.person_id = %d
- WHERE poll.date BETWEEN '%d-%02d-%02d' AND
- '%d-%02d-%02d';
- """
- select = select % (
- #suppressing 'Person has no attribute id' warning
- self.id,#pylint: disable-msg=E1101
- dayStart.year, dayStart.month, dayStart.day,
- dayEnd.year, dayEnd.month, dayEnd.day
- )
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- if len(rows) != 1:
- return None
- row = rows[0]
- retVal = Person(self)
- retVal.votes = Votes(
- excused = row[0],
- absences = row[1],
- vNay = row[2],
- vRefrains = row[3],
- vAye = row[4],
- sDate = dayStart,
- eDate = dayEnd
- )
- return retVal
-
- pre_save.connect(makeSlug, Person)
- class PersonDetail(models.Model):
- """
- Class PersonDetail(models.Model)
- PersonDetail class holds data for MP and specific term.
- These attributes are fetched from DB:
- region - foreign key, which referes to division
- person - foreign key, which referes to person
- term - foreign key, which referes to term, the record is bound to
- photo - of given MP
- """
- region = models.ForeignKey(Division, blank = True, null = True)
- person = models.ForeignKey(Person)
- term = models.ForeignKey(TermOfOffice)
- photo = models.ImageField( _("Photo"),
- upload_to = settings.MP_PHOTOS
- )
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Person's Additional Info")
- verbose_name_plural = _("Person's Additional Info")
-
- class GroupManager(models.Manager):
- """
- Class GroupManager(models.Manager)
- The GroupManager is a default custom manager for class Group.
- """
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def getGroupWithStats(self, term, qType, poll):
- """
- Method getGroupWithStats(term, qType, poll)
- Method retrives a list of groups extended by stat attribute,
- which is an instance of GroupStats class. The arguments are:
- term - TermOfOffice instance
- qType - django.db.models.Q object - it is used to perform
- custom filtering by group type
- poll - instance of Poll class, it presents the particular
- poll we want to gather data for
- Returns the list of groups extended by stat attribute (instance of
- GroupStats). The groups are ordered by name.
- """
- retVal = []
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- for g in Group.objects.filter(
- Q(term = term),
- qType).order_by('name'):
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- g.stat = GroupStats.objects.get(group = g, poll = poll)
- except ObjectDoesNotExist:
- g.stat = None
- subGroups = []
- for sg in g.children.all():
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- sg.stat = GroupStats.objects.get(
- group = sg,
- poll = poll
- )
- except ObjectDoesNotExist:
- g.stat = None
- subGroups.append(sg)
- g.subGroups = subGroups
- retVal.append(g)
- return retVal
- def getGroupWithStatsArg(self, poll, qObjs):
- """
- Method getGroupWithStatsArg(poll, qObjs)
- Method retrieves the list of groups. Each Group instance in the list
- will be extended by attribute stat (instance of GroupStats class). The
- method allows caller to finely define the desired querset parameter by
- using qObjs argument. The arguments are as follows:
- poll - the poll we want to gather stats for
- qObjs - the args for filter() method from queryset,
- it's basically tupple of django.db.models.Q instances
- Returns list of groups extended by stat attribute, which is an instance
- of GroupStats class.
- """
- retVal = []
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- #suppress used * or ** magic
- #pylint: disable-msg=W0142
- for g in Group.objects.filter(*qObjs).order_by('name'):
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- g.stat = GroupStats.objects.get(group = g, poll = poll)
- except ObjectDoesNotExist:
- g.stat = None
- subGroups = []
- for sg in g.children.all():
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- sg.stat = GroupStats.objects.get(
- group = sg,
- poll = poll
- )
- except ObjectDoesNotExist:
- sg.stat = None
- subGroups.append(sg)
- g.subGroups = subGroups
- retVal.append(g)
- return retVal
-
- class Group(AutoSlug):
- """
- Class Group(AutoSlug)
- Group represents any group of MP's, which participates in parliament
- in given term. These attributes are stored into DB:
- term - ForeignKey to term
- members - ManyToManyField links person through Membership
- table
- groupId - group ID (key) from psp.cz
- name - group name used in jakhlasovali.cz site
- origName - group name used in psp.cz site.
- type - type of group can be: party, board, subboard, ...
- coulor - colour assigned to group when generating charts,
- currently is used just for party clubs
- icon - icon assigned to group (currently unused)
- slug - slug field to generate human friendly urls
-
- Certain queries will compute extra attributes:
- group consistency, votes, ...
- The Group class is using GroupManager as a default manager.
- """
- term = models.ForeignKey(TermOfOffice)
- members = models.ManyToManyField( Person,
- through='Membership',
- blank = True,
- null = True
- )
- parentGroup = models.ForeignKey( 'self',
- related_name = 'children',
- blank = True,
- null = True
- )
- groupId = models.CharField(_("Group Id"), max_length = 20)
- name = models.CharField(_("Name"), max_length = 512)
- origName = models.CharField(_("Name"), max_length = 1024)
- type = models.CharField(_("Club Type"), max_length = 50, blank = True)
- color = models.CharField(_("Colour"), max_length = 6, blank = True)
- icon = models.ImageField(_("Club Icon"),
- upload_to = settings.GROUP_ICONS,
- blank = True
- )
- slug = models.SlugField(db_index = True)
- slugs = {
- 'slug' : ('name', )
- }
- consistency = None
- activeConsistency = None
- votes = None
- objects = GroupManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("MP Organ (party/board/...)")
- verbose_name_plural = _("MP Organs (parties/boards/...)")
- unique_together = (('term', 'groupId',),)
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- def getMembersCommon(self,
- dateStart = None,
- dateEnd = None,
- orderArg = None,
- distinct = True):
- """
- Method getMembersCommon(dateStart = None, dateEnd = None,
- orderArg = None, distinct = True)
- Returns list of person objects - members of group. If no date is
- specified returns summary for complete term, otherwise returns member
- list valid for particular date range. If dateStart only is specified,
- then actual list for given date is returned.
- Each person object in list returned is extended by these attributes:
- mship,
- days,
- and:
- age,
- partyClub,
- division,
- ...
- [ all attributes inserted by PersonManager.commonSelect ]
- """
- mships = None
- if dateStart == None and dateEnd == None:
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- mships = self.membership_set.all()
- elif dateStart != None and dateEnd == None:
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- mships = self.membership_set.filter(
- Q(end = None) | Q(end__gte = dateStart),
- start__lte = dateStart
- )
- elif dateStart != None and dateEnd != None:
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- mships = self.membership_set.filter(
- ~Q(end = None),
- Q(end__gte = dateEnd),
- start__lte = dateStart
- )
- else:
- return []
- if orderArg:
- mships = mships.order_by(orderArg)
- #
- # we have to fake distinct by person, if we are asked to do so
- #
- if distinct:
- tmp = {}
- for m in mships:
- tmp[m.person.id] = m
-
- mships = []
- for k in tmp.keys():
- mships.append(tmp[k])
- retVal = []
- for m in mships:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- person = Person.objects.getPerson(m.person, self.term)
- person.mship = m
- person.start = m.start
- person.end = m.end
- person.post = m.post
- if m.end == None:
- person.days = (datetime.date.today() - m.start).days
- else:
- person.days = (m.end - m.start).days
- retVal.append(person)
- return retVal
- def getMembersByAge(self, desc = True, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByAge(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByAge() to retrieve list of persons (members of group)
- ordered by age. The arguments are as follows:
- desc - if true the members will be ordered from the oldest
- to youngest
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = self.getMembersCommon(dateStart, dateEnd,
- distinct = distinct
- )
- if desc:
- retVal.sort(lambda a, b: a.age - b.age)
- else:
- retVal.sort(lambda a, b: b.age - a.age)
- return retVal
- #suppress warning 'Unused argument distinct'
- #pylint: disable-msg=W0613
- def getMembersByParty(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByParty(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByParty() to retrieve list of persons (members of group)
- ordered by party they member of. The arguments are as follows:
- desc - if false the members will be ordered by party name in
- alphabetical order
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = self.getMembersCommon(dateStart, dateEnd,
- distinct = True
- )
- if desc:
- retVal.sort(lambda a, b: a.partyName > b.partyName)
- else:
- retVal.sort(lambda a, b: a.partyName < b.partyName)
- return retVal
- def getMembersByName(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByName(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByName() to retrieve list of persons (members of group)
- ordered by their names. The arguments are as follows:
- desc - if false the members will be ordered by name in
- alphabetical order.
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = None
- if desc:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- '-person__name',
- distinct = distinct
- )
- else:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- 'person__name',
- distinct = distinct
- )
- return retVal
- def getMembersBySurname(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersBySurname(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersBySurname() to retrieve list of persons (members of
- group) ordered by their surname. The arguments are as follows:
- desc - if false the members will be ordered by surname in
- alphabetical order.
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = None
- if desc:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- '-person__surname',
- distinct = distinct
- )
- else:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- 'person__surname',
- distinct = distinct
- )
-
- return retVal
-
- def getMembersByDivision(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByDivision(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByDivision() to retrieve list of persons (members of
- group) ordered by the electoral division. The arguments are as follows:
- desc - if false the members will be ordered by division name
- in alphabetical order.
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = self.getMembersCommon(dateStart, dateEnd, distinct = distinct)
- if desc:
- retVal.sort(lambda a, b: a.divisionName > b.divisionName)
- else:
- retVal.sort(lambda a, b: a.divisionName < b.divisionName)
- return retVal
- def getMembersByDays(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByDays(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByDays() to retrieve list of persons (members of group)
- ordered by the number of days their membership lasts. The arguments
- are as follows:
- desc - if true the members will be ordered from the longest
- membership to the shortest one.
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = self.getMembersCommon(dateStart, dateEnd, distinct = distinct)
- if desc:
- retVal.sort(lambda a, b: a.days > b.days)
- else:
- retVal.sort(lambda a, b: a.days < b.days)
- return retVal
- def getMembersByStart(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByStart(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByStart() to retrieve list of persons (members of group)
- ordered by the start of their membership. The arguments are as
- follows:
- desc - if false the members will be ordered from the oldest date
- to recent ones
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = None
- if desc:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- '-start',
- distinct = distinct
- )
- else:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- 'start',
- distinct = distinct
- )
- return retVal
- def getMembersByEnd(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByEnd(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByEnd() to retrieve list of persons (members of group)
- ordered by the end date of their membership. The arguments are as
- follows:
- desc - if false the members will be ordered from the oldest
- end dates to recent ones
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = None
- if desc:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- '-end',
- distinct = distinct
- )
- else:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- 'end',
- distinct = distinct
- )
- return retVal
- def getMembersByPost(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByPost(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByPost() to retrieve list of persons (members of group)
- ordered by their membership post (member (člen), head (předseda)). The
- arguments are as follows:
- desc - if false the members will be ordered from the oldest
- end dates to recent ones
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = None
- if desc:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- '-post',
- distinct = distinct
- )
- else:
- retVal = self.getMembersCommon(
- dateStart,
- dateEnd,
- 'post',
- distinct = distinct
- )
- return retVal
- def getMembersByAbsences(self, desc = False, dateStart = None,
- dateEnd = None, distinct = True):
- """
- Method getMembersByAbsences(desc = True, dateStart = None
- dateEnd = None, distinct = True)
-
- Uses getMembersByAbsences() to retrieve list of persons (members of group)
- ordered by their absences. The arguments are as follows:
- desc - if false the members will be ordered from the highest
- absences to the lowest absences number.
- dateStart - date we want to retrieve members for
- dateEnd - if date end is specified then method wil retrieve
- persons for <dateStart, dateEnd> range.
- if no date is specified members for complete term
- are returned
- distinct - only one membership will be retreived for person,
- person might have several memberships, which can
- overlap (member, prime member, ...)
- Returns list of persons, it uses commonSelect to construct list.
- """
- retVal = self.getMembersCommon(dateStart, dateEnd, distinct = distinct)
- if desc:
- retVal.sort(
- lambda a, b: int(a.votes.totalAbsences - b.votes.totalAbsences)
- )
- else:
- retVal.sort(
- lambda a, b: int(b.votes.totalAbsences - a.votes.totalAbsences)
- )
-
- return retVal
- def getGroupPartyProfile( self,
- dateStart = None,
- dateEnd = None):
- """
- Method getGroupPartyProfile(dateStart = None, dateEnd = None)
- Returns list of parties the members of group are coming from. Each party
- group in list is extended by these parameters
- mpCount
- group - which is the self (the group we are braking down to parties rep)
- totalCount - number of members in self
- percent - relative percent of party members in self
- The arguments are:
- dateStart - retrieves data for particular date
- dateEnd - if specified retrieves data for range
- <dateStart, dateEnd>
- Returns list of party groups extended by mpCount, group, totalCount, percent
- """
- #suppress warning too many local variables
- #pylint: disable-msg=R0914
- if self.type == 'KLUB':
- return None
- select = None
- if dateStart == None and dateEnd == None:
- select = """
- SELECT groupId, SUM(num) FROM (
- SELECT partyMship.group_id AS groupId,
- COUNT(DISTINCT mp.id) AS num
- FROM psp_person AS mp,
- psp_membership AS mship
- JOIN psp_group AS party ON
- party.type LIKE 'KLUB' AND
- party.term_id = %d
- JOIN psp_membership AS partyMship ON
- mp.id = partyMship.person_id AND
- partyMship.group_id = party.id
- WHERE mship.group_id = %d AND mship.person_id = mp.id
- GROUP BY mp.id ORDER BY partyMship.group_id
- )
- GROUP BY groupId;
- """
- #suppress warning ForeignKey has no attribute id
- #pylint: disable-msg=E1101
- #suppress warning Group has no attribute id
- #pylint: disable-msg=E1101
- select = select % (self.term.id, self.id)
- elif dateStart != None and dateEnd == None:
- date = '%d-%02d-%02d' % ( dateStart.year,
- dateStart.month,
- dateStart.day
- )
- select = """
- SELECT groupId, SUM(num) FROM (
- SELECT partyMship.group_id AS groupId,
- COUNT(DISTINCT mp.id) AS num
- FROM psp_person AS mp,
- psp_membership AS mship
- JOIN psp_group AS party ON
- party.type LIKE 'KLUB' AND party.term_id = %d
- JOIN psp_membership AS partyMship ON
- mp.id = partyMship.person_id AND
- partyMship.group_id = party.id AND
- ( (partyMship.end IS NULL AND
- partyMship.start <= '%s') OR
- ('%s' BETWEEN partyMship.start AND
- partyMship.end)
- )
- WHERE mship.group_id = %d AND
- mship.person_id = mp.id AND
- ( (mship.end IS NULL AND
- mship.start <= '%s') OR
- ('%s' BETWEEN mship.start AND mship.end)
- )
- GROUP BY mp.id ORDER BY partyMship.group_id
- )
- GROUP BY groupId;
- """
- #suppress warning ForeignKey has no attribute id
- #pylint: disable-msg=E1101
- #suppress warning Group has no attribute id
- #pylint: disable-msg=E1101
- select = select % ( self.term.id,
- date, date,
- self.id,
- date, date
- )
- elif dateStart != None and dateEnd != None:
- start = '%d-%02d-%02d' % ( dateStart.year,
- dateStart.month,
- dateStart.day
- )
- end = '%d-%02d-%02d' % ( dateEnd.year,
- dateEnd.month,
- dateEnd.day
- )
- select = """
- SELECT groupId, SUM(num) FROM (
- SELECT partyMship.group_id AS groupId,
- COUNT(DISTINCT mp.id) AS num
- FROM psp_person AS mp, psp_membership AS mship
- JOIN psp_group AS party ON
- party.type LIKE 'KLUB' AND
- party.term_id = %d
- JOIN psp_membership AS partyMship ON
- mp.id = partyMship.person_id AND
- partyMship.group_id = party.id AND
- ((partyMship.end IS NULL AND
- (partyMship.start BETWEEN '%s' AND '%s' OR
- partyMship.start <= '%s'))
- OR
- (partyMship.start BETWEEN '%s' AND '%s' OR
- partyMship.end BETWEEN '%s' AND '%s') OR
- (partyMship.start <= '%s'))
- WHERE mship.group_id = %d AND
- mship.person_id = mp.id AND
- ((mship.end IS NULL AND
- (mship.start BETWEEN '%s' AND '%s' OR
- mship.start <= '%s'))
- OR
- (mship.start BETWEEN '%s' AND '%s' OR
- mship.end BETWEEN '%s' AND '%s') OR
- (mship.start <= '%s')
- )
- GROUP BY mp.id ORDER BY partyMship.group_id
- )
- GROUP BY groupId;
- """
- #suppress warning ForeignKey has no attribute id
- #pylint: disable-msg=E1101
- #suppress warning Group has no attribute id
- #pylint: disable-msg=E1101
- select = select % ( self.term.id,
- start, end, start,
- start, end, start, end,
- start,
- self.id,
- start, end, start,
- start, end, start, end,
- start,
- )
- else:
- raise ObjectDoesNotExist
-
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- retVal = []
- total = 0
- for row in rows:
- groupId = row[0]
- mpCount = row[1]
- total += mpCount
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- group = Group.objects.get(id = groupId)
- group.mpCount = mpCount
- group.group = self
- retVal.append(group)
- for g in retVal:
- g.totalCount = total
- g.percent = get_percents(g.mpCount, total)
-
- return retVal
-
- def getMfRatio(self):
- """
- Method getMfRatio()
- Returns the ratio between men and women in the group.
- """
- males = 0
- females = 0
- members = None
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- member_ids = self.membership_set.all().values('person_id').distinct()
- for m_id in member_ids:
- member = Person.objects.get(id = m_id['person_id'])
- if member.sex == 'F':
- females += 1
- else:
- males += 1
- return males, females
- def getMfPie(self):
- """
- Method getMfPie()
- Returns the GChart.Pie3D instance - chart representing ratio between
- men and women in the group.
- """
- male, female = self.getMfRatio()
- pm = get_percents(male, male + female)
- pf = get_percents(female, male + female)
- retVal = Pie3D([pm, pf])
- retVal.label(
- _(u'Muži') + ' %d' % male,
- _(u'Ženy') + ' %d' % female
- )
- retVal.color('000077', '770000')
- #suppress warning foreign key has no member getStart()
- #pylint: disable-msg=E1101
- #suppress warning foreign key has no meber getEnd()
- #pylint: disable-msg=E1101
- retVal.title(_(u'Poměr mužů a žen') + '(%d - %d)' % (
- self.term.getStart(),
- self.term.getEnd())
- )
- retVal.size(330, 130)
- return retVal
-
- def getPartyName(self):
- """
- Method getPartyName()
- Method converts long name format to acronum. The mpClub.name usually
- looks like
- Poslanecký klub Občasnské demokratické strany
- the method will turn it into abbreviation:
- ODS
- Returns string with party name acronum if group is party.
- """
- #work around Křesťansko demokratická strana-českosloven...
- #suppress warning foreign key has no meber replace
- #pylint: disable-msg=E1101
- name = self.origName.replace('-', ' - ')
- pattern = re.compile(u'.*Poslanecký klub(?P<name>.*)', re.U)
- match = pattern.match(name)
- retVal = u''
- if match:
- name = match.group('name')
-
- for i in name.split():
- if i == 'a' or i == 'A':
- continue
- retVal += i[0].upper()
- if retVal == 'N':
- retVal = _(u'Nezávislí')
- return retVal.strip()
- def getAvgAge(self):
- """
- Method getAvgAge()
- Returns the average age of group members.
- """
- retVal = 0
- totalAge = 0
- count = 0
- #suppress 'no membership_set member' warning
- #pylint: disable-msg=E1101
- members = self.membership_set.all().distinct('person')
- for member in members:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mp = Person.objects.get(id = member.person.id)
- age = self.term.getStart() - mp.birthDate.year
- totalAge += age
- count += 1
- if count != 0:
- retVal = totalAge / count
- return retVal
-
- def getPartyPie(self, dateStart = None, dateEnd = None):
- """
- Method getPartyPie(dateStart = None, dateEnd = None)
- Method returns party profile for group. It generates party profile
- either for single date, if dateStart only is specified or for
- <dateStart, dateEnd> range if both arguments are specified.
- If no argument is passed, then chart for complete term is
- returned.
- """
- partyProfile = self.getGroupPartyProfile(dateStart, dateEnd)
-
- if partyProfile == None:
- return None
- pieData = [ party.mpCount for party in partyProfile ]
- retVal = Pie3D(pieData)
- label = [ '%s (%.2f%%)' % ( party.getPartyName(),
- party.percent
- ) for party in partyProfile
- ]
- #suppress used * or ** magic
- #pylint: disable-msg=W0142
- retVal.label(*label)
- colors = ''
- for party in partyProfile:
- colors += party.color + '|'
- retVal.color(colors.strip('|'))
- if dateStart == None and dateEnd == None:
- #suppress warning foreign key has no member getStart()
- #pylint: disable-msg=E1101
- #suppress warning foreign key has no meber getEnd()
- #pylint: disable-msg=E1101
- title = u'%s (%d - %d)' % (
- self.name,
- self.term.getStart(),
- self.term.getEnd()
- )
- elif dateStart != None and dateEnd == None:
- title = u'%s (%s)' % (
- self.name,
- dateStart.strftime("%d. %m. %Y")
- )
- else:
- title = u'%s (%s - %s)' % (
- self.name,
- dateStart.strftime("%d. %m. %Y"),
- dateEnd.strftime("%d. %m. %Y")
- )
- retVal.title(title)
- retVal.size(400, 130)
- return retVal
- def getAccordanceWithGroup( self,
- otherGroup,
- dateStart = None,
- dateEnd = None
- ):
- """
- Method getAccordanceWithGroup(otherGroup,
- dateStart = None, dateEnd = None)
- Method generates accordance chart with 'otherGroup'.
- The arguments are:
- otherGroup - the group to be compared for accordance
- dateStart - dateStart if not specified the accordance for
- complete term is computed, otherwise for signle
- dateStart day only is computed.
- dateEnd - if specified then accordance for <dateStart,
- dateEnd> range is returned.
- Returns accordance with group chart.
- """
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- groupAccord = GroupStats.objects.getAccordanceWithGroup(
- self, otherGroup,
- dateStart, dateEnd
- )
- retVal = groupAccord.accordance.getChart()
- title = ''
- if self.type == 'KLUB':
- title = _(u'%s - shoda s ') % (self.getPartyName())
- else:
- title = _(u'%s - shoda s ') % (self.name)
- if otherGroup.type == 'KLUB':
- title += otherGroup.getPartyName()
- else:
- title += otherGroup.name
- retVal.title(title)
- retVal.size(330, 80)
- #suppress warning 'Attribute accordance defined outside of init'
- #pylint: disable-msg=W0201
- self.accordance = retVal
-
- return retVal
- def getPresencePieChart(self, dateStart = None, dateEnd = None):
- """
- Method getPresencePieChart(dateStart = None, dateEnd = None)
- Extends self by votes attribute, which is an instance of Votes class.
- If dateStart, dateEnd are None then presence pie chart for complete
- term is computed. If both arguments are specified then presence
- pie for <dateStart, dateEnd> range is returned.
- Returns Pie3D presence chart for given group.
- """
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- stats = GroupStats.objects.getStats(
- group = self,
- dateStart = dateStart,
- dateEnd = dateEnd
- )
- #suppress warning 'Attribute stats defined outside of init'
- #pylint: disable-msg=W0201
- self.stats = stats
- retVal = stats.votes.getPresenceChart()
-
- if self.type == 'KLUB':
- retVal.title(_(u'%s - absence %d - %d') % (
- self.getPartyName(),
- self.term.getStart(),
- self.term.getEnd()
- )
- )
- else:
- retVal.title(_(u'%s Absence %d - %d') % (
- self.name,
- self.term.getStart(),
- self.term.getEnd()
- )
- )
- retVal.size(330, 80)
- return retVal
- def getGroupConsistency(self, dateStart, dateEnd = None):
- """
- Method getGroupConsistency(dateStart, dateEnd = None)
- Returns self extended by two attributes:
- consistency
- activeConsistency
- both attributes are instances of Accordance class. Both attributes
- describe poll conistency inside the given group - group consistency.
- Group consistency is reflects the ratio between MPs, who voted with
- group majority vs. MPs who voted against the final group result.
- The activeConsistency does not account MP's absences.
- The date range we want to gather consistency for is defined as
- <dayStart, dayEnd> if no upper bound (dayEnd == None) is defined,
- then consistency data for single date (dayStart) are retreived.
- Method returns self on success, None on error.
- """
- def none2zero(x):
- """
- Internal function none2zero()
- Accepts argument 'x' if x is equal to None returns zero, otherwise
- returns x.
- """
- if x == None:
- return 0
- else:
- return x
- select = ''
- if dateEnd == None:
- select = """
- SELECT SUM (CASE
- WHEN gstats.result = vote.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM (CASE
- WHEN gstats.result != vote.result THEN 1
- ELSE 0
- END
- ) AS diff,
- SUM (CASE
- WHEN vote.result IN ('A', 'N', 'Z') THEN
- CASE
- WHEN gstats.result = vote.result THEN 1
- ELSE 0
- END
- ELSE 0
- END
- ) AS sameNoAbs,
- SUM (CASE
- WHEN vote.result IN ('A', 'N', 'Z') THEN
- CASE
- WHEN gstats.result != vote.result THEN 1
- ELSE 0
- END
- ELSE 0
- END
- ) AS diffNoAbs,
- SUM (1) AS total
- FROM psp_poll AS poll,
- psp_membership AS mship
- JOIN psp_groupstats AS gstats ON gstats.poll_id = poll.id AND
- gstats.group_id = %d
- JOIN psp_mpvote AS vote ON vote.person_id = mship.person_id AND
- mship.group_id = %d AND vote.poll_id = poll.id
- WHERE poll.date = '%d-%02d-%02d' AND mship.group_id = %d AND
- mship.post LIKE '_len' AND
- ((poll.date BETWEEN mship.start AND mship.end) OR
- (mship.start <= poll.date AND mship.end IS NULL))
- """
- #suppress 'Group has no id member' warning
- #pylint: disable-msg=E1101
- select = select % ( self.id,
- self.id,
- dateStart.year, dateStart.month, dateStart.day,
- self.id,
- )
- else:
- select = """
- SELECT SUM (CASE
- WHEN gstats.result = vote.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM (CASE
- WHEN gstats.result != vote.result THEN 1
- ELSE 0
- END
- ) AS diff,
- SUM (CASE
- WHEN vote.result IN ('A', 'N', 'Z') THEN
- CASE
- WHEN gstats.result = vote.result THEN 1
- ELSE 0
- END
- ELSE 0
- END
- ) AS sameNoAbs,
- SUM (CASE
- WHEN vote.result IN ('A', 'N', 'Z') THEN
- CASE
- WHEN gstats.result != vote.result THEN 1
- ELSE 0
- END
- ELSE 0
- END
- ) AS diffNoAbs,
- SUM (1) AS total
- FROM psp_poll AS poll,
- psp_membership AS mship
- JOIN psp_groupstats AS gstats ON gstats.poll_id = poll.id AND
- gstats.group_id = %d
- JOIN psp_mpvote AS vote ON vote.person_id = mship.person_id AND
- mship.group_id = %d AND vote.poll_id = poll.id
- WHERE poll.date BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d' AND
- mship.group_id = %d AND mship.post LIKE '_len' AND
- ((poll.date BETWEEN mship.start AND mship.end) OR
- (mship.start <= poll.date AND mship.end IS NULL));
- """
- #suppress 'Group has no id member' warning
- #pylint: disable-msg=E1101
- select = select % ( self.id,
- self.id,
- dateStart.year, dateStart.month, dateStart.day,
- dateEnd.year, dateEnd.month, dateEnd.day,
- self.id
- )
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
-
- if len(rows) != 1:
- return None
- row = rows[0]
- #suppress used builtin function 'map' warning
- #pylint: disable-msg=W0141
- row = map(none2zero, row)
- self.consistency = Accordance(
- same = row[0],
- diff = row[1],
- sDate = dateStart,
- eDate = dateEnd
- )
- self.activeConsistency = Accordance(
- same = row[2],
- diff = row[3],
- sDate = dateStart,
- eDate = dateEnd
- )
-
- return self
- pre_save.connect(makeSlug, Group)
- class Membership(models.Model):
- """
- Class Membership(models.Model)
- Class represents a membership of person in group.
- These attributes are fetched from DB:
- group - foreign key refering to group
- person - foreign key refering to person
- post - post bound to membership (member, head, ...)
- start - start date of membership
- end - end date of membership. if None then membership
- is still in progress.
- """
- group = models.ForeignKey(Group)
- person = models.ForeignKey(Person)
- post = models.CharField(_("Post"), max_length = 30)
- start = models.DateField(_("Start Date"))
- end = models.DateField(_("End Date"), blank = True, null = True)
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("MP Organ Membership")
- verbose_name_plural = _("MP Organs Membership")
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- def getStart(self):
- """
- Method getStart() returns self.start
- """
- return self.start
- def getEnd(self):
- """
- Method getEnd() returns self.end.
- If self.end is None then datetime.datetime.today()
- is returned.
- """
- if self.end == None:
- return datetime.datetime.today()
- return self.end
-
- def getDuration(self):
- """
- Method getDuration() returns time delta between start and date.
- """
- if self.end == None:
- today = datetime.datetime.today()
- return today - self.start
- return self.end - self.start
- class Meeting(models.Model):
- """
- Class Meeting(models.Model)
- Class meeting represents single meeting. These fields are fetched from DB:
- term - ForeignKey to TermOfOffice, when particular team happened
- meetingNo - the kind of meeting name (string) (i.e. '50', '51'...)
- start - datetime.date instance - start date of meeting
- end - datetime.date instance - end date of meeting, some meetings
- can last more than one day
- name - meeting name (i.e. '51. schuze')
- url - link to meeting data at psp.cz
- """
- term = models.ForeignKey(TermOfOffice)
- meetingNo = models.CharField(_("Meeting No."), max_length = 8)
- start = models.DateField(_("Start Date"))
- end = models.DateField(_("End Date"))
- name = models.CharField(_("Session Name"), max_length = 80)
- url = models.URLField(_("Link To Meeting Agenda"), verify_exists = False)
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Meeting")
- verbose_name_plural = _("Meetings")
-
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- class PollManager(models.Manager):
- """
- Class PollManager(models.Manager)
- Class is default manager for Polls.
- """
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def getMeetingDates(self):
- """
- Method getMeetingDates()
- Returns list of Poll instances grouped by date. Method is used in
- updateDB.py so far.
- """
- select = """
- SELECT date FROM psp_poll GROUP BY date ORDER BY date ASC;
- """
- retVal = []
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- for row in rows:
- retVal.append(row[0])
- return retVal
- class Poll(AutoSlug):
- """
- Class Poll(AutoSlug)
- Class represents single poll. These attributes are fetched from DB:
- meeting - meeting is ForeignKey referring to particular Meeting
- instance
- name - poll title
- pollId - an ID assigned to poll at psp.cz
- verdict - can be one of follows:
- 'přijato'
- 'zamítnuto'
- votesAye - number of votes Aye
- votesNay - number of votes Nay
- votesRefrain - number of refrains
- absences - number of absences
- excused - number of excused absences
- slug - slug referring to poll
- resultsLink - link to results at psp.cz
- stenoLink - link to stenographic record
- date - datetime.date instance with poll date
- """
- meeting = models.ForeignKey(Meeting)
- name = models.CharField(_("Poll Title"), max_length = 80)
- pollId = models.CharField(_("Poll Id"), max_length = 30, db_index = True)
- verdict = models.CharField(_("Verdict"), max_length = 20)
- votesAye = models.IntegerField( _("Votes For"),
- db_column = 'vote_aye'
- )
- votesNay = models.IntegerField( _("Votes Against"),
- db_column = 'vote_nay'
- )
- votesRefrain = models.IntegerField( _("Votes Refrained"),
- db_column = 'refrain'
- )
- absences = models.IntegerField( _("Absentees"),
- db_column = 'absentees'
- )
- excused = models.IntegerField(_("Excused"))
- slug = models.SlugField(db_index = True)
- resultsLink = models.URLField( _("Link to Poll Result"),
- verify_exists = False,
- blank = True
- )
- stenoLink = models.URLField( _("Link to steno record"),
- verify_exists = False,
- blank = True
- )
- date = models.DateField(_("Poll date"), blank = True)
- slugs = {
- 'slug' : ('name', )
- }
- objects = PollManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Poll")
- verbose_name_plural = _("Polls")
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- def resultPie(self):
- """
- Method resultPie()
- Method generates a pie chart representing results.
-
- Returns instance GChart.Pie3D instance.
- """
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mpVotes = MpVote.objects.filter(poll = self)
- votes = Votes(
- vAye = mpVotes.filter(result__iexact = 'A').count(),
- vNay = mpVotes.filter(result__iexact = 'N').count(),
- vRefrains = mpVotes.filter(result__iexact = 'Z').count(),
- absences = mpVotes.filter(result__iregex = '0|X|M').count(),
- sDate = self.date
- )
- retVal = votes.getVotesChart()
- retVal.size(370, 120)
-
- return retVal
- def bumpPoll(self, result):
- """
- Method bumpPoll(result)
- Bumps poll - result is code for result for particular MP.
- The update will bump votesAye, votesNay ... by result code:
- 'A' - adds one vote to votesAye
- 'N' - adds one vote to votesNay
- 'Z' - adds one vote to votesRefrain
- '0' - adds one vote to absences
- 'X'
- 'M' - adds one vote for excused
- Returns void
- """
- if result == 'A':
- self.votesAye += 1
- elif result == 'N':
- self.votesNay += 1
- elif result == 'Z':
- self.votesRefrain += 1
- elif result == '0' or result == 'X':
- self.absences += 1
- elif result == 'M':
- self.excused += 1
- return
- def getRebels(self, active = False):
- """
- Method getRebels(active = False)
- Method returns list persons. The list is ordered by accordance with
- MP's clubs for given poll. The person instances (MPs) are ordered from
- the least accordance. The argument active determines whether
- all results shoudl be counted or only those, which are result of
- active presence (results code 'A', 'N', 'Z').
-
- Returns the list of persons ordered by accordance with party club
- for given poll.
- """
- extraArg = ''
- if active:
- extraArg = """
- AND mpvote.result IN ('A', 'N', 'Z')
- """
- select = """
- SELECT mship.person_id
- FROM psp_mpvote AS mpvote,
- psp_group AS party
- JOIN psp_groupstats AS gs ON gs.group_id = party.id AND gs.poll_id = %d
- JOIN psp_membership AS mship ON mship.person_id = mpvote.person_id AND
- mship.group_id = party.id AND mship.post LIKE '_len' AND
- gs.group_id = mship.group_id AND gs.result != mpvote.result %s
- WHERE mpvote.poll_id = %d AND party.type = 'KLUB'
- GROUP BY mship.person_id;
- """
- #suppress warning Poll has no attribute id
- #pylint: disable-msg=E1101
- select = select % ( self.id,
- extraArg,
- self.id
- )
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
-
- retVal = []
- for row in rows:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mp = Person.objects.get(id = row[0])
- retVal.append(mp)
- return retVal
-
- class MpVoteManager(models.Manager):
- """
- Class MpVoteManager(models.Manager)
- MpVoteManager is default manager for MpVote class.
- """
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def getDayStats(self, dateStart, dateEnd = None):
- """
- Method getDayStats(dateStart, dateEnd = None)
- Retrieves stats for any arbitrary period. dateStart is mandatory
- argument, dateEnd is optional. When both arguments are specified
- function retrieves stats for range <dateStart, dateEnd>
- Returns VoteStats object. It's kind of surprise (one would expect it
- will be returned by by VoteStats manager). The think is the
- VoteStats aggregate records for whole term. Therefore I've decided
- to put this method here.
- """
- if dateEnd != None:
- select = """
- SELECT SUM( CASE
- WHEN mpvote.result = 'A' THEN 1
- ELSE 0
- END
- ) AS votes_aye,
- SUM( CASE
- WHEN mpvote.result = 'N' THEN 1
- ELSE 0
- END
- ) AS votes_nay,
- SUM( CASE
- WHEN mpvote.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS votes_refrains,
- SUM( CASE
- WHEN mpvote.result = '0' OR
- mpvote.result = 'X' THEN 1
- ELSE 0
- END
- ) AS absences,
- SUM( CASE
- WHEN mpvote.result = 'M' THEN 1
- ELSE 0
- END
- ) AS absences_excused
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS mpvote ON mpvote.poll_id = poll.id
- WHERE poll.date BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d'
- """ % ( dateStart.year, dateStart.month, dateStart.day,
- dateEnd.year, dateEnd.month, dateEnd.day
- )
- else:
- select = """
- SELECT SUM( CASE
- WHEN mpvote.result = 'A' THEN 1
- ELSE 0
- END
- ) AS votes_aye,
- SUM( CASE
- WHEN mpvote.result = 'N' THEN 1
- ELSE 0
- END
- ) AS votes_nay,
- SUM( CASE
- WHEN mpvote.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS votes_refrains,
- SUM( CASE
- WHEN mpvote.result = '0' OR
- mpvote.result = 'X' THEN 1
- ELSE 0
- END
- ) AS absences,
- SUM( CASE
- WHEN mpvote.result = 'M' THEN 1
- ELSE 0
- END
- ) AS absences_excused
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS mpvote ON mpvote.poll_id = poll.id
- WHERE poll.date = '%d-%02d-%02d';
- """ % (dateStart.year, dateStart.month, dateStart.day)
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- if len(rows) != 1:
- return None
- row = rows[0]
- retVal = VoteStats()
- retVal.votesAye = row[0]
- retVal.votesNay = row[1]
- retVal.votesRefrain = row[2]
- retVal.absences = row[3]
- retVal.excused = row[4]
- #suppress warning 'Attribute totalAbsences defined outside of init'
- #pylint: disable-msg=W0201
- retVal.totalAbsences = sum(row[3:])
- #suppress warning 'Attribute totalPolls defined outside of init'
- #pylint: disable-msg=W0201
- retVal.totalPolls = sum(row)
- retVal.dateStart = dateStart
- retVal.dateEnd = dateEnd
- return retVal
- class MpVote(AutoSlug):
- """
- Class MpVote(AutoSlug)
- MpVote stores a poll result for single MP. The attributes fetched
- from database are as follows:
- poll - ForeignKey referring to particular poll
- person - ForeignKey referring to MP, who polled
- result - single char, valid values are as follows:
- A votes aye
- N votes nay
- Z refrain
- M excused
- A,X absence
- """
- poll = models.ForeignKey(Poll, db_index = True)
- person = models.ForeignKey(Person, db_index = True)
- result = models.CharField(_("Result"), max_length = 20)
- objects = MpVoteManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Vote")
- verbose_name_plural = _("Votes")
- unique_together = (('poll', 'person',),)
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- #suppress warning 'Argument differs from overridden method'
- #pylint: disable-msg=W0221
- def save(self):
- """
- Method save()
- The saving a vote for particular person must update corresponding
- VoteStats record. If there is no such record exists yet, then it
- is created.
- """
-
- super(MpVote, self).save()
- mpStats = None
- try:
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mpStats = VoteStats.objects.get(
- person = self.person,
- term = self.poll.meeting.term
- )
- except ObjectDoesNotExist:
- print "creating stats for: %s %s" % (
- #suppress 'ForeignKey has no member name' warning
- #pylint: disable-msg=E1101
- self.person.name,
- #suppress 'ForeignKey has no member surname' warning
- #pylint: disable-msg=E1101
- self.person.surname
- )
- mpStats = VoteStats()
- mpStats.votesAye = 0
- mpStats.votesNay = 0
- mpStats.votesRefrain = 0
- mpStats.excused = 0
- mpStats.absences = 0
- #suppress 'ForeignKey has no member meeting
- #pylint: disable-msg=E1101
- mpStats.term = self.poll.meeting.term
- mpStats.person = self.person
-
- if self.result == 'A':
- mpStats.votesAye += 1
- elif self.result == 'N':
- mpStats.votesNay += 1
- elif self.result == 'Z':
- mpStats.votesRefrain += 1
- elif self.result == 'M':
- mpStats.excused += 1
- else:
- mpStats.absences += 1
- mpStats.save()
- return
- def delete(self):
- """
- Method delete()
- When vote is being deleted, then corresponding VoteStats record
- must be also updated.
- """
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- mpStats = VoteStats.objects.get( person = self.person,
- term = self.poll.meeting.term
- )
- super(MpVote, self).delete()
- if self.result == 'A':
- mpStats.votesAye -= 1
- elif self.result == 'N':
- mpStats.votesNay -= 1
- elif self.result == 'Z':
- mpStats.votesRefrain -= 1
- elif self.result == 'M':
- mpStats.excused -= 1
- else:
- mpStats.absences -= 1
- mpStats.save()
- return
- def getResult(self):
- """
- Method getResult()
- Returns poll result in human readable form.
- """
- if self.result == 'A':
- return _(u'Pro')
- elif self.result == 'N':
- return _(u'Proti')
- elif self.result == 'Z':
- return _(u'Zdržel')
- elif self.result == '0':
- return _(u'Chybí')
- else:
- return _(u'Omluven')
- @staticmethod
- def get_presence_pie(dateStart, dateEnd = None):
- """
- Static method get_presence_pie(dateStart, dateEnd)
- Renders a pie chart showing MP's presence for given <dateStart,
- dateEnd> range. If no dateEnd is specified, then pie chart for
- single day is rendered.
- Returns GChart.Pie3D instance.
- """
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- vs = MpVote.objects.getDayStats(dateStart, dateEnd)
- presences = vs.votesAye + vs.votesNay + vs.votesRefrain
- presences = get_percents(presences, vs.totalPolls)
- excused = get_percents(vs.excused, vs.totalPolls)
- absences = get_percents(vs.absences, vs.totalPolls)
- retVal = Pie3D([ presences, excused, absences ])
- retVal.label( _(u'Přítomno') + ' %.2f%%' % presences,
- _(u'Omluveno') + ' %.2f%%' % excused,
- _(u'Chybí') + ' %.2f%%' % absences,
- )
- retVal.color('00dd00', 'dd7700', 'dd0000')
- retVal.title(_(u'Nepřítomnost při hlasování'))
- retVal.size(330, 80)
- return retVal
- class VoteStatsManager(models.Manager):
- """
- Class VoteStatsManager(models.Manager)
- Class provides default manager for VoteStats class.
- """
- def getStatsForTerm(self, term = None):
- """
- Aggregates stats for all MPs in given term. If no term is passed
- returns aggregation for all terms. Function returns VoteStat object
- without any reference to particular person. Thus the returned VoteStat
- object can not be saved.
- """
- retVal = None
- cursor = None
- if term == None:
- select = """
- SELECT SUM(votes_aye),
- SUM(votes_nay),
- SUM(votes_refrains),
- SUM(absences),
- SUM(excused),
- SUM(absences + excused),
- SUM(votes_aye + votes_nay + votes_refrains)
- FROM psp_votestats;
- """
- else:
- termId = term_to_id(term)
- select = """
- SELECT SUM(votes_aye),
- SUM(votes_nay),
- SUM(votes_refrains),
- SUM(absences),
- SUM(excused),
- SUM(absences + excused),
- SUM(votes_aye + votes_nay + votes_refrains)
- FROM psp_votestats
- WHERE term_id = %d;
- """
- select = select % termId
- cursor = connection.cursor()
- cursor.execute(select)
- for row in cursor.fetchall()[:1]:
- retVal = self.model(
- votesAye = row[0],
- votesNay = row[1],
- votesRefrain = row[2],
- absences = row[3],
- excused = row[4]
- )
- retVal.totalAbsences = row[5]
- retVal.presences = row[6]
- retVal.term = term
-
- return retVal
- class VoteStats(models.Model):
- """
- Class VoteStats(models.Model)
- Class encapsulates a DB table with poll results aggregation for particular
- person and term. These attributes are being fetched from DB:
- person - ForeignKey - referrence to Person instance
- term - ForeignKey - referrence to TermOfOffice instance
- votesAye - votes aye (result == 'A')
- votesNay - votes nay (result == 'N')
- votesRefrain - refrains (result == 'Z')
- absences - result == 'X' or result == '0'
- excused - result == 'M'
- """
- #suppress 'too many instance attributes' warning
- #pylint: disable-msg=R0902
- person = models.ForeignKey(Person, db_index = True)
- term = models.ForeignKey(TermOfOffice)
- votesAye = models.IntegerField(_("Votes For"), db_column = 'votes_aye')
- votesNay = models.IntegerField(_("Votes Against"), db_column = 'votes_nay')
- votesRefrain = models.IntegerField( _("Votes Refraiend"),
- db_column = 'votes_refrains'
- )
- absences = models.IntegerField(_("Absences"))
- excused = models.IntegerField(_("Excused Absences"))
- dateStart = None
- dateEnd = None
- _votes = None
- objects = VoteStatsManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Aggregated stats for MP")
- verbose_name_plural = _("Aggregated stats for MPs")
- unique_together = (('person', 'term',),)
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- @property
- def votes(self):
- """
- Property votes
- returns a Votes instance for given stat.
- """
- if self._votes == None:
- self._votes = Votes(
- vAye = self.votesAye,
- vNay = self.votesNay,
- vRefrains = self.votesRefrain,
- absences = self.absences,
- excused = self.excused,
- sDate = self.dateStart,
- eDate = self.dateEnd
- )
- return self._votes
-
- class MpDayStatsManager(models.Manager):
- """
- Class MpDayStatsManager(models.Manager)
- Default manager for MpDayStats class.
- """
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def createStatsForDay(self, date):
- """
- Method createStatsForDay(date)
- Method computes a day stats for all MPs in given day.
- Returns void
- """
- select = """
- INSERT OR IGNORE INTO psp_mpdaystats (
- person_id,
- date,
- votes_aye,
- votes_nay,
- votes_refrain,
- absences,
- excused
- )
- SELECT
- id,
- '%d-%02d-%02d',
- aye,
- nay,
- refrains,
- abs,
- excs
- FROM (
- SELECT person.id AS id,
- person.mpId AS mpId,
- person.name AS name,
- person.surname AS surname,
- person.title AS title,
- person.titleLast AS titleLast,
- person.birthDate AS birthDate,
- person.email AS email,
- person.office AS office,
- person.regionOffice AS regionOffice,
- person.phone AS phone,
- person.slug AS slug,
- person.homePage AS homePage,
- person.nasiPoliticiUrl AS nasiPoliticiUrl,
- SUM(
- CASE
- WHEN vote.result = 'M' THEN 1
- ELSE 0
- END
- ) AS abs,
- SUM(
- CASE
- WHEN vote.result = '0' OR
- vote.result = 'X' THEN 1
- ELSE 0
- END
- ) AS excs,
- SUM(
- CASE
- WHEN vote.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM (
- CASE
- WHEN vote.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM (
- CASE
- WHEN vote.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye
- FROM psp_poll AS poll
- INNER JOIN psp_mpvote AS vote ON
- poll.id = vote.poll_id
- INNER JOIN psp_person AS person ON
- vote.person_id = person.id
- WHERE poll.date = '%d-%02d-%02d'
- GROUP BY person.id
- ) GROUP BY id;
- """
- select = select % ( date.year, date.month, date.day,
- date.year, date.month, date.day
- )
- cursor = connection.cursor()
- cursor.execute(select)
- return
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def getStatsForRange(self, mp, dateStart, dateEnd = None):
- """
- Method getStatsForRange(mp, dateStart, dateEnd = None)
- Method returns MpDayStats instance for given MP and date range (if both
- arguments dateStart, dateEnd are specified). The arguments are as
- follows:
- mp - Person ID or person instance,
- dateStart - datetime.date instance representing date instance
- dateEnd - datetime.date instance if specified then
- stats for <dateStart, dateEnd> range are
- retreived. if no dateEnd is specified then
- stats for single date are retrieved.
- Returns agregated stats for single MP and chosen date range.
- """
- mpId = None
- person = None
- if type(mp) == type(0):
- mpId = mp
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- person = Person.objects.get(id = mpId)
- else:
- mpId = mp.id
- person = mp
- if dateEnd == None:
- select = """
- SELECT SUM(ds.votes_aye),
- SUM(ds.votes_nay),
- SUM(ds.votes_refrain),
- SUM(ds.absences),
- SUM(ds.excused)
- FROM psp_mpdaystats AS ds
- WHERE ds.person_id = %d AND ds.date = '%d-%02d-%02d';
- """
- select = select % ( mpId,
- dateStart.year, dateStart.month, dateStart.day
- )
- else:
- select = """
- SELECT SUM(ds.votes_aye),
- SUM(ds.votes_nay),
- SUM(ds.votes_refrain),
- SUM(ds.absences),
- SUM(ds.excused)
- FROM psp_mpdaystats AS ds
- WHERE ds.person_id = %d AND
- ds.date BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d';
- """
- select = select % ( mpId,
- dateStart.year, dateStart.month, dateStart.day,
- dateEnd.year, dateEnd.month, dateEnd.day
- )
-
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- if len(rows) != 1:
- return None
-
- retVal = MpDayStats()
- row = rows[0]
- retVal.votesAye = row[0]
- retVal.votesNay = row[1]
- retVal.refrains = row[2]
- retVal.absences = row[3]
- retVal.excused = row[4]
- retVal.dateStart = dateStart
- retVal.dateEnd = dateEnd
- retVal.person = person
- return retVal
-
- class MpDayStats(models.Model):
- """
- Class MpDayStats(models.Model)
- MpDayStats provides statistic aggregation for day and MP (Person).
- These attributes are fetched from DB:
- person - is ForeignKey referres to Person
- date - datetime.date instance
- votesAye - votes aye
- votesNay - votes nay
- refrains - refrains
- absences - absences
- excused - excused absences
- """
- #suppress 'too many instance attributes' warning
- #pylint: disable-msg=R0902
- person = models.ForeignKey(Person, db_index = True)
- date = models.DateField(_("Date"))
- votesAye = models.IntegerField(_("Votes For"), db_column = 'votes_aye')
- votesNay = models.IntegerField(_("Votes For"), db_column = 'votes_nay')
- refrains = models.IntegerField(_("Refrains"), db_column = 'votes_refrain')
- absences = models.IntegerField(_("Absences"))
- excused = models.IntegerField(_("Excused Absences"))
- dateStart = None
- dateEnd = None
- _votes = None
- objects = MpDayStatsManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Aggregated stats for MP and day")
- verbose_name_plural = _("Aggregated stats for MPs and day")
- unique_together = (('person', 'date',),)
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- @property
- def votes(self):
- """
- Property votes returns instance of Votes class.
- """
- if self._votes == None:
- self._votes = Votes(
- vAye = self.votesAye,
- vNay = self.votesNay,
- vRefrains = self.refrains,
- absences = self.absences,
- excused = self.excused,
- sDate = self.dateStart,
- eDate = self.dateEnd
- )
- return self._votes
- class GroupStatsManager(models.Manager):
- """
- Class GroupStatsManager(models.Manager)
- GroupStatsManager provides default manager for GroupStats class.
- """
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def getStats(self, group, dateStart = None, dateEnd = None):
- """
- Method getStats(group, dateStart = None, dateEnd = None)
- Method returns stats for particular group for complete term (each group
- is bound to term by dafault). The arguments are as follows:
- group - group id or Group instance
- dateStart - if None, then stats for complete term are
- retrievved, otherwise just for particular
- day
- dateEnd - if specified then stats for <dateStart, dateEnd>
- range are retrieved.
- Returns a GroupStats instance.
- """
- groupId = group_to_id(group)
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- g = Group.objects.get(id = groupId)
- retVal = GroupStats()
- select = None
- if dateStart == None and dateEnd == None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye,
- SUM(
- CASE
- WHEN gs.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM(
- CASE
- WHEN gs.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM(
- CASE
- WHEN gs.result NOT IN ('A', 'N', 'Z') THEN 1
- ELSE 0
- END
- ) AS absences,
- SUM(1) AS total
- FROM psp_groupstats AS gs, psp_poll AS poll,
- psp_meeting AS meeting
- WHERE meeting.term_id = %d AND
- poll.meeting_id = meeting.id AND
- gs.group_id = %d AND gs.poll_id = poll.id;
- """
- select = select % (g.term.id, g.id)
- elif dateStart != None and dateEnd == None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye,
- SUM(
- CASE
- WHEN gs.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM(
- CASE
- WHEN gs.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM(
- CASE
- WHEN gs.result NOT IN ('A', 'N', 'Z') THEN 1
- ELSE 0
- END
- ) AS absences,
- SUM(1) AS total
- FROM psp_groupstats AS gs, psp_poll AS poll
- WHERE poll.date = '%d-%02d-%02d' AND
- gs.poll_id = poll.id AND gs.group_id = %d
- """
- select = select % ( dateStart.year, dateStart.month, dateStart.day,
- groupId
- )
- elif dateStart != None and dateEnd != None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye,
- SUM(
- CASE
- WHEN gs.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM(
- CASE
- WHEN gs.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM(
- CASE
- WHEN gs.result NOT IN ('A', 'N', 'Z') THEN 1
- ELSE 0
- END
- ) AS absences,
- SUM(1) AS total
- FROM psp_groupstats AS gs, psp_poll AS poll
- WHERE poll.date BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d'
- AND gs.poll_id = poll.id AND gs.group_id = %d
- """
- select = select % ( dateStart.year, dateStart.month, dateStart.day,
- dateEnd.year, dateEnd.month, dateEnd.day,
- g.id
- )
- else:
- return None
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- if len(rows) != 1:
- return None
-
- row = rows[0]
- retVal.votesAye = row[0]
- retVal.votesNay = row[1]
- retVal.votesRefrain = row[2]
- retVal.absences = row[3]
- #suppress warning 'Attribute totalVotes defined outside of init'
- #pylint: disable-msg=W0201
- retVal.totalVotes = row[4]
- retVal.dateStart = dateStart
- retVal.dateEnd = dateEnd
- return retVal
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def getAccordanceWithGroup(self, group, accordGroup, dateStart, dateEnd):
- """
- Method getAccordanceWithGroup(group, accordGroup, dateStart, dateEnd)
- Method computes group accordance with accordGroup. Returns an instance
- of Group (group), which is extended by these attributes:
- accordance - an instance of Accordance class
- accordGroup - the argument accordGroup
- The arguments are as follows:
- group - is ID of group or Group instance,
- accordGroup - is ID of group or Group instance,
- dateStart, dateEnd - define date range we want to gather
- stats for. If both are None, then stats
- for complete term are computed, if
- dateStart only is defined, then method
- will compute stats for particular single
- 'dateStart' day. Both arguments are
- datetime.date instances.
- Returns an instance of Group class, which is group itself.
- """
- select = ''
- groupId = group_to_id(group)
- accordGroupId = group_to_id(accordGroup)
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- retVal = Group.objects.get(id = groupId)
- if dateStart == None and dateEnd == None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result = accordGs.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(
- CASE
- WHEN gs.result != accordGs.result THEN 1
- ELSE 0
- END
- ) AS diff,
- SUM(1) AS total
- FROM psp_groupstats AS gs, psp_groupstats AS accordGs,
- psp_meeting AS m, psp_poll AS poll
- WHERE m.term_id = %d AND poll.meeting_id = m.id AND
- gs.group_id = %d AND accordGs.group_id = %d AND
- gs.poll_id = poll.id AND accordGs.poll_id = poll.id;
- """
- select = select % (retVal.term.id, groupId, accordGroupId)
- elif dateStart != None and dateEnd == None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result = accordGs.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(
- CASE
- WHEN gs.result != accordGs.result THEN 1
- ELSE 0
- END
- ) AS diff,
- SUM(1) AS total
- FROM psp_groupstats AS gs, psp_groupstats AS accordGs,
- psp_poll AS poll
- WHERE poll.date = '%d-%02d-%02d' AND
- gs.group_id = %d AND accordGs.group_id = %d AND
- gs.poll_id = poll.id AND accordGs.poll_id = poll.id;
- """
- select = select % ( dateStart.year, dateStart.month, dateStart.day,
- groupId, accordGroupId
- )
- elif dateStart != None and dateEnd != None:
- select = """
- SELECT SUM(
- CASE
- WHEN gs.result = accordGs.result THEN 1
- ELSE 0
- END
- ) AS same,
- SUM(
- CASE
- WHEN gs.result != accordGs.result THEN 1
- ELSE 0
- END
- ) AS diff,
- SUM(1) AS total
- FROM psp_groupstats AS gs, psp_groupstats AS accordGs,
- psp_poll AS poll
- WHERE poll.date BETWEEN '%d-%02d-%02d' AND '%d-%02d-%02d' AND
- gs.group_id = %d AND accordGs.group_id = %d AND
- gs.poll_id = poll.id AND accordGs.poll_id = poll.id;
- """
- select = select % ( dateStart.year, dateStart.month, dateStart.day,
- dateEnd.year, dateEnd.month, dateEnd.day,
- groupId, accordGroupId
- )
- else:
- return None
- cursor = connection.cursor()
- cursor.execute(select)
- rows = cursor.fetchall()
- if len(rows) != 1:
- return None
-
- row = rows[0]
- #suppress 'no objects member' warning
- #pylint: disable-msg=E1101
- retVal.accordanceGroup = Group.objects.get(id = accordGroupId)
- retVal.accordance = Accordance(
- same = row[0],
- diff = row[1],
- sDate = dateStart,
- eDate = dateEnd
- )
- return retVal
- #suppress 'method could be a function' refactor warning
- #pylint: disable-msg=R0201
- def createStats(self, poll):
- """
- Method createStats(poll)
- Method createStats(poll) computes GroupStats for given poll and all
- groups.
- Returns None
- """
- pollId = poll_to_id(poll)
- insert = """
- INSERT OR IGNORE INTO psp_groupStats (
- poll_id,
- group_id,
- aye,
- nay,
- refrains,
- absences,
- result
- )
- SELECT
- poll.id,
- membership.group_id,
- SUM(
- CASE
- WHEN vote.result = 'A' THEN 1
- ELSE 0
- END
- ) AS aye,
- SUM(
- CASE
- WHEN vote.result = 'N' THEN 1
- ELSE 0
- END
- ) AS nay,
- SUM(
- CASE
- WHEN vote.result = 'Z' THEN 1
- ELSE 0
- END
- ) AS refrains,
- SUM(
- CASE
- WHEN vote.result IN ('0', 'X', 'M') THEN 1
- ELSE 0
- END
- ) AS absences,
- ' ' as result
- FROM psp_poll AS poll
- INNER JOIN psp_mpVote AS vote ON poll.id = vote.poll_id
- INNER JOIN psp_membership AS membership ON
- membership.person_id = vote.person_id
- INNER JOIN psp_group AS groupa ON
- membership.group_id = groupa.id
- INNER JOIN psp_meeting AS meeting ON
- meeting.term_id = groupa.term_id AND
- poll.meeting_id = meeting.id
- WHERE (
- membership.post = 'člen' OR
- membership.post = 'poslanec'
- ) AND poll.id = %d
- GROUP BY poll.id, membership.group_id
- ;
- """
- insert = insert % pollId
- cursor = connection.cursor()
- cursor.execute(insert)
-
- return
- class GroupStats(models.Model):
- """
- Class GroupStats(models.Model)
- GroupStats aggregates poll results for group and poll.
- These attributes are fetched from database:
- poll - ForeignKey, which referres to poll
- group - ForeignKey, which referres to group
- votesAye - number of Ayes in group for given poll
- votesNay - number of Nays in group for given poll
- votesRefrain - number of refrains in group for poll
- absences - number of absences
- result - if poll was supported or denied by group
- """
- #suppress 'too many instance attributes' warning
- #pylint: disable-msg=R0902
- poll = models.ForeignKey(Poll, db_index = True)
- group = models.ForeignKey(Group, db_index = True)
- votesAye = models.IntegerField(_("Group Aye"), db_column = 'aye')
- votesNay = models.IntegerField(_("Group Nay"), db_column = 'nay')
- votesRefrain = models.IntegerField( _("Group Refrains"),
- db_column = 'refrains'
- )
- absences = models.IntegerField(_("Group Absences"))
- result = models.CharField(_("Result"), max_length = 20)
- dateStart = None
- dateEnd = None
- _votes = None
- _accordance = None
- objects = GroupStatsManager()
- class Meta:
- """
- See http://docs.djangoproject.com/en/dev/ref/models/options/
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- verbose_name = _("Group Statistic")
- verbose_name_plural = _("Group Statistics")
- unique_together = (('poll', 'group',),)
- class Admin:
- """
- See http://docs.djangoproject.com/en/dev/intro/tutorial02
- for details
- """
- #suppress class has no __init__ method
- #pylint: disable-msg=W0232
- #suppress too few public methods warning
- #pylint: disable-msg=R0903
- pass
- def getResult(self):
- """
- Method getResult()
- Method converts the stats to result code, if result code is still not
- defined (self.result == ' ' or self.result == '').
- The result codes are same as for MpVote.result
- A for
- N against
- Z refrain
- 0 absent (no difference is being made between excused and absent
- in case of GroupStats)
- Returns result code
- """
- if self.result == ' ' or self.result == '':
- #suppress redefining built-in max
- #pylint: disable-msg=W0622
- max = {}
- max['value'] = 0
- max['key'] = ''
- for k in ( 'votesAye',
- 'votesNay',
- 'votesRefrain',
- 'absences'
- ):
- if max['value'] < self.__getattribute__(k):
- max['value'] = self.__getattribute__(k)
- max['key'] = k
-
- if max['key'] == 'votesAye':
- self.result = 'A'
- elif max['key'] == 'votesNay':
- self.result = 'N'
- elif max['key'] == 'votesRefrain':
- self.result = 'Z'
- else:
- self.result = '0'
- self.save()
- if self.result == 'A':
- return _(u'Pro')
- elif self.result == 'N':
- return _(u'Proti')
- elif self.result == 'Z':
- return _(u'Zdrželi')
- else:
- return _(u'Chyběli')
- @property
- def votes(self):
- """
- Property votes returns Votes instance
- """
- if self._votes == None:
- self._votes = Votes(
- vAye = self.votesAye,
- vNay = self.votesNay,
- vRefrains = self.votesRefrain,
- absences = self.absences
- )
- return self._votes
- def getResultChart(self):
- """
- Method getResultChart()
-
- Method returns pie showing the result. Returns a pie chart for a group
- stat. Pie chart shows percent of votes
- for,
- against,
- reefrains,
- absences
- the default size is 400x80
- Returns GChart.Pie3D instance
- """
- retVal = None
-
- if self.votes.totalVotes != 0:
- retVal = self.votes.getVotesChart(group = True)
- retVal.size(400, 80)
- return retVal
- class SiteStateData(models.Model):
- """
- Class SiteStateData
-
- class is a container for various run-time data for site.
- These attributes are stored into DB:
- recentUpdate - datetime.date - the last update date from psp.cz
- recentMeeting - ForeignKey referring to last poll processed.
- """
- recentUpdate = models.DateField(_("Recent site update"), blank = True)
- recentMeeting = models.ForeignKey(Meeting)