from otree.api import * import random import cpo_shared doc = """ CPO - Vignette experiment (rating version). Each participant goes through C.NUM_ROUNDS = 4 rounds, one per profession (Avvocato/a, Ingegnere/a, Architetto/a, Dottore/ssa - order randomized per participant). In each round a short scenario is shown, followed by an accordion of N profiles (N = cpo_shared config 'PROFILES_PER_SCENARIO', default 4). For each profile the participant rates, on a 1-10 scale, how likely they would be to turn to that professional. The profile pool (names, ages, titles - depending on the between-subject title-treatment arm - and profession-specific "quality signal" details) is built once per participant by cpo_shared.build_profile_pool() and stored in participant.vars['cpo_pool'] / ['cpo_treatment']. """ REGIONI_ITALIANE = [ 'Abruzzo', 'Basilicata', 'Calabria', 'Campania', 'Emilia-Romagna', 'Friuli-Venezia Giulia', 'Lazio', 'Liguria', 'Lombardia', 'Marche', 'Molise', 'Piemonte', 'Puglia', 'Sardegna', 'Sicilia', 'Toscana', 'Provincia autonoma di Trento', 'Provincia autonoma di Bolzano', 'Umbria', "Valle d'Aosta", 'Veneto', 'Altro / Lavoro all\'estero' ] class C(BaseConstants): NAME_IN_URL = 'cpo_vignette2' PLAYERS_PER_GROUP = None NUM_ROUNDS = len(cpo_shared.PROFESSIONS) PROFILES_PER_SCENARIO = cpo_shared.DEFAULT_CONFIG['PROFILES_PER_SCENARIO'] NUM_SCENARIOS = len(cpo_shared.PROFESSIONS) MAX_PROG = 50 N_PAGES = 7 not_mandatory = False next_progress = 'cpo_survey/_templates/next_progress.html' class Subsession(BaseSubsession): pass def creating_session(subsession): if subsession.round_number == 1: for p in subsession.get_players(): cpo_shared.build_profile_pool(p.participant, cpo_shared.DEFAULT_CONFIG) order = [prof['key'] for prof in cpo_shared.PROFESSIONS] random.shuffle(order) p.participant.vars['cpo2_profession_order'] = order for p in subsession.get_players(): order = p.participant.vars['cpo2_profession_order'] profession_key = order[subsession.round_number - 1] pool = p.participant.vars['cpo_pool'] entry = pool[profession_key] scenario = entry['scenario'] profiles = entry['profiles'] p.profession_key = profession_key p.scenario_id = scenario['id'] p.treatment = p.participant.vars['cpo_treatment'] p.nome = '/'.join(pr['nome'] for pr in profiles) p.cognome = '/'.join(pr['cognome'] for pr in profiles) p.donna = '/'.join(str(pr['donna']) for pr in profiles) p.titolo = '/'.join(pr['titolo'] for pr in profiles) p.titolo_fem = '/'.join(str(pr['titolo_fem']) for pr in profiles) p.anno_nascita = '/'.join(str(pr['anno_nascita']) for pr in profiles) p.anno_iscr = '/'.join(str(pr['anno_iscr']) for pr in profiles) p.quality_1 = '/'.join(str(pr['qualita'][0]['value']) for pr in profiles) p.quality_2 = '/'.join(str(pr['qualita'][1]['value']) for pr in profiles) class Group(BaseGroup): pass class Player(BasePlayer): # Vignette fields profession_key = models.StringField() scenario_id = models.StringField() treatment = models.IntegerField() donna = models.StringField() titolo_fem = models.StringField() # export-friendly snapshot of the profiles shown this round # (one value per profile, '/'-joined, in the same order as choice_1..N) nome = models.StringField() cognome = models.StringField() titolo = models.StringField() anno_nascita = models.StringField() anno_iscr = models.StringField() quality_1 = models.StringField() quality_2 = models.StringField() for _i in range(1, C.PROFILES_PER_SCENARIO + 1): locals()['choice_%d' % _i] = cpo_shared.choice_scale() del _i # other fields privacy = models.BooleanField( label="Confermo di avere almeno 18 anni e di aver ricevuto e letto le informazioni generali sul progetto e l'informativa sulla privacy. Comprendo che la mia partecipazione al questionario è volontaria e anonima, e che posso ritirarmi in qualsiasi momento. Riconosco che i miei dati saranno trattati nel pieno rispetto della normativa vigente e pertanto acconsento a partecipare al questionario, autorizzando l'utilizzo delle mie risposte per ulteriori scopi di ricerca.", widget=widgets.CheckboxInput ) stato_lavorativo = models.IntegerField( label="Qual è la Sua attuale situazione lavorativa prevalente ?", choices=cpo_shared.STATO_LAVORATIVO_CHOICES, widget=widgets.RadioSelect, # NOT blank: the routing depends on it ) professione_attuale = models.StringField(blank=C.not_mandatory) # label now dynamic regione = models.StringField(choices=REGIONI_ITALIANE, blank=C.not_mandatory) # PAGES class Privacy(Page): form_model = 'player' form_fields = ['privacy'] @staticmethod def is_displayed(player: Player): return player.round_number == 1 class SL(Page): template_name = 'cpo_vignette2/StatoLavorativo.html' form_model = 'player' form_fields = ['stato_lavorativo'] @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars['cpo_stato_lavorativo'] = player.stato_lavorativo @staticmethod def vars_for_template(player: Player): return dict( progress_pct=round(C.MAX_PROG * 1 / C.N_PAGES), ) class DM(Page): template_name = 'cpo_vignette2/Demografia.html' form_model = 'player' @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def get_form_fields(player: Player): info = cpo_shared.STATO_INFO[player.stato_lavorativo] if info['prof_label'] is None: return ['regione'] return ['professione_attuale', 'regione'] @staticmethod def vars_for_template(player: Player): info = cpo_shared.STATO_INFO[player.stato_lavorativo] return dict( prof_label=info['prof_label'], # None -> hide the card reg_label=info['reg_label'], progress_pct=round(C.MAX_PROG * 2 / C.N_PAGES), ) class Intro(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def vars_for_template(player: Player): return dict( progress_pct=round(C.MAX_PROG * 3 / C.N_PAGES), ) class Sc(Page): template_name = 'cpo_vignette2/Demo.html' form_model = 'player' @staticmethod def get_form_fields(player: Player): return ['choice_%d' % i for i in range(1, C.PROFILES_PER_SCENARIO + 1)] @staticmethod def vars_for_template(player: Player): pool = player.participant.vars['cpo_pool'] entry = pool[player.profession_key] profession = entry['profession'] scenario = entry['scenario'] profiles = entry['profiles'] scenario_text = cpo_shared.get_scenario_text(player.profession_key, scenario, player.participant) indexed_profiles = [] for i, prof in enumerate(profiles, start=1): indexed_profiles.append(dict(prof, index=i, choice_field='choice_%d' % i)) return dict( profession=profession, scenario_text=scenario_text, closing_text=cpo_shared.closing_text(len(profiles)), profiles=indexed_profiles, n_profiles=len(profiles), round_nr=player.round_number, rounds=C.NUM_ROUNDS, progress_pct = 22 + round(28 * player.round_number / C.NUM_ROUNDS) ) page_sequence = [Privacy, SL, DM, Intro, Sc]