Source code for election_day.models.election.election_result

from onegov.core.orm import Base
from onegov.core.orm.mixins import TimestampMixin
from onegov.core.orm.types import UUID
from onegov.election_day.models.election.mixins import DerivedAttributesMixin
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy import text
from sqlalchemy import Text
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship
from uuid import uuid4


from typing import TYPE_CHECKING
if TYPE_CHECKING:
    import uuid
    from onegov.election_day.models import CandidatePanachageResult
    from onegov.election_day.models import CandidateResult
    from onegov.election_day.models import Election
    from onegov.election_day.models import ListResult
    from sqlalchemy.sql import ColumnElement


[docs] class ElectionResult(Base, TimestampMixin, DerivedAttributesMixin): """ The election result in a single political entity. """
[docs] __tablename__ = 'election_results'
#: identifies the result
[docs] id: 'Column[uuid.UUID]' = Column( UUID, # type:ignore[arg-type] primary_key=True, default=uuid4 )
#: the election id this result belongs to
[docs] election_id: 'Column[str]' = Column( Text, ForeignKey('elections.id', onupdate='CASCADE', ondelete='CASCADE'), nullable=False )
#: the election this candidate belongs to
[docs] election: 'relationship[Election]' = relationship( 'Election', back_populates='results' )
#: entity id (e.g. a BFS number).
[docs] entity_id: 'Column[int]' = Column(Integer, nullable=False)
#: the name of the entity
[docs] name: 'Column[str]' = Column(Text, nullable=False)
#: the district this entity belongs to
[docs] district: 'Column[str | None]' = Column(Text, nullable=True)
#: the superregion this entity belongs to
[docs] superregion: 'Column[str | None]' = Column(Text, nullable=True)
#: True if the result has been counted and no changes will be made anymore. #: If the result is definite, all the values below must be specified.
[docs] counted: 'Column[bool]' = Column(Boolean, nullable=False)
#: number of eligible voters
[docs] eligible_voters: 'Column[int]' = Column( Integer, nullable=False, default=lambda: 0 )
#: number of expats
[docs] expats: 'Column[int | None]' = Column( Integer, nullable=True )
#: number of received ballots
[docs] received_ballots: 'Column[int]' = Column( Integer, nullable=False, default=lambda: 0 )
#: number of blank ballots
[docs] blank_ballots: 'Column[int]' = Column( Integer, nullable=False, default=lambda: 0 )
#: number of invalid ballots
[docs] invalid_ballots: 'Column[int]' = Column( Integer, nullable=False, default=lambda: 0 )
#: number of blank votes
[docs] blank_votes: 'Column[int]' = Column( Integer, nullable=False, default=lambda: 0 )
#: number of invalid votes
[docs] invalid_votes: 'Column[int]' = Column( Integer, nullable=False, default=lambda: 0 )
if TYPE_CHECKING:
[docs] accounted_votes: 'Column[int]'
@hybrid_property # type:ignore[no-redef] def accounted_votes(self) -> int: """ The number of accounted votes. """ return ( self.election.number_of_mandates * self.accounted_ballots - self.blank_votes - self.invalid_votes ) @accounted_votes.expression # type:ignore[no-redef] def accounted_votes(cls) -> 'ColumnElement[int]': """ The number of accounted votes. """ from onegov.election_day.models import Election # circular # A bit of a hack :| number_of_mandates = select( [Election.number_of_mandates], whereclause=text('elections.id = election_results.election_id') ) return ( number_of_mandates * ( cls.received_ballots - cls.blank_ballots - cls.invalid_ballots ) - cls.blank_votes - cls.invalid_votes ) #: an election result may contain n list results
[docs] list_results: 'relationship[list[ListResult]]' = relationship( 'ListResult', cascade='all, delete-orphan', back_populates='election_result' )
#: an election result contains n candidate results
[docs] candidate_results: 'relationship[list[CandidateResult]]' = relationship( 'CandidateResult', cascade='all, delete-orphan', back_populates='election_result' )
#: an election result contains n candidate panachage results
[docs] candidate_panachage_results: 'relationship[list[CandidatePanachageResult]]'
candidate_panachage_results = relationship( 'CandidatePanachageResult', cascade='all, delete-orphan', back_populates='election_result' )