def get_attention_needed_posts(max_results=None, random=False): from candidates.election_specific import shorten_post_label cursor = connection.cursor() # This is similar to the query in ConstituencyCountsView, # except it's not specific to a particular election and the # results are ordered with fewest candidates first: query = ''' SELECT pe.slug, p.label, ee.name, ee.slug, count(m.id) as count FROM popolo_post p INNER JOIN candidates_postextra pe ON pe.base_id = p.id INNER JOIN candidates_postextra_elections cppee ON cppee.postextra_id = pe.id INNER JOIN elections_election ee ON cppee.election_id = ee.id LEFT OUTER JOIN (popolo_membership m INNER JOIN candidates_membershipextra me ON me.base_id = m.id) ON m.role = ee.candidate_membership_role AND m.post_id = p.id AND me.election_id = ee.id GROUP BY pe.slug, p.label, ee.slug, ee.name ORDER BY''' if random: query += ' count, random()' else: query += ' count, ee.name, p.label' if max_results is not None: query += ' LIMIT {limit}'.format(limit=max_results) cursor.execute(query) return [{ 'post_slug': row[0], 'post_label': row[1], 'election_name': row[2], 'election_slug': row[3], 'count': row[4], 'post_short_label': shorten_post_label(row[1]), } for row in cursor.fetchall()]
def get_context_data(self, **kwargs): from candidates.election_specific import shorten_post_label context = super(ConstituencyCountsView, self).get_context_data(**kwargs) cursor = connection.cursor() cursor.execute(''' SELECT pe.slug, p.label, count(m.id) as count FROM popolo_post p INNER JOIN candidates_postextra pe ON pe.base_id = p.id INNER JOIN candidates_postextraelection cppee ON cppee.postextra_id = pe.id INNER JOIN elections_election ee ON cppee.election_id = ee.id AND ee.id = %s LEFT OUTER JOIN (popolo_membership m INNER JOIN candidates_membershipextra me ON me.base_id = m.id) ON m.role = ee.candidate_membership_role AND m.post_id = p.id AND me.election_id = ee.id GROUP BY pe.slug, p.label ORDER BY count DESC; ''', [self.election_data.id]) context['post_counts'] = [ { 'post_slug': row[0], 'post_label': row[1], 'count': row[2], 'post_short_label': shorten_post_label(row[1]), } for row in cursor.fetchall() ] return context
def get_person_as_version_data(person): from candidates.election_specific import shorten_post_label result = {} person_extra = person.extra result['id'] = str(person.id) for field, null_value in form_simple_fields.items(): result[field] = getattr(person, field) or null_value for field in form_complex_fields_locations: result[field] = getattr(person_extra, field) result['other_names'] = [ { 'name': on.name, 'note': on.note, 'start_date': on.start_date, 'end_date': on.end_date, } for on in person.other_names.all() ] identifiers = list(person.identifiers.all()) if identifiers: result['identifiers'] = [ { 'scheme': i.scheme, 'identifier': i.identifier, } for i in identifiers ] result['image'] = person.image standing_in = {} party_memberships = {} for membership in person.memberships.filter(post__isnull=False): from candidates.models import MembershipExtra post = membership.post try: membership_extra = membership.extra except MembershipExtra.DoesNotExist: continue election = membership_extra.election standing_in[election.slug] = { 'post_id': post.extra.slug, 'name': shorten_post_label(post.label) } if membership_extra.elected is not None: standing_in[election.slug]['elected'] = membership_extra.elected if membership_extra.party_list_position is not None: standing_in[election.slug]['party_list_position'] = \ membership_extra.party_list_position party = membership.on_behalf_of party_memberships[election.slug] = { 'id': party.extra.slug, 'name': party.name, } for not_standing_in_election in person_extra.not_standing.all(): standing_in[not_standing_in_election.slug] = None result['standing_in'] = standing_in result['party_memberships'] = party_memberships return result
def add_election_fields(self, election_data): from candidates.election_specific import shorten_post_label election = election_data.slug self.fields["standing_" + election] = forms.ChoiceField( label=_("Standing in %s") % election_data.name, choices=BasePersonForm.STANDING_CHOICES, widget=forms.Select(attrs={"class": "standing-select"}), ) self.fields["constituency_" + election] = forms.ChoiceField( label=_("Constituency in %s") % election_data.name, required=False, choices=[("", "")] + sorted( [ (post.slug, shorten_post_label(post.label)) for post in Post.objects.filter(elections__slug=election) ], key=lambda t: t[1], ), widget=forms.Select(attrs={"class": "post-select"}), ) for party_set, party_choices in self.party_sets_and_party_choices: self.fields[ "party_" + party_set.slug.upper() + "_" + election ] = forms.ChoiceField( label=_("Party in {election} ({party_set_name})").format( election=election_data.name, party_set_name=party_set.name ), choices=party_choices, required=False, widget=forms.Select( attrs={"class": "party-select party-select-" + election} ), ) if election_data.party_lists_in_use: # Then add a field to enter the position on the party list # as an integer: field_name = ( "party_list_position_" + party_set.slug.upper() + "_" + election ) self.fields[field_name] = forms.IntegerField( label=_( "Position in party list ('1' for first, '2' for second, etc.)" ), min_value=1, required=False, widget=forms.NumberInput( attrs={ "class": "party-position party-position-" + election } ), )
def get_person_as_version_data(person): from candidates.election_specific import shorten_post_label result = {} person_extra = person.extra result['id'] = str(person.id) for field, null_value in form_simple_fields.items(): result[field] = getattr(person, field) or null_value for field in form_complex_fields_locations: result[field] = getattr(person_extra, field) result['other_names'] = [{ 'name': on.name, 'note': on.note, 'start_date': on.start_date, 'end_date': on.end_date, } for on in person.other_names.all()] identifiers = list(person.identifiers.all()) if identifiers: result['identifiers'] = [{ 'scheme': i.scheme, 'identifier': i.identifier, } for i in identifiers] result['image'] = person.image standing_in = {} party_memberships = {} for membership in person.memberships.filter(post__isnull=False): from candidates.models import MembershipExtra post = membership.post try: membership_extra = membership.extra except MembershipExtra.DoesNotExist: continue election = membership_extra.election standing_in[election.slug] = { 'post_id': post.extra.slug, 'name': shorten_post_label(post.label) } if membership_extra.elected is not None: standing_in[election.slug]['elected'] = membership_extra.elected if membership_extra.party_list_position is not None: standing_in[election.slug]['party_list_position'] = \ membership_extra.party_list_position party = membership.on_behalf_of party_memberships[election.slug] = { 'id': party.extra.slug, 'name': party.name, } for not_standing_in_election in person_extra.not_standing.all(): standing_in[not_standing_in_election.slug] = None result['standing_in'] = standing_in result['party_memberships'] = party_memberships return result
def get_attention_needed_posts(max_results=None, random=False): from candidates.election_specific import shorten_post_label cursor = connection.cursor() # This is similar to the query in ConstituencyCountsView, # except it's not specific to a particular election and the # results are ordered with fewest candidates first: query = ''' SELECT pe.slug, p.label, ee.name, ee.slug, count(m.id) as count FROM popolo_post p INNER JOIN candidates_postextra pe ON pe.base_id = p.id INNER JOIN candidates_postextraelection cppee ON cppee.postextra_id = pe.id INNER JOIN elections_election ee ON cppee.election_id = ee.id LEFT OUTER JOIN (popolo_membership m INNER JOIN candidates_membershipextra me ON me.base_id = m.id) ON m.role = ee.candidate_membership_role AND m.post_id = p.id AND me.election_id = ee.id WHERE ee.current = TRUE GROUP BY pe.slug, p.label, ee.slug, ee.name ORDER BY''' if random: query += ' count, random()' else: query += ' count, ee.name, p.label' if max_results is not None: query += ' LIMIT {limit}'.format(limit=max_results) cursor.execute(query) return [ { 'post_slug': row[0], 'post_label': row[1], 'election_name': row[2], 'election_slug': row[3], 'count': row[4], 'post_short_label': shorten_post_label(row[1]), } for row in cursor.fetchall() ]
def get_context_data(self, **kwargs): from candidates.election_specific import shorten_post_label context = super().get_context_data(**kwargs) context["post_election"] = get_object_or_404( PostExtraElection.objects.all().select_related("post", "election"), ballot_paper_id=context["election"], ) mp_post = context["post_election"].post context["election"] = election = context["post_election"].election context["post_id"] = post_id = mp_post.slug context["post_obj"] = mp_post documents_by_type = {} # Make sure that every available document type has a key in # the dictionary, even if there are no such documents. doc_lookup = { t[0]: (t[1], t[2]) for t in OfficialDocument.DOCUMENT_TYPES } for t in doc_lookup.values(): documents_by_type[t] = [] documents_for_post = OfficialDocument.objects.filter( post_election=context["post_election"]) for od in documents_for_post: documents_by_type[doc_lookup[od.document_type]].append(od) context["official_documents"] = documents_by_type.items() context["some_official_documents"] = documents_for_post.count() context["post_label"] = mp_post.label context["post_label_shorter"] = shorten_post_label( context["post_label"]) context["redirect_after_login"] = context[ "post_election"].get_absolute_url() context["post_data"] = {"id": mp_post.slug, "label": mp_post.label} pee = context["post_election"] context["candidates_locked"] = pee.candidates_locked context["has_lock_suggestion"] = SuggestedPostLock.objects.filter( postextraelection=pee).exists() if self.request.user.is_authenticated: context[ "current_user_suggested_lock"] = SuggestedPostLock.objects.filter( user=self.request.user, postextraelection=pee).exists() context["suggest_lock_form"] = SuggestedPostLockForm( initial={"postextraelection": pee}) if self.request.user.is_authenticated: context[ "user_has_suggested_lock"] = SuggestedPostLock.objects.filter( user=self.request.user, postextraelection=pee).exists() context["lock_form"] = ToggleLockForm( initial={ "post_id": post_id, "lock": not context["candidates_locked"], }) context["candidate_list_edits_allowed"] = get_edits_allowed( self.request.user, context["candidates_locked"]) extra_qs = Membership.objects.select_related("post_election__election") current_candidacies, past_candidacies = split_candidacies( election, mp_post.memberships.select_related("person", "party").all(), ) area_2015_map = { "WMC:E14000824": "65693", "WMC:E14000825": "65633", "WMC:E14000826": "65735", "WMC:E14000827": "65556", "WMC:E14000820": "65657", "WMC:E14000821": "65953", "WMC:E14000822": "66076", "WMC:E14000823": "66038", "WMC:E14000828": "65815", "WMC:E14000829": "65696", "WMC:E14000948": "65829", "WMC:E14000543": "66006", "WMC:E14000810": "65647", "WMC:E14000813": "65718", "WMC:E14000540": "65662", "WMC:E14000699": "65857", "WMC:E14000751": "66069", "WMC:E14000546": "65711", "WMC:S14000048": "14445", "WMC:S14000049": "14446", "WMC:E14000912": "65889", "WMC:E14000913": "65891", "WMC:E14000914": "66027", "WMC:E14000915": "65763", "WMC:E14000916": "65706", "WMC:E14000917": "65842", "WMC:S14000040": "14436", "WMC:S14000041": "14437", "WMC:S14000042": "14438", "WMC:S14000043": "14439", "WMC:S14000044": "14440", "WMC:S14000045": "14441", "WMC:S14000046": "14442", "WMC:S14000047": "14443", "WMC:E14000727": "65576", "WMC:E14000726": "65836", "WMC:E14000725": "65915", "WMC:E14000724": "65671", "WMC:E14000723": "65599", "WMC:E14000649": "65636", "WMC:E14000721": "65752", "WMC:E14000720": "65550", "WMC:E14000644": "65926", "WMC:E14000645": "65835", "WMC:E14000646": "65771", "WMC:E14000690": "65816", "WMC:E14000640": "65734", "WMC:W07000063": "66111", "WMC:E14000642": "66030", "WMC:E14000643": "66057", "WMC:E14001034": "65629", "WMC:E14001035": "65758", "WMC:E14001036": "65851", "WMC:E14001037": "65963", "WMC:E14001030": "66047", "WMC:E14001031": "65716", "WMC:E14001032": "66058", "WMC:E14001033": "65873", "WMC:E14000544": "65898", "WMC:E14001038": "65742", "WMC:E14001039": "65612", "WMC:E14000965": "66067", "WMC:E14000964": "65854", "WMC:E14000967": "65960", "WMC:E14000966": "65907", "WMC:S14000039": "14435", "WMC:S14000038": "14434", "WMC:E14000963": "65732", "WMC:E14000962": "66073", "WMC:S14000035": "14431", "WMC:S14000034": "14430", "WMC:S14000037": "14433", "WMC:S14000036": "14432", "WMC:E14000969": "65606", "WMC:E14000968": "65571", "WMC:S14000033": "14429", "WMC:S14000032": "14428", "WMC:E14000639": "65759", "WMC:E14000731": "65650", "WMC:W07000072": "66093", "WMC:E14000868": "65663", "WMC:E14000869": "65653", "WMC:W07000077": "66097", "WMC:W07000049": "66101", "WMC:E14000860": "65822", "WMC:E14000861": "66059", "WMC:E14000862": "65910", "WMC:E14000863": "65768", "WMC:E14000864": "65634", "WMC:E14000865": "65559", "WMC:E14000866": "65643", "WMC:E14000867": "65945", "WMC:W07000062": "66121", "WMC:E14000631": "65801", "WMC:N06000006": "66129", "WMC:N06000007": "66130", "WMC:W07000066": "66109", "WMC:N06000001": "66124", "WMC:N06000002": "66125", "WMC:N06000003": "66126", "WMC:W07000068": "66088", "WMC:W07000069": "66082", "WMC:N06000008": "66131", "WMC:N06000009": "66132", "WMC:E14000819": "65998", "WMC:E14000818": "65888", "WMC:E14000549": "65731", "WMC:E14000548": "65751", "WMC:E14000547": "65798", "WMC:E14000814": "66007", "WMC:E14000545": "65623", "WMC:E14000816": "65949", "WMC:E14000811": "65772", "WMC:E14000542": "66012", "WMC:E14000541": "65665", "WMC:E14000812": "65932", "WMC:E14000600": "66009", "WMC:E14000601": "66031", "WMC:E14000602": "65574", "WMC:E14000603": "65852", "WMC:E14000604": "65954", "WMC:E14000605": "65617", "WMC:E14000606": "65639", "WMC:E14000607": "65849", "WMC:E14000608": "65909", "WMC:E14000609": "65846", "WMC:E14000929": "65920", "WMC:E14000928": "65986", "WMC:E14000921": "65601", "WMC:E14000920": "65793", "WMC:E14000923": "65549", "WMC:E14000654": "65603", "WMC:E14000925": "65959", "WMC:E14000924": "65632", "WMC:E14000927": "65610", "WMC:E14000926": "65563", "WMC:E14000778": "65941", "WMC:E14000779": "65866", "WMC:E14000774": "66053", "WMC:E14000775": "65869", "WMC:E14000776": "65568", "WMC:E14000777": "65765", "WMC:E14000770": "65778", "WMC:E14000771": "65709", "WMC:E14000772": "65618", "WMC:E14000773": "65984", "WMC:E14000675": "65701", "WMC:E14000674": "65755", "WMC:E14000677": "65823", "WMC:E14000676": "65794", "WMC:E14000671": "65806", "WMC:E14000670": "65555", "WMC:E14000673": "65808", "WMC:E14000672": "66054", "WMC:E14000679": "65573", "WMC:E14000678": "65813", "WMC:E14001009": "65733", "WMC:E14001008": "65825", "WMC:E14001005": "65782", "WMC:E14001004": "65660", "WMC:E14001007": "65613", "WMC:E14001006": "65868", "WMC:E14001001": "65810", "WMC:E14001000": "65904", "WMC:E14001003": "65659", "WMC:E14001002": "66074", "WMC:E14000733": "65990", "WMC:E14000781": "65988", "WMC:E14000780": "66068", "WMC:E14000783": "65604", "WMC:E14000782": "65807", "WMC:E14000785": "65978", "WMC:E14000784": "65587", "WMC:E14000787": "65705", "WMC:E14000786": "66020", "WMC:E14000789": "66041", "WMC:E14000788": "65616", "WMC:E14000851": "65760", "WMC:E14000850": "65817", "WMC:E14000581": "65821", "WMC:E14000580": "65738", "WMC:E14000587": "65694", "WMC:E14000586": "65697", "WMC:E14000585": "65933", "WMC:E14000856": "65859", "WMC:E14000859": "65713", "WMC:E14000858": "65776", "WMC:E14000589": "66036", "WMC:E14000588": "65995", "WMC:S14000028": "14424", "WMC:S14000029": "14425", "WMC:S14000020": "14417", "WMC:S14000021": "14418", "WMC:E14000922": "65741", "WMC:E14000739": "65967", "WMC:E14000730": "65578", "WMC:E14000638": "65885", "WMC:E14000732": "65796", "WMC:E14000746": "65850", "WMC:E14000734": "65674", "WMC:E14000735": "65640", "WMC:E14000736": "65699", "WMC:E14000737": "65912", "WMC:E14000738": "65557", "WMC:E14000630": "65946", "WMC:E14000633": "65558", "WMC:E14000632": "65980", "WMC:E14000635": "65940", "WMC:E14000634": "65721", "WMC:E14000637": "65792", "WMC:E14000636": "65886", "WMC:E14001041": "65921", "WMC:E14001040": "65827", "WMC:E14001043": "65847", "WMC:E14001042": "65552", "WMC:E14001045": "65831", "WMC:E14001044": "65897", "WMC:E14001047": "66039", "WMC:E14001046": "65622", "WMC:E14001049": "65777", "WMC:E14001048": "65774", "WMC:E14000910": "65654", "WMC:E14000911": "65688", "WMC:E14000976": "65609", "WMC:E14000977": "65648", "WMC:E14000974": "65770", "WMC:E14000975": "65950", "WMC:E14000972": "65710", "WMC:E14000973": "65783", "WMC:E14000970": "65641", "WMC:E14000971": "65908", "WMC:S14000026": "14423", "WMC:S14000027": "14444", "WMC:S14000024": "14421", "WMC:S14000025": "14422", "WMC:S14000022": "14419", "WMC:S14000023": "14420", "WMC:E14000978": "66042", "WMC:E14000979": "65911", "WMC:E14000745": "65994", "WMC:E14000744": "66003", "WMC:E14000747": "65814", "WMC:E14000830": "65862", "WMC:E14000741": "65754", "WMC:E14000740": "66018", "WMC:E14000743": "65582", "WMC:E14000742": "65786", "WMC:E14000749": "65724", "WMC:E14000748": "66052", "WMC:E14000918": "65698", "WMC:E14000919": "65957", "WMC:E14000895": "65722", "WMC:E14000894": "65579", "WMC:E14000897": "65843", "WMC:E14000896": "65598", "WMC:E14000891": "66032", "WMC:E14000890": "65982", "WMC:E14000893": "66005", "WMC:E14000892": "65700", "WMC:W07000057": "66108", "WMC:W07000056": "66099", "WMC:W07000055": "66094", "WMC:W07000054": "66084", "WMC:E14000899": "65584", "WMC:E14000898": "66043", "WMC:W07000051": "66120", "WMC:W07000050": "66090", "WMC:E14000648": "65590", "WMC:E14000722": "65971", "WMC:E14000558": "65611", "WMC:E14000559": "65581", "WMC:E14000808": "65834", "WMC:E14000809": "65819", "WMC:E14000806": "65661", "WMC:E14000807": "66048", "WMC:E14000804": "65936", "WMC:E14000553": "65689", "WMC:E14000554": "65726", "WMC:E14000803": "65901", "WMC:E14000556": "65934", "WMC:E14000801": "66080", "WMC:E14000647": "65893", "WMC:W07000059": "66100", "WMC:W07000058": "66085", "WMC:E14000641": "66021", "WMC:E14000729": "65875", "WMC:E14000728": "65675", "WMC:E14000949": "65848", "WMC:W07000053": "66104", "WMC:W07000052": "66092", "WMC:E14000758": "65899", "WMC:E14000652": "65781", "WMC:E14000938": "65684", "WMC:E14000939": "66051", "WMC:E14000932": "65812", "WMC:E14000933": "65962", "WMC:E14000930": "65680", "WMC:E14000931": "65879", "WMC:E14000936": "65788", "WMC:E14000937": "65997", "WMC:E14000934": "65922", "WMC:E14000935": "65762", "WMC:E14000709": "65870", "WMC:E14000708": "65900", "WMC:E14000701": "65655", "WMC:E14000700": "65764", "WMC:E14000703": "65938", "WMC:E14000702": "65865", "WMC:E14000705": "66064", "WMC:E14000704": "65779", "WMC:E14000707": "65952", "WMC:E14000706": "65955", "WMC:E14000666": "65746", "WMC:E14000667": "65553", "WMC:E14000664": "65799", "WMC:E14000665": "65723", "WMC:E14000662": "66070", "WMC:E14000663": "65863", "WMC:E14000660": "66025", "WMC:E14000661": "65924", "WMC:E14000668": "65621", "WMC:E14000669": "65672", "WMC:E14001018": "65916", "WMC:E14001019": "65608", "WMC:E14001016": "66079", "WMC:E14001017": "65874", "WMC:E14001014": "65631", "WMC:E14001015": "65638", "WMC:E14001012": "65832", "WMC:E14001013": "65651", "WMC:E14001010": "65635", "WMC:E14001011": "65890", "WMC:W07000061": "66096", "WMC:E14000989": "65992", "WMC:E14000988": "65767", "WMC:E14000987": "65964", "WMC:E14000986": "65880", "WMC:E14000985": "65703", "WMC:E14000984": "66040", "WMC:E14000983": "65747", "WMC:E14000982": "65586", "WMC:E14000981": "65607", "WMC:E14000980": "65858", "WMC:E14000815": "66061", "WMC:E14000792": "65704", "WMC:E14000793": "66066", "WMC:E14000790": "66013", "WMC:E14000791": "66046", "WMC:E14000796": "65766", "WMC:E14000797": "65785", "WMC:E14000794": "65970", "WMC:E14000795": "65644", "WMC:E14000798": "65987", "WMC:E14000799": "65690", "WMC:E14000598": "65787", "WMC:E14000599": "65839", "WMC:E14000594": "65685", "WMC:E14000595": "65620", "WMC:E14000596": "66000", "WMC:E14000597": "65844", "WMC:E14000590": "65670", "WMC:E14000591": "66065", "WMC:E14000592": "65595", "WMC:E14000593": "65958", "WMC:E14000842": "66063", "WMC:E14000843": "65676", "WMC:E14000840": "65745", "WMC:E14000841": "65855", "WMC:E14000846": "65619", "WMC:E14000847": "65642", "WMC:E14000844": "65729", "WMC:E14000845": "65840", "WMC:E14000848": "65872", "WMC:E14000849": "66017", "WMC:E14000817": "65999", "WMC:E14000561": "65667", "WMC:E14000560": "65931", "WMC:E14000563": "66072", "WMC:E14000562": "65597", "WMC:E14000565": "65966", "WMC:E14000564": "65989", "WMC:E14000567": "65804", "WMC:E14000566": "66028", "WMC:E14000569": "65820", "WMC:E14000568": "65707", "WMC:E14000961": "65591", "WMC:E14000960": "65715", "WMC:E14000628": "65797", "WMC:E14000629": "65818", "WMC:E14000622": "65914", "WMC:E14000623": "65749", "WMC:E14000620": "65929", "WMC:E14000621": "65972", "WMC:E14000626": "66075", "WMC:E14000627": "65727", "WMC:E14000624": "65748", "WMC:E14000625": "65615", "WMC:S14000031": "14427", "WMC:S14000030": "14426", "WMC:E14001052": "65577", "WMC:E14001053": "65625", "WMC:E14001050": "65593", "WMC:E14001051": "65948", "WMC:E14001056": "66010", "WMC:E14001057": "65695", "WMC:E14001054": "65757", "WMC:E14001055": "65562", "WMC:E14001058": "66078", "WMC:E14001059": "65669", "WMC:E14000943": "65951", "WMC:E14000942": "65902", "WMC:E14000941": "65666", "WMC:E14000940": "66034", "WMC:E14000947": "65800", "WMC:E14000946": "65614", "WMC:E14000945": "65943", "WMC:E14000944": "65719", "WMC:S14000013": "14410", "WMC:S14000012": "14409", "WMC:S14000011": "14408", "WMC:S14000010": "14407", "WMC:S14000017": "14414", "WMC:S14000016": "14413", "WMC:S14000015": "14412", "WMC:S14000014": "14411", "WMC:E14000756": "65624", "WMC:E14000757": "65592", "WMC:E14000754": "65947", "WMC:E14000755": "65691", "WMC:E14000752": "65883", "WMC:E14000753": "65717", "WMC:E14000750": "65824", "WMC:E14000698": "66033", "WMC:E14000697": "66062", "WMC:E14000696": "66023", "WMC:E14000695": "65743", "WMC:E14000694": "65803", "WMC:E14000693": "66044", "WMC:E14000692": "65567", "WMC:E14000691": "66050", "WMC:E14000759": "65630", "WMC:E14000886": "65637", "WMC:E14000887": "66045", "WMC:E14000884": "66014", "WMC:E14000885": "65673", "WMC:E14000882": "65917", "WMC:E14000883": "65566", "WMC:E14000880": "65737", "WMC:E14000881": "65860", "WMC:W07000041": "66115", "WMC:W07000042": "66112", "WMC:W07000043": "66103", "WMC:W07000044": "66113", "WMC:W07000045": "66117", "WMC:E14000888": "65795", "WMC:E14000889": "65973", "WMC:E14000550": "65687", "WMC:E14000551": "65725", "WMC:E14000552": "65561", "WMC:E14000805": "65645", "WMC:E14000901": "65884", "WMC:E14000802": "65896", "WMC:E14000900": "66077", "WMC:E14000555": "65853", "WMC:E14000800": "65887", "WMC:E14000557": "65845", "WMC:E14000688": "65991", "WMC:E14000689": "65677", "WMC:E14000839": "65702", "WMC:E14000838": "65658", "WMC:S14000051": "14448", "WMC:E14000833": "65664", "WMC:E14000832": "65594", "WMC:E14000831": "66055", "WMC:E14000908": "65736", "WMC:E14000837": "65602", "WMC:E14000836": "65918", "WMC:E14000835": "65828", "WMC:E14000834": "65861", "WMC:E14000583": "66071", "WMC:E14000582": "65969", "WMC:E14000853": "65720", "WMC:E14000852": "65605", "WMC:E14000855": "65565", "WMC:W07000048": "66091", "WMC:E14000682": "65780", "WMC:E14000854": "66024", "WMC:E14000683": "65979", "WMC:E14000857": "65894", "WMC:E14000584": "65993", "WMC:E14000538": "65739", "WMC:E14000539": "66008", "WMC:E14000536": "65811", "WMC:E14000537": "66056", "WMC:E14000534": "65784", "WMC:E14000535": "65895", "WMC:E14000532": "65892", "WMC:E14000533": "65809", "WMC:E14000530": "65730", "WMC:E14000531": "65773", "WMC:E14000907": "65589", "WMC:E14000906": "65681", "WMC:E14000905": "65656", "WMC:E14000904": "66029", "WMC:E14000903": "65930", "WMC:E14000902": "66019", "WMC:S14000059": "14456", "WMC:S14000058": "14455", "WMC:S14000057": "14454", "WMC:S14000056": "14453", "WMC:S14000055": "14452", "WMC:S14000054": "14451", "WMC:S14000053": "14450", "WMC:S14000052": "14449", "WMC:E14000909": "65833", "WMC:S14000050": "14447", "WMC:E14000718": "65837", "WMC:E14000719": "65838", "WMC:E14000712": "65996", "WMC:E14000713": "65928", "WMC:E14000710": "65551", "WMC:E14000711": "65864", "WMC:E14000716": "65600", "WMC:E14000717": "65627", "WMC:E14000714": "65683", "WMC:E14000715": "65944", "WMC:E14000653": "65572", "WMC:N06000004": "66127", "WMC:E14000651": "65877", "WMC:E14000650": "65575", "WMC:E14000657": "65985", "WMC:E14000656": "65923", "WMC:E14000655": "65867", "WMC:N06000005": "66128", "WMC:E14000659": "66011", "WMC:E14000658": "65802", "WMC:W07000060": "66116", "WMC:E14001029": "65983", "WMC:E14001028": "65588", "WMC:E14001023": "65961", "WMC:E14001022": "66004", "WMC:E14001021": "65626", "WMC:E14001020": "66049", "WMC:E14001027": "65740", "WMC:E14001026": "65560", "WMC:E14001025": "65830", "WMC:W07000067": "66089", "WMC:W07000064": "66110", "WMC:W07000065": "66102", "WMC:E14000998": "65554", "WMC:E14000999": "65692", "WMC:E14000990": "65976", "WMC:E14000991": "65789", "WMC:E14000992": "65977", "WMC:E14000993": "65686", "WMC:E14000994": "65905", "WMC:E14000995": "65919", "WMC:E14000996": "65761", "WMC:E14000997": "65744", "WMC:E14000879": "65974", "WMC:E14000878": "65649", "WMC:E14000877": "66081", "WMC:E14000876": "66002", "WMC:E14000875": "65668", "WMC:E14000874": "65564", "WMC:E14000873": "66060", "WMC:E14000872": "65682", "WMC:E14000871": "66022", "WMC:E14000870": "65903", "WMC:W07000071": "66086", "WMC:W07000070": "66105", "WMC:W07000073": "66095", "WMC:N06000018": "66141", "WMC:W07000075": "66087", "WMC:W07000074": "66107", "WMC:W07000046": "66083", "WMC:W07000076": "66106", "WMC:N06000013": "66136", "WMC:N06000012": "66135", "WMC:N06000011": "66134", "WMC:N06000010": "66133", "WMC:N06000017": "66140", "WMC:N06000016": "66139", "WMC:N06000015": "66138", "WMC:N06000014": "66137", "WMC:W07000047": "66118", "WMC:E14001024": "65769", "WMC:W07000080": "66119", "WMC:E14000572": "65750", "WMC:E14000573": "65679", "WMC:E14000570": "65981", "WMC:E14000571": "65583", "WMC:E14000576": "65841", "WMC:E14000577": "65628", "WMC:E14000574": "65805", "WMC:E14000575": "65753", "WMC:E14000578": "65646", "WMC:E14000579": "65712", "WMC:W07000079": "66114", "WMC:E14000617": "65927", "WMC:E14000616": "65826", "WMC:E14000615": "65913", "WMC:E14000614": "65906", "WMC:E14000613": "66035", "WMC:E14000612": "65975", "WMC:E14000611": "66015", "WMC:E14000610": "65708", "WMC:E14000619": "65878", "WMC:E14000618": "65790", "WMC:W07000078": "66098", "WMC:E14001062": "66037", "WMC:E14001061": "65965", "WMC:E14001060": "65935", "WMC:E14000958": "65728", "WMC:E14000959": "65942", "WMC:E14000954": "65956", "WMC:E14000955": "66016", "WMC:E14000956": "65580", "WMC:E14000957": "65876", "WMC:E14000950": "65775", "WMC:E14000951": "65596", "WMC:E14000952": "65652", "WMC:E14000953": "65678", "WMC:S14000004": "14401", "WMC:S14000005": "14402", "WMC:S14000006": "14403", "WMC:S14000007": "14404", "WMC:S14000001": "14398", "WMC:S14000002": "14399", "WMC:S14000003": "14400", "WMC:S14000008": "14405", "WMC:S14000009": "14406", "WMC:E14000763": "65937", "WMC:E14000762": "65791", "WMC:E14000761": "65925", "WMC:E14000760": "65585", "WMC:E14000767": "65968", "WMC:E14000766": "65871", "WMC:E14000765": "66026", "WMC:E14000764": "65882", "WMC:E14000680": "65569", "WMC:E14000681": "65856", "WMC:E14000769": "66001", "WMC:E14000768": "65939", "WMC:E14000684": "65714", "WMC:E14000685": "65881", "WMC:E14000686": "65756", "WMC:E14000687": "65570", "WMC:S14000019": "14416", "WMC:S14000018": "14415", } # HACK slug = area_2015_map.get(mp_post.slug) current_candidacies_2015 = set() past_candidacies_2015 = set() if slug: other_post = Post.objects.get(slug=slug) current_candidacies_2015, past_candidacies_2015 = split_candidacies( election, other_post.memberships.select_related( "person", "party").filter(post_election__election__slug="2015"), ) # HACK past_candidacies = past_candidacies.union(past_candidacies_2015) current_candidates = {c.person for c in current_candidacies} past_candidates = {c.person for c in past_candidacies} current_candidates = current_candidates.union( {c.person for c in current_candidacies_2015}) past_candidates = past_candidates.union( {c.person for c in past_candidacies_2015}) other_candidates = past_candidates - current_candidates elected, unelected = split_by_elected(election, current_candidacies) # Now split those candidates into those that we know aren't # standing again, and those that we just don't know about. not_standing_candidates = { p for p in other_candidates if election in p.not_standing.all() } might_stand_candidates = { p for p in other_candidates if election not in p.not_standing.all() } might_stand_candidates = { p for p in might_stand_candidates if p.death_date == "" } not_standing_candidacies = [ c for c in past_candidacies if c.person in not_standing_candidates ] might_stand_candidacies = [ c for c in past_candidacies if c.person in might_stand_candidates ] context["candidacies_not_standing_again"] = group_candidates_by_party( election, not_standing_candidacies) context["candidacies_might_stand_again"] = group_candidates_by_party( election, might_stand_candidacies) context["elected"] = group_candidates_by_party(election, elected, show_all=True) context["unelected"] = group_candidates_by_party(election, unelected) context["has_elected"] = (len(context["elected"]["parties_and_people"]) > 0) context["show_retract_result"] = False number_of_winners = 0 for c in current_candidacies: if c.elected: number_of_winners += 1 if c.elected is not None: context["show_retract_result"] = True max_winners = get_max_winners(pee) context["show_confirm_result"] = bool(max_winners) context["add_candidate_form"] = NewPersonForm( election=election.slug, initial={ ("constituency_" + election.slug): post_id, ("standing_" + election.slug): "standing", }, hidden_post_widget=True, ) context = get_person_form_fields(context, context["add_candidate_form"]) context["identifiers_formset"] = PersonIdentifierFormsetFactory() return context
def handle(self, username=None, **options): from slumber.exceptions import HttpClientError from candidates.popit import create_popit_api_object from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson if username is None: message = "You must supply the name of a user to be associated with the image uploads." raise CommandError(message) try: user = User.objects.get(username=username) except User.DoesNotExist: message = "No user with the username '{0}' could be found" raise CommandError(message.format(username)) api = create_popit_api_object() json_filename = join( dirname(__file__), '..', '..','data', 'candidates.json' ) with open(json_filename) as f: all_data = json.load(f) # This map is needed to get getting YNR election data from # the election ID used in the JSON file. json_election_id_to_name = { e['pk']: e['fields']['name'] for e in all_data if e['model'] == 'elections.election' } person_dict = { e['pk']: e['fields'] for e in all_data if e['model'] == 'popolo.person' } candidate_list = [ dict(person_id=e['pk'], election_id=e['fields']['election']) for e in all_data if e['model'] == 'elections.candidate' ] for candidate in candidate_list: vi_person_id = candidate['person_id'] person_data = person_dict[vi_person_id] election_data, post_data = get_post_data( api, candidate['election_id'], json_election_id_to_name ) birth_date = None if person_data['birth_date']: birth_date = str(dateutil.parser.parse( person_data['birth_date'], dayfirst=True ).date()) name = person_data['name'] gender = person_data['gender'] image_url = person_data['image'] person = get_existing_popit_person(vi_person_id) if person: print("Found an existing person:", person.get_absolute_url()) else: print("No existing person, creating a new one:", name) person = PopItPerson() # Now update fields from the imported data: person.name = name person.gender = gender if birth_date: person.birth_date = str(birth_date) else: person.birth_date = None standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area']['identifier'] person.standing_in = { election_data.slug: standing_in_election } person.party_memberships = { election_data.slug: { 'id': UNKNOWN_PARTY_ID, 'name': PARTY_DATA.party_id_to_name[UNKNOWN_PARTY_ID], } } person.set_identifier('import-id', vi_person_id) change_metadata = get_change_metadata( None, 'Imported candidate from JSON', ) person.record_version(change_metadata) try: person.save_to_popit(api) if image_url: enqueue_image(person, user, image_url) except HttpClientError as hce: print("Got an HttpClientError:", hce.content) raise
def get_person_as_version_data(person, new_person=False): """ If new_person is True then skip some DB checks that we know will be empty. This should reduce the number of queries needed. """ # Prefetch to reduce the number of queries prefetch_related_objects([person], "tmp_person_identifiers") from candidates.election_specific import shorten_post_label result = {} result["id"] = str(person.id) # Add PersonIdentifier fields in to the global version namespace # TODO: move these to dict to make it easier to merge/split/revert existing_identifiers = { identifier.value_type: identifier.value for identifier in person.tmp_person_identifiers.all() } for field in PersonIdentifierFields: result[field.name] = existing_identifiers.get(field.name, "") for field in settings.SIMPLE_POPOLO_FIELDS: result[field.name] = getattr(person, field.name) or "" # Add legacy identifiers # TODO: these should use the PersonIdenfitiers model and value types, # but this code emulates the legacy way of adding IDs. if person.get_single_identifier_of_type("theyworkforyou"): result["identifiers"] = [] new_id = person.get_single_identifier_of_type( "theyworkforyou").internal_identifier if not "publicwhip" in new_id: new_id = "uk.org.publicwhip/person/{}".format(new_id) result["identifiers"].append({ "identifier": new_id, "scheme": "uk.org.publicwhip" }) if person.get_single_identifier_of_type("twitter_username"): result["identifiers"] = result.get("identifiers", []) result["identifiers"].append({ "identifier": person.get_single_identifier_of_type( "twitter_username").internal_identifier, "scheme": "twitter", }) extra_values = {} result["other_names"] = [] standing_in = {} party_memberships = {} if not new_person: result["other_names"] = [{ "name": on.name, "note": on.note, "start_date": on.start_date, "end_date": on.end_date, } for on in person.other_names.order_by( "name", "start_date", "end_date")] for membership in person.memberships.filter(post__isnull=False): post = membership.post post_election = membership.post_election election = post_election.election standing_in[post_election.election.slug] = { "post_id": post.slug, "name": shorten_post_label(post.label), } if membership.elected is not None: standing_in[election.slug]["elected"] = membership.elected if membership.party_list_position is not None: standing_in[election.slug][ "party_list_position"] = membership.party_list_position party = membership.party party_memberships[post_election.election.slug] = { "id": party.legacy_slug, "name": party.name, } for not_standing_in_election in person.not_standing.all(): standing_in[not_standing_in_election.slug] = None # Delete party memberships if not standing in this election party_memberships.pop(not_standing_in_election.slug, None) # Add `favourite_biscuits` to an `extra_fields` key # to re-produce the previous ExtraField model. # This is done like this to save changing the version diff # for exery edit to move to key to the parent object. # In the future we will have to run a script to move all the # keys to wherever we want them. extra_fields = {"favourite_biscuits": person.favourite_biscuit or ""} result["extra_fields"] = extra_fields result["standing_in"] = standing_in result["party_memberships"] = party_memberships return result
def get_person_as_version_data(person): from candidates.election_specific import shorten_post_label result = {} person_extra = person.extra result['id'] = str(person.id) for field in SimplePopoloField.objects.all(): result[field.name] = getattr(person, field.name) or '' for field in ComplexPopoloField.objects.all(): result[field.name] = getattr(person_extra, field.name) extra_values = { extra_value.field.key: extra_value.value for extra_value in person.extra_field_values.select_related('field') } extra_fields = { extra_field.key: extra_values.get(extra_field.key, '') for extra_field in ExtraField.objects.all() } if extra_fields: result['extra_fields'] = extra_fields result['other_names'] = [ { 'name': on.name, 'note': on.note, 'start_date': on.start_date, 'end_date': on.end_date, } for on in person.other_names.order_by('name', 'start_date', 'end_date') ] identifiers = list(person.identifiers.all()) if identifiers: result['identifiers'] = [ { 'scheme': i.scheme, 'identifier': i.identifier, } for i in identifiers ] result['image'] = person.image standing_in = {} party_memberships = {} for membership in person.memberships.filter(post__isnull=False): from candidates.models import MembershipExtra post = membership.post try: membership_extra = membership.extra except MembershipExtra.DoesNotExist: continue election = membership_extra.election standing_in[election.slug] = { 'post_id': post.extra.slug, 'name': shorten_post_label(post.label) } if membership_extra.elected is not None: standing_in[election.slug]['elected'] = membership_extra.elected if membership_extra.party_list_position is not None: standing_in[election.slug]['party_list_position'] = \ membership_extra.party_list_position party = membership.on_behalf_of party_memberships[election.slug] = { 'id': party.extra.slug, 'name': party.name, } for not_standing_in_election in person_extra.not_standing.all(): standing_in[not_standing_in_election.slug] = None result['standing_in'] = standing_in result['party_memberships'] = party_memberships return result
def __init__(self, *args, **kwargs): from candidates.election_specific import shorten_post_label election = kwargs.pop("election", None) hidden_post_widget = kwargs.pop("hidden_post_widget", None) super().__init__(*args, **kwargs) election_data = Election.objects.get_by_slug(election) standing_field_kwargs = { "label": _("Standing in %s") % election_data.name, "choices": self.STANDING_CHOICES, } if hidden_post_widget: standing_field_kwargs["widget"] = forms.HiddenInput() else: standing_field_kwargs["widget"] = forms.Select( attrs={"class": "standing-select"}) self.fields["standing_" + election] = forms.ChoiceField(**standing_field_kwargs) self.elections_with_fields = [election_data] post_field_kwargs = { "label": _("Post in the {election}").format(election=election_data.name), "max_length": 256, } if hidden_post_widget: post_field_kwargs["widget"] = forms.HiddenInput() post_field = StrippedCharField(**post_field_kwargs) else: post_field = forms.ChoiceField( label=_("Post in the {election}").format( election=election_data.name), required=False, choices=[("", "")] + sorted( [(post.slug, shorten_post_label(post.label)) for post in Post.objects.filter(elections__slug=election) ], key=lambda t: t[1], ), widget=forms.Select(attrs={"class": "post-select"}), ) self.fields["constituency_" + election] = post_field # It seems to be common in elections around the world for # there to be different sets of parties that candidates can # stand for depending on, for example, where in the country # they're standing. (For example, in the UK General Election, # there is a different register of parties for Northern # Ireland and Great Britain constituencies.) We create a party # choice field for each such "party set" and make sure only # the appropriate one is shown, depending on the election and # selected constituency, using Javascript. specific_party_set = None if hidden_post_widget: # Then the post can't be changed, so only add the # particular party set relevant for that post: post_id = kwargs["initial"]["constituency_" + election] specific_party_set = PartySet.objects.get(post__slug=post_id) party_registers_for_election = set( election_data.postextraelection_set.annotate( Count("post__party_set__slug")).values_list( "post__party_set__slug", flat=True)) for register in party_registers_for_election: register = register.upper() if specific_party_set and (register != specific_party_set.slug.upper()): continue self.fields[ "party_" + register + "_" + election] = forms.ChoiceField( label=_("Party in {election} ({register})").format( election=election_data.name, register=register), choices=Party.objects.register(register).party_choices(), required=False, widget=forms.Select( attrs={ "class": "party-select party-select-" + election }), ) if election_data.party_lists_in_use: # Then add a field to enter the position on the party list # as an integer: field_name = "party_list_position_" + register + "_" + election self.fields[field_name] = forms.IntegerField( label= _("Position in party list ('1' for first, '2' for second, etc.)" ), min_value=1, required=False, widget=forms.NumberInput( attrs={ "class": "party-position party-position-" + election }), )
def get_person_as_version_data(person, new_person=False): """ If new_person is True then skip some DB checks that we know will be empty. This should reduce the number of queries needed. """ from candidates.election_specific import shorten_post_label result = {} result["id"] = str(person.id) for field in settings.SIMPLE_POPOLO_FIELDS: result[field.name] = getattr(person, field.name) or "" for field in ComplexPopoloField.objects.all(): if new_person: # Just set the attrs, as these will all be empty result[field.name] = "" else: result[field.name] = getattr(person, field.name) extra_values = {} result["other_names"] = [] standing_in = {} party_memberships = {} if not new_person: result["other_names"] = [ { "name": on.name, "note": on.note, "start_date": on.start_date, "end_date": on.end_date, } for on in person.other_names.order_by( "name", "start_date", "end_date" ) ] identifiers = list(person.identifiers.all()) if identifiers: result["identifiers"] = [ {"scheme": i.scheme, "identifier": i.identifier} for i in identifiers ] for membership in person.memberships.filter(post__isnull=False): post = membership.post post_election = membership.post_election election = post_election.election standing_in[post_election.election.slug] = { "post_id": post.slug, "name": shorten_post_label(post.label), } if membership.elected is not None: standing_in[election.slug]["elected"] = membership.elected if membership.party_list_position is not None: standing_in[election.slug][ "party_list_position" ] = membership.party_list_position party = membership.party party_memberships[post_election.election.slug] = { "id": party.legacy_slug, "name": party.name, } for not_standing_in_election in person.not_standing.all(): standing_in[not_standing_in_election.slug] = None extra_values = { extra_value.field.key: extra_value.value for extra_value in person.extra_field_values.select_related("field") } extra_fields = { extra_field.key: extra_values.get(extra_field.key, "") for extra_field in ExtraField.objects.all() } if extra_fields: result["extra_fields"] = extra_fields result["standing_in"] = standing_in result["party_memberships"] = party_memberships return result
def handle(self, username=None, **options): from slumber.exceptions import HttpClientError from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson from candidates.popit import create_popit_api_object election_data = { 'prv-2015': 'listedescandidatsauxelectionslegislativeslisteprovincialeanptic.csv', 'nat-2015': 'listedescandidatsauxelectionslegislativesanptic.csv' } field_map = { 'prv-2015': { 'region': 1, 'party': 4, 'list_order': 5, 'first_name': 7, 'last_name': 6, 'gender': 8, 'birth_date': 9, 'party_short': 3 }, 'nat-2015': { 'region': 0, 'party': 2, 'list_order': 3, 'first_name': 5, 'last_name': 4, 'gender': 6, 'birth_date': 7, 'party_short': 2 } } api = create_popit_api_object() party_id_missing = {} party_name_to_id = {} for party_id, party_name in PARTY_DATA.party_id_to_name.items(): party_name_to_id[party_name] = party_id for election_id, filename in election_data.items(): csv_filename = join( dirname(__file__), '..', '..', 'data', filename ) fields = field_map[election_id] with codecs.open(csv_filename, 'r', encoding='windows-1252') as f: initial = True for candidate in unicode_csv_reader(f): # skip header line if initial: initial = False continue region = candidate[fields['region']] party = candidate[fields['party']] party_list_order = candidate[fields['list_order']] first_name = string.capwords(candidate[fields['first_name']]) last_name = string.capwords(candidate[fields['last_name']]) gender = candidate[fields['gender']] birth_date = None if candidate[fields['birth_date']] is not None: birth_date = str(dateutil.parser.parse( candidate[fields['birth_date']], dayfirst=True ).date()) name = first_name + ' ' + last_name id = '-'.join([ re.sub('[^\w]*', '', re.sub(r' ', '-', strip_accents(name.lower()))), re.sub('[^\w]*', '', candidate[fields['party_short']].lower()), birth_date ]) # national candidate if region == 'PAYS': region = 'Burkina Faso' election_data, post_data = get_post_data( api, election_id, region ) # debug # tmp = '%s %s %s (%s) - %s (%s)' % ( id, first_name, last_name, party, region, post_data['label'] ) # print(tmp) person = get_existing_popit_person(id) if person: # print("Found an existing person:", person.get_absolute_url()) pass else: print("No existing person, creating a new one:", name) person = PopItPerson() person.set_identifier('import-id', id) person.family_name = last_name person.given_name = first_name person.name = name person.gender = gender if birth_date: person.birth_date = str(birth_date) else: person.birth_date = None standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), 'party_list_position': party_list_order, } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area']['identifier'] person.standing_in = { election_data.slug: standing_in_election } change_metadata = get_change_metadata( None, 'Imported candidate from CSV', ) party_comp = re.sub(' +', ' ', party) party_id = UNKNOWN_PARTY_ID if party_comp in party_name_to_id.keys(): party_id = party_name_to_id[party_comp] party = party_comp else: party_id = party_name_to_id['Unknown Party'] party = 'Unknown Party' if party_id == UNKNOWN_PARTY_ID and party_comp not in party_id_missing.keys(): party_id_missing[party_comp] = 1 person.party_memberships = { election_data.slug: { 'id': party_id, 'name': party, 'imported_name': party_comp } } person.record_version(change_metadata) try: person.save_to_popit(api) except HttpClientError as hce: print("Got an HttpClientError:", hce.content) raise if len(party_id_missing) > 0: print("Unmatched party names:") for name in party_id_missing.keys(): print(name)
def handle(self, **options): from slumber.exceptions import HttpClientError, HttpServerError from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson from candidates.popit import create_popit_api_object api = create_popit_api_object() csv_filename = join(dirname(__file__), '..', '..', 'data', 'candidates.csv') with open(csv_filename) as f: all_data = csv.DictReader(f) for candidate in all_data: vi_person_id = candidate['Distrito'] + candidate[ 'Numero Lista'] + candidate['Posicion'] + candidate[ 'Cargo'] + candidate['Nombre Lista'] election_data, post_data = get_post_data( api, candidate['Cargo'], candidate['Distrito']) if (election_data == False): print("Skipping: " + candidate['Cargo'] + ", " + candidate['Distrito'] + ", " + candidate['Nombre']) continue name = candidate['Nombre'] birth_date = None gender = None image_url = None person = get_existing_popit_person(vi_person_id) if person: print("Found an existing person:", person.get_absolute_url()) else: print("No existing person, creating a new one:", name) person = PopItPerson() # Now update fields from the imported data: person.name = name.split(",")[1] + " " + name.split(",")[0] person.gender = gender if birth_date: person.birth_date = str(birth_date) else: person.birth_date = None standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), 'party_list_position': candidate['Posicion'], } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area'][ 'identifier'] person.standing_in = {election_data.slug: standing_in_election} party_id = get_party_id(candidate["Partido"]) person.party_memberships = { election_data.slug: { 'id': party_id, 'name': PARTY_DATA.party_id_to_name[party_id], } } person.set_identifier('import-id', vi_person_id) change_metadata = get_change_metadata( None, 'Imported candidate from CSV', ) person.record_version(change_metadata) try: person.save_to_popit(api) except HttpClientError as hce: print("Got an HttpClientError:", hce.content) raise except HttpServerError as hse: print("The server error content was:", hse.content) raise
def short_label(self): from candidates.election_specific import shorten_post_label return shorten_post_label(self.base.label)
def handle(self, username=None, **options): from slumber.exceptions import HttpClientError from candidates.popit import create_popit_api_object from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson if username is None: message = "You must supply the name of a user to be associated with the image uploads." raise CommandError(message) try: user = User.objects.get(username=username) except User.DoesNotExist: message = "No user with the username '{0}' could be found" raise CommandError(message.format(username)) api = create_popit_api_object() json_filename = join(dirname(__file__), '..', '..', 'data', 'candidates.json') with open(json_filename) as f: all_data = json.load(f) # This map is needed to get getting YNR election data from # the election ID used in the JSON file. json_election_id_to_name = { e['pk']: e['fields']['name'] for e in all_data if e['model'] == 'elections.election' } person_dict = { e['pk']: e['fields'] for e in all_data if e['model'] == 'popolo.person' } candidate_list = [ dict(person_id=e['pk'], election_id=e['fields']['election']) for e in all_data if e['model'] == 'elections.candidate' ] for candidate in candidate_list: vi_person_id = candidate['person_id'] person_data = person_dict[vi_person_id] election_data, post_data = get_post_data(api, candidate['election_id'], json_election_id_to_name) birth_date = None if person_data['birth_date']: birth_date = str( dateutil.parser.parse(person_data['birth_date'], dayfirst=True).date()) name = person_data['name'] gender = person_data['gender'] image_url = person_data['image'] person = get_existing_popit_person(vi_person_id) if person: print("Found an existing person:", person.get_absolute_url()) else: print("No existing person, creating a new one:", name) person = PopItPerson() # Now update fields from the imported data: person.name = name person.gender = gender if birth_date: person.birth_date = str(birth_date) else: person.birth_date = None standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area'][ 'identifier'] person.standing_in = {election_data.slug: standing_in_election} person.party_memberships = { election_data.slug: { 'id': UNKNOWN_PARTY_ID, 'name': PARTY_DATA.party_id_to_name[UNKNOWN_PARTY_ID], } } person.set_identifier('import-id', vi_person_id) change_metadata = get_change_metadata( None, 'Imported candidate from JSON', ) person.record_version(change_metadata) try: person.save_to_popit(api) if image_url: enqueue_image(person, user, image_url) except HttpClientError as hce: print("Got an HttpClientError:", hce.content) raise
def get_person_as_version_data(person, new_person=False): """ If new_person is True then skip some DB checks that we know will be empty. This should reduce the number of queries needed. """ from candidates.election_specific import shorten_post_label result = {} person_extra = person.extra result['id'] = str(person.id) for field in settings.SIMPLE_POPOLO_FIELDS: result[field.name] = getattr(person, field.name) or '' for field in ComplexPopoloField.objects.all(): if new_person: # Just set the attrs, as these will all be empty result[field.name] = '' else: result[field.name] = getattr(person_extra, field.name) extra_values = {} result['other_names'] = [] standing_in = {} party_memberships = {} result['image'] = '' if not new_person: result['other_names'] = [{ 'name': on.name, 'note': on.note, 'start_date': on.start_date, 'end_date': on.end_date, } for on in person.other_names.order_by( 'name', 'start_date', 'end_date')] identifiers = list(person.identifiers.all()) if identifiers: result['identifiers'] = [{ 'scheme': i.scheme, 'identifier': i.identifier, } for i in identifiers] result['image'] = person.image for membership in person.memberships.filter(post__isnull=False): post = membership.post post_election = membership.post_election election = post_election.election standing_in[post_election.election.slug] = { 'post_id': post.extra.slug, 'name': shorten_post_label(post.label) } if membership.elected is not None: standing_in[election.slug]['elected'] = \ membership.elected if membership.party_list_position is not None: standing_in[election.slug]['party_list_position'] = \ membership.party_list_position party = membership.on_behalf_of party_memberships[post_election.election.slug] = { 'id': party.extra.slug, 'name': party.name, } for not_standing_in_election in person_extra.not_standing.all(): standing_in[not_standing_in_election.slug] = None extra_values = { extra_value.field.key: extra_value.value for extra_value in person.extra_field_values.select_related( 'field') } extra_fields = { extra_field.key: extra_values.get(extra_field.key, '') for extra_field in ExtraField.objects.all() } if extra_fields: result['extra_fields'] = extra_fields result['standing_in'] = standing_in result['party_memberships'] = party_memberships return result
def handle(self, **options): from slumber.exceptions import HttpClientError, HttpServerError from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson from candidates.popit import create_popit_api_object api = create_popit_api_object() csv_filename = join( dirname(__file__), '..', '..','data', 'candidates.csv' ) with open(csv_filename) as f: all_data = csv.DictReader(f) for candidate in all_data: vi_person_id = candidate['Distrito']+candidate['Numero Lista']+candidate['Posicion']+candidate['Cargo']+candidate['Nombre Lista'] election_data, post_data = get_post_data( api, candidate['Cargo'], candidate['Distrito'] ) if (election_data == False): print("Skipping: "+ candidate['Cargo'] +", " + candidate['Distrito']+", " + candidate['Nombre']) continue; name = candidate['Nombre'] birth_date = None gender = None image_url = None person = get_existing_popit_person(vi_person_id) if person: print("Found an existing person:", person.get_absolute_url()) else: print("No existing person, creating a new one:", name) person = PopItPerson() # Now update fields from the imported data: person.name = name.split(",")[1] + " " + name.split(",")[0] person.gender = gender if birth_date: person.birth_date = str(birth_date) else: person.birth_date = None standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), 'party_list_position': candidate['Posicion'], } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area']['identifier'] person.standing_in = { election_data.slug: standing_in_election } party_id = get_party_id(candidate["Partido"]); person.party_memberships = { election_data.slug: { 'id': party_id, 'name': PARTY_DATA.party_id_to_name[party_id], } } person.set_identifier('import-id', vi_person_id) change_metadata = get_change_metadata( None, 'Imported candidate from CSV', ) person.record_version(change_metadata) try: person.save_to_popit(api) except HttpClientError as hce: print("Got an HttpClientError:", hce.content) raise except HttpServerError as hse: print("The server error content was:", hse.content) raise
def get_person_as_version_data(person): from candidates.election_specific import shorten_post_label result = {} person_extra = person.extra result['id'] = str(person.id) for field in SimplePopoloField.objects.all(): result[field.name] = getattr(person, field.name) or '' for field in ComplexPopoloField.objects.all(): result[field.name] = getattr(person_extra, field.name) extra_values = { extra_value.field.key: extra_value.value for extra_value in person.extra_field_values.select_related('field') } extra_fields = { extra_field.key: extra_values.get(extra_field.key, '') for extra_field in ExtraField.objects.all() } if extra_fields: result['extra_fields'] = extra_fields result['other_names'] = [{ 'name': on.name, 'note': on.note, 'start_date': on.start_date, 'end_date': on.end_date, } for on in person.other_names.order_by('name', 'start_date', 'end_date')] identifiers = list(person.identifiers.all()) if identifiers: result['identifiers'] = [{ 'scheme': i.scheme, 'identifier': i.identifier, } for i in identifiers] result['image'] = person.image standing_in = {} party_memberships = {} for membership in person.memberships.filter(post__isnull=False): from candidates.models import MembershipExtra post = membership.post try: membership_extra = membership.extra except MembershipExtra.DoesNotExist: continue election = membership_extra.election standing_in[election.slug] = { 'post_id': post.extra.slug, 'name': shorten_post_label(post.label) } if membership_extra.elected is not None: standing_in[election.slug]['elected'] = membership_extra.elected if membership_extra.party_list_position is not None: standing_in[election.slug]['party_list_position'] = \ membership_extra.party_list_position party = membership.on_behalf_of party_memberships[election.slug] = { 'id': party.extra.slug, 'name': party.name, } for not_standing_in_election in person_extra.not_standing.all(): standing_in[not_standing_in_election.slug] = None result['standing_in'] = standing_in result['party_memberships'] = party_memberships return result
def handle(self, username=None, **options): from slumber.exceptions import HttpClientError from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson from candidates.popit import create_popit_api_object election_data = { 'prv-2015': 'listedescandidatsauxelectionslegislativeslisteprovincialeanptic.csv', 'nat-2015': 'listedescandidatsauxelectionslegislativesanptic.csv' } field_map = { 'prv-2015': { 'region': 1, 'party': 4, 'list_order': 5, 'first_name': 7, 'last_name': 6, 'gender': 8, 'birth_date': 9, 'party_short': 3 }, 'nat-2015': { 'region': 0, 'party': 2, 'list_order': 3, 'first_name': 5, 'last_name': 4, 'gender': 6, 'birth_date': 7, 'party_short': 2 } } api = create_popit_api_object() party_id_missing = {} party_name_to_id = {} for party_id, party_name in PARTY_DATA.party_id_to_name.items(): party_name_to_id[party_name] = party_id for election_id, filename in election_data.items(): csv_filename = join(dirname(__file__), '..', '..', 'data', filename) fields = field_map[election_id] with codecs.open(csv_filename, 'r', encoding='windows-1252') as f: initial = True for candidate in unicode_csv_reader(f): # skip header line if initial: initial = False continue region = candidate[fields['region']] party = candidate[fields['party']] party_list_order = candidate[fields['list_order']] first_name = string.capwords( candidate[fields['first_name']]) last_name = string.capwords(candidate[fields['last_name']]) gender = candidate[fields['gender']] birth_date = None if candidate[fields['birth_date']] is not None: birth_date = str( dateutil.parser.parse( candidate[fields['birth_date']], dayfirst=True).date()) name = first_name + ' ' + last_name id = '-'.join([ re.sub('[^\w]*', '', re.sub(r' ', '-', strip_accents(name.lower()))), re.sub('[^\w]*', '', candidate[fields['party_short']].lower()), birth_date ]) # national candidate if region == 'PAYS': region = 'Burkina Faso' election_data, post_data = get_post_data( api, election_id, region) # debug # tmp = '%s %s %s (%s) - %s (%s)' % ( id, first_name, last_name, party, region, post_data['label'] ) # print(tmp) person = get_existing_popit_person(id) if person: # print("Found an existing person:", person.get_absolute_url()) pass else: print("No existing person, creating a new one:", name) person = PopItPerson() person.set_identifier('import-id', id) person.family_name = last_name person.given_name = first_name person.name = name person.gender = gender if birth_date: person.birth_date = str(birth_date) else: person.birth_date = None standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), 'party_list_position': party_list_order, } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area'][ 'identifier'] person.standing_in = { election_data.slug: standing_in_election } change_metadata = get_change_metadata( None, 'Imported candidate from CSV', ) party_comp = re.sub(' +', ' ', party) party_id = UNKNOWN_PARTY_ID if party_comp in party_name_to_id.keys(): party_id = party_name_to_id[party_comp] party = party_comp else: party_id = party_name_to_id['Unknown Party'] party = 'Unknown Party' if party_id == UNKNOWN_PARTY_ID and party_comp not in party_id_missing.keys( ): party_id_missing[party_comp] = 1 person.party_memberships = { election_data.slug: { 'id': party_id, 'name': party, 'imported_name': party_comp } } person.record_version(change_metadata) try: person.save_to_popit(api) except HttpClientError as hce: print("Got an HttpClientError:", hce.content) raise if len(party_id_missing) > 0: print("Unmatched party names:") for name in party_id_missing.keys(): print(name)
def short_label(self): from candidates.election_specific import shorten_post_label return shorten_post_label(self.label)
def handle(self, **options): from slumber.exceptions import HttpClientError from candidates.cache import get_post_cached, UnknownPostException from candidates.election_specific import PARTY_DATA, shorten_post_label from candidates.models import PopItPerson from candidates.popit import create_popit_api_object spreadsheet_url = 'https://docs.google.com/spreadsheets/d/{0}/pub?output=csv'\ .format(GOOGLE_DOC_ID) candidate_list = requests.get(spreadsheet_url) content = StringIO(unicode(candidate_list.content)) reader = csv.DictReader(content) api = create_popit_api_object() for row in reader: try: election_data = Election.objects.get_by_slug('council-member-2015') ocd_division = election_data.post_id_format.format(area_id=row['Ward']) post_data = get_post_cached(api, ocd_division)['result'] except (UnknownPostException, memcache.Client.MemcachedKeyCharacterError): election_data = Election.objects.get_by_slug('school-board-2015') post_data = get_post_cached(api, election_data.post_id_format)['result'] person_id = slugify(row['Name']) person = get_existing_popit_person(person_id) if person: print("Found an existing person:", row['Name']) else: print("No existing person, creating a new one:", row['Name']) person = PopItPerson() person.name = row['Name'] # TODO: Get these attributes in the spreadsheet # person.gender = gender # if birth_date: # person.birth_date = str(birth_date) # else: # person.birth_date = None person.email = row['Campaign Email'] person.facebook_personal_url = row["Candidate's Personal Facebook Profile"] person.facebook_page_url = row['Campaign Facebook Page'] person.twitter_username = row['Campaign Twitter']\ .replace('N', '')\ .replace('N/A', '')\ .replace('http://twitter.com/', '')\ .replace('https://twitter.com/', '') person.linkedin_url = row['LinkedIn'] person.homepage_url = row['Campaign Website\n'] standing_in_election = { 'post_id': post_data['id'], 'name': shorten_post_label(post_data['label']), } if 'area' in post_data: standing_in_election['mapit_url'] = post_data['area']['identifier'] person.standing_in = { election_data.slug: standing_in_election } if 'dfl' in row['Party'].lower(): party_id = 'party:101' elif 'green' in row['Party'].lower(): party_id = 'party:201' elif 'independence' in row['Party'].lower(): party_id = 'party:301' else: party_id = 'party:401' party_name = PARTY_DATA.party_id_to_name[party_id] person.party_memberships = { election_data.slug: { 'id': party_id, 'name': party_name, } } person.set_identifier('import-id', person_id) change_metadata = get_change_metadata( None, 'Imported candidate from Google Spreadsheet', ) person.record_version(change_metadata) try: person.save_to_popit(api) # TODO: Get candidate Images # if image_url: # enqueue_image(person, user, image_url) except HttpClientError as hce: print "Got an HttpClientError:", hce.content raise