from otree.api import * c = cu doc = 'Post experiment questions. Includes survey questions, Tightwad-spendthrift scale by Rick Scott, Cynthia Cryder, and George Loewenstein (2008), and demographic questions.\n' class C(BaseConstants): # built-in constants NAME_IN_URL = 'Survey' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 1 # user-defined constants LIKERT_OPTS = (1, 2, 3, 4, 5) SMILEY_LIKERT_OPTS = (1, 2, 3, 4, 5, 6, 7) UW_TETON_BG_TEMPLATE = 'Survey/uw_teton_bg.html' UW_TETON_SURVEY_TEMPLATE = 'Survey/uw_teton_survey.html' CHECKBOX_LIST_TEMPLATE = 'Survey/checkbox_list.html' class Subsession(BaseSubsession): pass def after_all_players_arrive(subsession: Subsession): session = subsession.session # pull the matrix you stored in the code‐entry app matrix = subsession.session.vars.get('couple_matrix') if not matrix: # safety check in case someone forgot to run grouping first raise RuntimeError("No couple_matrix in session.vars") # re‐apply it in this app's subsession subsession.set_group_matrix(matrix) class Group(BaseGroup): pass class Player(BasePlayer): r_entiltedMe = models.IntegerField(choices=C.LIKERT_OPTS, label='I felt entitled to spend the money earned by me in the joint account.', widget=widgets.RadioSelectHorizontal) r_entiltedPartner = models.IntegerField(choices=C.LIKERT_OPTS, label='I felt entitled to spend the money earned by my partner in the joint account.', widget=widgets.RadioSelectHorizontal) r_upsetPartner = models.IntegerField(choices=C.LIKERT_OPTS, label='My partner would be upset with me if I spent a large portion of the money from the joint account in this study on an item only I would use.', widget=widgets.RadioSelectHorizontal) r_guilty = models.IntegerField(choices=C.LIKERT_OPTS, label='I would feel guilty if I spent a large portion of the money from the joint account in this study on an item only I would use.', widget=widgets.RadioSelectHorizontal) r_entitledPartnerToSpendTheirs = models.IntegerField(choices=C.LIKERT_OPTS, label='I felt my partner was entitled to spend the money earned by themselves in the joint account.', widget=widgets.RadioSelectHorizontal) r_entitledPartnerToSpendMine = models.IntegerField(choices=C.LIKERT_OPTS, label='I felt my partner was entitled to spend the money earned by me in the joint account.', widget=widgets.RadioSelectHorizontal) r_upsetWithPartner = models.IntegerField(choices=C.LIKERT_OPTS, label='I would be upset with my partner if they spent a large portion of the money from the joint account in this study on an item only they would use.', widget=widgets.RadioSelectHorizontal) r_expectPartnerGuilt = models.IntegerField(choices=C.LIKERT_OPTS, label='I would expect my partner to feel guilty if they spent a large portion of the money from the joint account in this study on an item only they would use.', widget=widgets.RadioSelectHorizontal) r_importance = models.IntegerField(choices=C.LIKERT_OPTS, label='My relationship with my partner is very important to me.', widget=widgets.RadioSelectHorizontal) r_uncomfortable = models.IntegerField(choices=C.LIKERT_OPTS, label='I feel very uncomfortable when my partner is upset with me.', widget=widgets.RadioSelectHorizontal) r_liveTogether = models.BooleanField(choices=[[True, 'Yes'], [False, 'No']], label='Do you live with your partner?', widget=widgets.RadioSelect) r_maritalStatus = models.StringField(choices=[['0', 'Relationship with Partner'], ['1', 'Married']], label='What is your current relationship status?', widget=widgets.RadioSelect) r_relationshipLength = models.StringField(choices=[['1', 'Less than 6 months'], ['2', '6 months to 1 year'], ['3', '1 to 2 years'], ['4', '3 to 5 years'], ['5', '6 to 10 years'], ['6', '11 to 20 years'], ['7', 'More than 20 years']], label='How long have you been in a relationship with your partner? (Please round to the nearest full year. For example, 2.3 years = "1 to 2 years")', widget=widgets.RadioSelect) r_relationshipLast = models.StringField(choices=[['1', 'A few months at most'], ['2', 'Around a year'], ['3', 'Several years'], ['4', 'A lifetime']], label='How long do you believe your relationship with your partner will last?', widget=widgets.RadioSelect) r_householdAdults = models.IntegerField(label='How many adults (age 18 or older) are in your household (including you)?', min=0) r_householdChildren = models.IntegerField(label='How many children (under age 18) are in your household?', min=0) r_happy = models.StringField(choices=[['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', '']], label='How happy are you in your relationship?', widget=widgets.RadioSelectHorizontal) TWST_1 = models.StringField(choices=[['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11']], label='Which of the following descriptions fits you better?', widget=widgets.RadioSelectHorizontal) TWST_2a = models.StringField(choices=[['1', 'Never'], ['2', 'Rarely'], ['3', 'Sometimes'], ['4', 'Often'], ['5', 'Always']], label='How well does the the first description fit you? That is, do you have trouble limiting your spending?', widget=widgets.RadioSelectHorizontal) TWST_2b = models.StringField(choices=[['1', 'Never'], ['2', 'Rarely'], ['3', 'Sometimes'], ['4', 'Often'], ['5', 'Always']], label='How well does the the second description fit you? That is, do you have trouble spending money?', widget=widgets.RadioSelectHorizontal) TWST_3 = models.StringField(choices=[['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5']], label='In terms of your own behavior, who are you more similar to, Mr. A or Mr. B?', widget=widgets.RadioSelectHorizontal) f_householdIncome = models.StringField(choices=[['1', 'Under $25,000'], ['2', 'Between $25,001 and $50,000'], ['3', 'Between $50,001 and $75,000'], ['4', 'Between $75,001 and $100,000'], ['5', 'Between $100,001 and $125,000'], ['6', 'Between $125,001 and $150,000'], ['7', 'Between $150,001 and $175,000'], ['8', 'Between $175,001 and $200,000'], ['9', 'More than $200,001']], label="What is your household's combined, pre-tax, annual income (including bonuses and commissions) last year in U.S. dollars?", widget=widgets.RadioSelect) gender = models.StringField(choices=[['0', 'Male'], ['1', 'Female'], ['2', 'Other']], label='What is your gender?', widget=widgets.RadioSelect) gender_other = models.StringField(label='"You selected \'Other\' as your gender. Please describe your gender identity:"') age = models.IntegerField(label='What is your age? Please enter your answer as a number', max=99, min=18) student = models.StringField(choices=[['1', 'Yes'], ['0', 'No']], label='Are you a college student?', widget=widgets.RadioSelect) education = models.StringField(choices=[['1', 'Some high school or less'], ['2', 'High school diploma or GED'], ['3', 'Some college, but no degree'], ['4', 'Associates or technical degree'], ['5', "Bachelor's degree"], ['6', 'Graduate or professional degree (MA, MS, MBA, PhD, JD, MD, DDS etc.)']], label='What is the highest level of education you have completed?', widget=widgets.RadioSelect) def custom_export(players): # Header yield [ 'session_code', 'participant_id_in_session', 'participant_code', 'id_in_group', 'group_number', 'spender', 'earner_1', # noticed error (not correct variable), keeping for consistency in custom exports 'earner_2', # noticed error (not correct variable), keeping for consistency in custom exports # Relationship Qs 'r_entiltedMe', 'r_entiltedPartner', 'r_upsetPartner', 'r_guilty', # Spender likert Qs 'r_entitledPartnerToSpendTheirs', 'r_entitledPartnerToSpendMine', 'r_upsetWithPartner', 'r_expectPartnerGuilt', # Nonspender likert Qs 'r_importance', 'r_uncomfortable', 'r_liveTogether', 'r_maritalStatus', 'r_relationshipLength', 'r_relationshipLast', 'r_householdAdults', 'r_householdChildren', 'r_happy', # TWST Qs 'TWST_1', 'TWST_2a', 'TWST_2b', 'TWST_3', # General Demographis Qs 'gender', 'age', 'student', 'education', 'householdIncome' ] # Rows for p in players: pp = p.participant pg = p.group ps = p.session # Pull participant fields spender = p.participant.vars.get('spender', '') earner_round_1 = p.participant.vars.get('earner_round_1', '') earner_round_2 = p.participant.vars.get('earner_round_2', '') yield [ ps.code, pp.id_in_session, pp.code, p.id_in_group, pg.id_in_subsession, spender, earner_1, # noticed error (not correct variable), keeping for consistency in custom exports earner2, # noticed error (not correct variable), keeping for consistency in custom exports p.r_entiltedMe, p.r_entiltedPartner, p.r_upsetPartner, p.r_guilty, p.r_entitledPartnerToSpendTheirs, p.r_entitledPartnerToSpendMine, p.r_upsetWithPartner, p.r_expectPartnerGuilt, p.r_importance, p.r_uncomfortable, p.r_liveTogether, p.r_maritalStatus, p.r_relationshipLength, p.r_relationshipLast, p.r_householdAdults, p.r_householdChildren, p.r_happy, p.TWST_1, p.TWST_2a, p.TWST_2b, p.TWST_3, p.gender, p.age, p.student, p.education, p.f_householdIncome ] class GroupingWaitPage(WaitPage): wait_for_all_groups = True after_all_players_arrive = after_all_players_arrive class Relationship_Qs_Spender(Page): form_model = 'player' form_fields = ['r_entiltedMe', 'r_entiltedPartner', 'r_upsetPartner', 'r_guilty', 'r_importance', 'r_uncomfortable', 'r_liveTogether', 'r_maritalStatus', 'r_relationshipLength', 'r_relationshipLast', 'r_householdAdults', 'r_householdChildren', 'r_happy'] @staticmethod def is_displayed(player: Player): participant = player.participant # Display if participant is the spender if player.participant.spender == 1: return True # vars_for_template is deprecated in favor of python-based renderers @staticmethod def vars_for_template(player: Player): # List of fields to include in the Likert scale table likert_fields_spender = ['r_entiltedMe','r_entiltedPartner', 'r_upsetPartner','r_guilty','r_importance','r_uncomfortable'] # List of fields for the happiness Likert scale happiness_fields = ['r_happy'] # Passing Python variables to the HTML template of the page return { 'img_url': 'https://imgur.com/N7q1Rts.png', 'likert_fields_spender': likert_fields_spender, 'happiness_fields': happiness_fields } class Relationship_Qs_Nonspender(Page): form_model = 'player' form_fields = ['r_entitledPartnerToSpendTheirs', 'r_entitledPartnerToSpendMine', 'r_upsetWithPartner', 'r_expectPartnerGuilt', 'r_importance', 'r_uncomfortable', 'r_liveTogether', 'r_maritalStatus', 'r_relationshipLength', 'r_relationshipLast', 'r_householdAdults', 'r_householdChildren', 'r_happy'] @staticmethod def is_displayed(player: Player): participant = player.participant # Display if participant is the spender if player.participant.spender != 1: return True # vars_for_template is deprecated in favor of python-based renderers @staticmethod def vars_for_template(player: Player): # List of fields to include in the Likert scale table likert_fields_nonspender = ['r_entitledPartnerToSpendMine','r_entitledPartnerToSpendTheirs', 'r_upsetWithPartner','r_expectPartnerGuilt','r_importance','r_uncomfortable'] # List of fields for the happiness Likert scale happiness_fields = ['r_happy'] # Passing Python variables to the HTML template of the page return { 'img_url': 'https://imgur.com/N7q1Rts.png', 'likert_fields_nonspender': likert_fields_nonspender, 'happiness_fields': happiness_fields } class TWST_Questions(Page): form_model = 'player' form_fields = ['TWST_1', 'TWST_2a', 'TWST_2b', 'TWST_3'] class Demo_Questions(Page): form_model = 'player' form_fields = ['gender', 'age', 'student', 'education', 'f_householdIncome'] class SurveyEndPage(WaitPage): wait_for_all_groups = True page_sequence = [GroupingWaitPage, Relationship_Qs_Spender, Relationship_Qs_Nonspender, TWST_Questions, Demo_Questions, SurveyEndPage]