from otree.api import * import random class C(BaseConstants): NAME_IN_URL = 'survey_pre_treatment' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 # Labels for the 6-point Likert scale LIKERT_CHOICES = [ [1, 'Strongly disagree'], [2, 'Disagree'], [3, 'Somewhat disagree'], [4, 'Somewhat agree'], [5, 'Agree'], [6, 'Strongly agree'], ] # Item texts — individualism-communitarianism subscale # Source: Kahan et al. (2007, 2011) # Items 1, 2, 3, 5, 6 are scored directly (individualism direction) # Item 4 is REVERSED (communitarianism direction → high agreement = low individualism) IC_ITEMS = { 'ic_1': 'The government interferes far too much in our everyday lives.', 'ic_2': 'People should be allowed to make their own choices, even if it means making mistakes.', 'ic_3': 'We have gone too far in pushing equal rights in this country.', 'ic_4': 'The government should do more to advance society\'s goals, even if that means limiting the freedom and choices of individuals.', 'ic_5': "It's not the government's place to try to protect people from themselves.", 'ic_6': 'Society works best when it allows individuals to succeed or fail on their own.', } # Which items are reverse-scored (communitarianism end) IC_REVERSED = {'ic_4'} class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # --- Individualism-Communitarianism items --- # Each is a 1–6 Likert item; ic_4 is reverse-scored ic_1 = models.IntegerField( label=C.IC_ITEMS['ic_1'], choices=C.LIKERT_CHOICES, widget=widgets.RadioSelect, ) ic_2 = models.IntegerField( label=C.IC_ITEMS['ic_2'], choices=C.LIKERT_CHOICES, widget=widgets.RadioSelect, ) ic_3 = models.IntegerField( label=C.IC_ITEMS['ic_3'], choices=C.LIKERT_CHOICES, widget=widgets.RadioSelect, ) ic_4 = models.IntegerField( label=C.IC_ITEMS['ic_4'], choices=C.LIKERT_CHOICES, widget=widgets.RadioSelect, ) ic_5 = models.IntegerField( label=C.IC_ITEMS['ic_5'], choices=C.LIKERT_CHOICES, widget=widgets.RadioSelect, ) ic_6 = models.IntegerField( label=C.IC_ITEMS['ic_6'], choices=C.LIKERT_CHOICES, widget=widgets.RadioSelect, ) # Computed score: mean of all 6 items after reversing ic_4 # Higher score = more individualistic; lower score = more communitarian # Range: 1–6 (stored as a float rounded to 2 decimals) ic_score = models.FloatField(blank=True) # --- Helper: compute and store the IC scale score --- def compute_ic_score(player: Player): raw = { 'ic_1': player.ic_1, 'ic_2': player.ic_2, 'ic_3': player.ic_3, 'ic_4': player.ic_4, 'ic_5': player.ic_5, 'ic_6': player.ic_6, } scores = [] for field, value in raw.items(): if field in C.IC_REVERSED: scores.append(7 - value) # reverse: 1↔6, 2↔5, 3↔4 else: scores.append(value) player.ic_score = round(sum(scores) / len(scores), 2) # --- Pages --- class Questionnaire(Page): form_model = 'player' form_fields = ['ic_1', 'ic_2', 'ic_3', 'ic_4', 'ic_5', 'ic_6'] @staticmethod def vars_for_template(player: Player): items = [] keys = list(C.IC_ITEMS.keys()) random.shuffle(keys) DIC_IC = [(k, C.IC_ITEMS[k]) for k in keys] i = 1 for field_name, label in DIC_IC: items.append({ 'name': field_name, 'label': label, 'row_class': 'row-even' if i % 2 == 0 else 'row-odd', }) i+=1 return { 'items': items, 'likert_choices': C.LIKERT_CHOICES, 'fields_order': [item['name'] for item in items], # randomised order as a list } @staticmethod def before_next_page(player: Player, timeout_happened): compute_ic_score(player) page_sequence = [Questionnaire]