def prettify_error_listings(form): errordict = form.errors #print "errordict ", errordict response = """<ul class='errors'>""" response += '\n'.join(["""<li>{}</li>""".format(e) for e in errordict.pop('__all__', [])]) for key, values in errordict.iteritems(): if key != "__all__": response += """<li class='fielderror'>""" response += """Guest {}'s {}:<ul>""".format( Utility.apnumber(int(key.split('_')[1])), key.split('_')[0] ) for error in values: response += """<li>{}</li>""".format(error) if key != "__all__": response += """</ul>""" response += """</li>""" response += """</ul>""" return mark_safe(response)
def prettify_error_listings(form): errordict = form.errors #print "errordict ", errordict response = """<ul class='errors'>""" response += '\n'.join( ["""<li>{}</li>""".format(e) for e in errordict.pop('__all__', [])]) for key, values in errordict.iteritems(): if key != "__all__": response += """<li class='fielderror'>""" response += """Guest {}'s {}:<ul>""".format( Utility.apnumber(int(key.split('_')[1])), key.split('_')[0]) for error in values: response += """<li>{}</li>""".format(error) if key != "__all__": response += """</ul>""" response += """</li>""" response += """</ul>""" return mark_safe(response)
class Enrollment(models.Model): """ Keeps track of which students are in which courses """ student = models.ForeignKey(Student) section = models.ForeignKey(Section) grade = models.CharField(max_length=2, choices=([(x, x) for x in Utility.create_grades()]), default='NR') description = models.TextField(null=True, blank=True) def __unicode__(self): return u'{} in {}'.format(self.student, self.section)
def is_not_set(self): return Utility.conjunct(self.timeslots.all())
class Ballot(models.Model): """For example, a ballot for ASHMC President would have candidates (actually PersonCandidates). Multiple ballots can appear in a measure; that is, you can have a ballot for ASHMC President election and one for VP election in the same measure. """ VOTE_TYPES = Utility.enum('POPULARITY', 'PREFERENCE', 'SELECT_X', 'INOROUT', type_name='BallotVoteType') TYPES = ( (VOTE_TYPES.POPULARITY, "Popularity"), (VOTE_TYPES.PREFERENCE, 'Preference'), (VOTE_TYPES.SELECT_X, 'Select Top X'), (VOTE_TYPES.INOROUT, 'Yes or No'), ) vote_type = models.SmallIntegerField(default=0, choices=TYPES) number_to_select = models.PositiveIntegerField(blank=True, null=True) measure = models.ForeignKey('Measure', null=True) display_position = models.IntegerField(default=1) title = models.CharField(max_length=50) blurb = models.TextField() can_write_in = models.BooleanField(default=False) can_abstain = models.BooleanField(default=True) is_secret = models.BooleanField(default=False) is_irv = models.BooleanField( default=False, help_text= 'Only applies to Preferential type; changes the way winners are calculated.', ) def get_winners(self): """does not break ties.""" if self.candidate_set.count() == 0: return [] if self.vote_type == self.VOTE_TYPES.POPULARITY or self.vote_type == self.VOTE_TYPES.INOROUT: max_choices = max( self.candidate_set.annotate( pv_max=models.Count('popularityvote')).values_list( 'pv_max', flat=True)) return self.candidate_set.annotate( models.Count('popularityvote')).filter( popularityvote__count=max_choices) elif self.vote_type == self.VOTE_TYPES.PREFERENCE: if not self.is_irv: # The lower the sum of the ranks of a candidate, the better they're doing overall. min_choices = min( self.candidate_set.annotate(pf_sum=models.Sum( 'preferentialvote__amount')).values_list('pf_sum', flat=True)) return self.candidate_set.annotate( models.Sum('preferentialvote__amount')).filter( preferentialvote__amount=min_choices) # IRV voting is a little more intense. # we do rounds - until one candidate has a majority, we eliminate the # least popular candidate and apply the voters' other votes to their # next favorite choice. # http://en.wikipedia.org/wiki/Instant-runoff_voting # Since each candidate gets a vote with a different ballot, # we normalize the number of votes by the number of voters -- # each voter should have contributed the same number of votes per # ballot (e.g., the number of candidates on the ballot) # If no more votes can come in, then don't calculate again. # Don't do anything while votes can still come in. if not self.measure.voting_closed: return Candidate.objects.none() # Don't re-calculate if it's been calculated. if InstantRerunVotingRound.objects.filter( ballot=self).count() != 0: irvr = InstantRerunVotingRound.objects.filter( ballot=self).order_by('-number')[0] try: max_votes = max( IRVCandidate.objects.filter(irv_round=irvr, ).annotate( models.Count('votes')).values_list( 'votes__count', flat=True, )) return irvr.irvcandidate_set.annotate( models.Count('votes')).filter(votes__count=max_votes) except ValueError: return IRVCandidate.objects.none() logger.debug("Calcluating IRV for BALLOT %s", self) total_votes = self.measure.vote_set.count() candidates = list(self.candidate_set.all()) logger.debug("total votes: %s", total_votes) the_round = InstantRerunVotingRound.objects.create( number=1, ballot=self, ) for candidate in candidates: logger.debug("Creating initial IRVCandidate for %s", candidate) irvc = IRVCandidate.objects.create( candidate=candidate, irv_round=the_round, # Get the FIRST-CHOICE votes for every candidate. ) irvc.votes.add(*list( self.preferentialvote_set.filter( candidate=candidate, amount=1, ))) # Do rounds until *someone* has a majority. logger.debug("calculating starting max votes") try: max_votes = max( IRVCandidate.objects.filter( irv_round=the_round, ).annotate( models.Count('votes')).values_list( 'votes__count', flat=True, )) logger.debug("max_votes: %s", max_votes) except ValueError: Candidate.objects.none() while max_votes <= total_votes / 2: logger.debug("%s out of %s", max_votes, total_votes) old_candidates = IRVCandidate.objects.filter( irv_round=the_round).annotate( pv_count=models.Count('votes')).order_by('pv_count') logger.debug("old candidates: %s", old_candidates) the_round = InstantRerunVotingRound.objects.create( ballot=self, number=the_round.number + 1, ) logger.debug("creating new round: %s", the_round.number) # TODO: break ties LOLOLOL loser = old_candidates[0] logger.debug("found loser: %s", loser) # Move all the surviving votes over, and delete the # loser from the running. for irvcandidate in old_candidates[1:]: irvc = IRVCandidate.objects.create( irv_round=the_round, candidate=irvcandidate.candidate, ) irvc.votes.add(*list(irvcandidate.votes.all())) # Attach losers votes to their next preference for pvote in loser.votes.all(): logger.debug("attaching loser's votes to other candidates") v = pvote.vote try: next_pvote = v.preferentialvote_set.get( amount=pvote.amount + 1, ) except PreferentialVote.ObjectDoesNotExist: logger.info( "losing a preference due to lack of ranking") # If there are no more preferences, that's fine. # their vote no longer contributes to the total, # and they don't get a candidate assigned to them. total_votes -= 1 continue next_irc = IRVCandidate.objects.get( irv_round=the_round, candidate=next_pvote.candidate, ) next_irc.votes.add(next_pvote) max_votes = max( IRVCandidate.objects.filter( irv_round=the_round, ).annotate( models.Count('votes')).values_list('votes__count', flat=True)) # The rounds are over! Time to find the max votes and return the list # of winners. return IRVCandidate.objects.annotate(models.Count('votes')).filter( votes__count=max_votes, irv_round=the_round) elif self.vote_type == self.VOTE_TYPES.SELECT_X: max_choices = self.candidate_set.annotate(pv_max=models.Count( 'popularityvote')).order_by('-pv_max').values_list( 'pv_max', flat=True)[0] return self.candidate_set.annotate( models.Count('popularityvote')).filter( popularityvote__count=max_choices) def ordered_candidates(self): if self.vote_type == self.VOTE_TYPES.POPULARITY or self.vote_type == self.VOTE_TYPES.INOROUT: return self.candidate_set.annotate( votes=models.Count('popularityvote')).order_by('-votes') elif self.vote_type == self.VOTE_TYPES.PREFERENCE: return self.candidate_set.annotate( votes=models.Sum('preferentialvote__amount')).order_by('votes') elif self.vote_type == self.VOTE_TYPES.SELECT_X: return self.candidate_set.annotate( votes=models.Count('popularityvote')).order_by('-votes') def __unicode__(self): return u"Ballot #{}: {}".format(self.id, self.title) class Meta: unique_together = (('measure', 'title'), ) def save(self, *args, **kwargs): if self.vote_type == self.VOTE_TYPES.SELECT_X and self.number_to_select is None: raise IntegrityError( "Can't have a SELECT_X vote type and no number_to_select.") super(Ballot, self).save(*args, **kwargs) if self.vote_type == self.VOTE_TYPES.INOROUT: # create the two candidates now. yes, _ = Candidate.objects.get_or_create( title="Yes", ballot=self, ) no, _ = Candidate.objects.get_or_create( title="No", ballot=self, )
class Ballot(models.Model): """For example, a ballot for ASHMC President would have candidates (actually PersonCandidates). Multiple ballots can appear in a measure; that is, you can have a ballot for ASHMC President election and one for VP election in the same measure. """ VOTE_TYPES = Utility.enum('POPULARITY', 'PREFERENCE', 'SELECT_X', 'INOROUT', type_name='BallotVoteType') TYPES = ( (VOTE_TYPES.POPULARITY, "Popularity"), (VOTE_TYPES.PREFERENCE, 'Preference'), (VOTE_TYPES.SELECT_X, 'Select Top X'), (VOTE_TYPES.INOROUT, 'Yes or No'), ) vote_type = models.SmallIntegerField(default=0, choices=TYPES) number_to_select = models.PositiveIntegerField(blank=True, null=True) measure = models.ForeignKey('Measure', null=True) display_position = models.IntegerField(default=1) title = models.CharField(max_length=50) blurb = models.TextField() can_write_in = models.BooleanField(default=False) can_abstain = models.BooleanField(default=True) is_secret = models.BooleanField(default=False) def get_winners(self): """does not break ties.""" if self.vote_type == self.VOTE_TYPES.POPULARITY or self.vote_type == self.VOTE_TYPES.INOROUT: max_choices = max( self.candidate_set.annotate( pv_max=models.Count('popularityvote')).values_list( 'pv_max', flat=True)) return self.candidate_set.annotate( models.Count('popularityvote')).filter( popularityvote__count=max_choices) elif self.vote_type == self.VOTE_TYPES.PREFERENCE: # The lower the sum of the ranks of a candidate, the better they're doing overall. min_choices = min( self.candidate_set.annotate( pf_sum=models.Sum('preferentialvote__amount')).values_list( 'pf_sum', flat=True)) return self.candidate_set.annotate( models.Sum('preferentialvote__amount')).filter( preferentialvote__amount=min_choices) elif self.vote_type == self.VOTE_TYPES.SELECT_X: max_choices = self.candidate_set.annotate(pv_max=models.Count( 'popularityvote')).order_by('-pv_max').values_list( 'pv_max', flat=True)[0] return self.candidate_set.annotate( models.Count('popularityvote')).filter( popularityvote__count=max_choices) def ordered_candidates(self): if self.vote_type == self.VOTE_TYPES.POPULARITY or self.vote_type == self.VOTE_TYPES.INOROUT: return self.candidate_set.annotate( votes=models.Count('popularityvote')).order_by('-votes') elif self.vote_type == self.VOTE_TYPES.PREFERENCE: return self.candidate_set.annotate( votes=models.Sum('preferentialvote__amount')).order_by('votes') elif self.vote_type == self.VOTE_TYPES.SELECT_X: return self.candidate_set.annotate( votes=models.Count('popularityvote')).order_by('-votes') def __unicode__(self): return u"Ballot #{}: {}".format(self.id, self.title) class Meta: unique_together = (('measure', 'title'), ) def save(self, *args, **kwargs): if self.vote_type == self.VOTE_TYPES.SELECT_X and self.number_to_select is None: raise IntegrityError( "Can't have a SELECT_X vote type and no number_to_select.") super(Ballot, self).save(*args, **kwargs) if self.vote_type == self.VOTE_TYPES.INOROUT: # create the two candidates now. yes, _ = Candidate.objects.get_or_create( title="Yes", ballot=self, ) no, _ = Candidate.objects.get_or_create( title="No", ballot=self, )