""" models.py — oTree data models. num_rounds = 1. All situation looping is handled by JavaScript within each page. """ import json import random from otree.api import BaseConstants, BaseSubsession, BaseGroup, BasePlayer, models, widgets # --------------------------------------------------------------------------- # Constants # --------------------------------------------------------------------------- class Constants(BaseConstants): name_in_url = 'main_early' players_per_group = None num_rounds = 1 # --------------------------------------------------------------------------- # Subsession # --------------------------------------------------------------------------- class Subsession(BaseSubsession): pass # --------------------------------------------------------------------------- # Group # --------------------------------------------------------------------------- class Group(BaseGroup): pass # --------------------------------------------------------------------------- # Player # --------------------------------------------------------------------------- class Player(BasePlayer): # ------------------------------------------------------------------ # Consent # ------------------------------------------------------------------ consent = models.StringField( choices=[['consent', 'I consent'], ['not_consent', 'I do not consent']], widget=widgets.RadioSelect, label='Please indicate your decision:', ) #treatment treatment = models.StringField(blank=True) # ------------------------------------------------------------------ # General comprehension questions # ------------------------------------------------------------------ gen_q1_errors = models.IntegerField(initial=0) gen_q1 = models.StringField(choices=[['a',''],['b',''],['c','']], widget=widgets.RadioSelect, label='', blank=True) # ------------------------------------------------------------------ # Task ordering # ------------------------------------------------------------------ task_order = models.StringField(blank=True) # ------------------------------------------------------------------ # Comprehension questions # ------------------------------------------------------------------ # DN task comprehension dn_q1 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) dn_q1_errors = models.IntegerField(initial=0) dict_q1 = models.StringField(choices=[['a',''],['b',''],['c','']], widget=widgets.RadioSelect, label='', blank=True) dict_q2 = models.StringField(choices=[['a',''],['b',''],['c','']], widget=widgets.RadioSelect, label='', blank=True) dict_q3 = models.StringField(choices=[['a',''],['b',''],['c','']], widget=widgets.RadioSelect, label='', blank=True) dict_q1_errors = models.IntegerField(initial=0) dict_q2_errors = models.IntegerField(initial=0) dict_q3_errors = models.IntegerField(initial=0) risk_q1 = models.StringField(choices=[['a',''],['b',''],['c','']], widget=widgets.RadioSelect, label='', blank=True) risk_q2 = models.StringField(choices=[['a',''],['b',''],['c','']], widget=widgets.RadioSelect, label='', blank=True) risk_q1_errors = models.IntegerField(initial=0) risk_q2_errors = models.IntegerField(initial=0) # Preference instructions comprehension pref_q1 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) pref_q1_errors = models.IntegerField(initial=0) # Thresholdd instructions comprehension threshold_q1 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) threshold_q2 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) threshold_q3 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) threshold_q4 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) threshold_q1_errors = models.IntegerField(initial=0) threshold_q2_errors = models.IntegerField(initial=0) threshold_q3_errors = models.IntegerField(initial=0) threshold_q4_errors = models.IntegerField(initial=0) # Additional Decisions (DN info task) instructions comprehension additional_decisions_q1 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) additional_decisions_q2 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) additional_decisions_q1_errors = models.IntegerField(initial=0) additional_decisions_q2_errors = models.IntegerField(initial=0) #Appropriateness task # appr_q1 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) appr_q1_errors = models.IntegerField(initial=0) appr_q2 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) appr_q2_errors = models.IntegerField(initial=0) # Appropriateness task — temporary per-submission fields app_decisions_data = models.LongStringField(blank=True) # Storage fields dg_app_ratings = models.LongStringField(initial='{}') lt_app_ratings = models.LongStringField(initial='{}') dg_app_lr = models.LongStringField(initial='{}') lt_app_lr = models.LongStringField(initial='{}') # ------------------------------------------------------------------ # Preference ratings # ------------------------------------------------------------------ pref_decisions_data = models.LongStringField(blank=True) # Preference task — all ratings stored as a JSON dict # Format: {"s_DG1": 3, "s_DG2": -5, "s_LT1": 7, ...} dg_preference_ratings = models.LongStringField(initial='{}') lt_preference_ratings = models.LongStringField(initial='{}') # Left/right option assignment per situation (for debugging) # Format: {situation_id: {"left": option_id, "right": option_id}} dg_preference_lr = models.LongStringField(initial='{}') lt_preference_lr = models.LongStringField(initial='{}') # Rule following task # instructions comprehension rule_following_q1 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) rule_following_q2 = models.StringField(choices=[['a', ''], ['b', ''], ['c', '']], widget=widgets.RadioSelect, label='', blank=True) rule_following_q1_errors = models.IntegerField(initial=0) rule_following_q2_errors = models.IntegerField(initial=0) rf_yellow = models.IntegerField(initial=0) rf_blue = models.IntegerField(initial=0) rule_following_task_division = models.LongStringField(blank=True) # ------------------------------------------------------------------ # Threshold task decisions (JSON blobs, one per task type) # ------------------------------------------------------------------ threshold_decisions_data = models.LongStringField(blank=True) # temporary submission field situation_order_data = models.LongStringField(blank=True) # temporary submission field dg_threshold_decisions = models.LongStringField(initial='{}') lt_threshold_decisions = models.LongStringField(initial='{}') dg_threshold_lr = models.LongStringField(initial='{}') lt_threshold_lr = models.LongStringField(initial='{}') # ------------------------------------------------------------------ # Norm task — per-submission temporary fields # ------------------------------------------------------------------ # Norm task — temporary submission field norm_decisions_data = models.LongStringField(blank=True) # Norm task — storage dg_norm_decisions = models.LongStringField(initial='{}') lt_norm_decisions = models.LongStringField(initial='{}') dg_norm_lr = models.LongStringField(initial='{}') lt_norm_lr = models.LongStringField(initial='{}') # ------------------------------------------------------------------ # Payoff details # ------------------------------------------------------------------ selected_task = models.StringField(blank=True) selected_pair_index = models.IntegerField(blank=True) selected_option_chosen = models.StringField(blank=True) other_payoff = models.FloatField(blank=True) risk_outcome_realised = models.FloatField(initial=0) payoff_explanation = models.LongStringField(initial='{}') total_payment_eur = models.FloatField(blank=True) # ------------------------------------------------------------------ # Inclusion of Other in Self (IOS Scale, Aron et al., 1992) # 1-7 Venn diagram overlap (1=no overlap, 7=near-complete overlap) # ------------------------------------------------------------------ ios_scale = models.IntegerField(blank=True) # ------------------------------------------------------------------ # Social Norm Espousal Scale (SNES; Bizer et al., 2014) # 14 items, 1-7; items 2,3,8,12,13 are reverse-coded # ------------------------------------------------------------------ snes_q1 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q2 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q3 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q4 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q5 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q6 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q7 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q8 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q9 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q10 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q11 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q12 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q13 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") snes_q14 = models.IntegerField(choices=[[i, str(i)] for i in range(1, 8)], widget=widgets.RadioSelectHorizontal, label="") SUP_data = models.LongStringField(blank=True) # ------------------------------------------------------------------ # Ex post questionnaire # ------------------------------------------------------------------ q_instructions_unclear = models.LongStringField(blank=True) q_comments = models.LongStringField(blank=True) q_understood_general = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_lottery = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_allocation = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_preference_task = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_threshold_task = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_norm_task = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_appropriateness_task = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_understood_urns_task = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) q_effort = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) cognitive_uncertainty_dictator = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) cognitive_uncertainty_risk = models.IntegerField(choices=[[i,str(i)] for i in range(0,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) demo_age = models.IntegerField(blank=True, label="") demo_gender = models.StringField( choices=[["woman","Woman"],["man","Man"],["nonbinary","Non-binary / third gender"], ["self_describe","Prefer to self-describe"],["no_answer","Prefer not to say"]], widget=widgets.RadioSelect, label="", blank=True) demo_gender_self = models.StringField(blank=True, label="") demo_education = models.StringField( choices=[["none","No formal qualifications"],["primary","Primary school"], ["secondary","Secondary school (i.e., High school or equivalent)"], ["vocational","Vocational / technical qualification"], ["bachelor","Bachelor degree or equivalent"], ["postgrad","Postgraduate degree (Masters, PhD, or equivalent)"], ["no_answer","Prefer not to say"]], widget=widgets.RadioSelect, label="", blank=True) demo_ses = models.IntegerField(choices=[[i,str(i)] for i in range(1,11)], widget=widgets.RadioSelectHorizontal, label="", blank=True) contrarian = models.StringField( choices=[['yes', 'Yes'], ['no', 'No']], widget=widgets.RadioSelect, label='', blank=True, ) page_timestamps = models.LongStringField(initial='{}') def record_timestamp(self, page_name, start=None, end=None): ts = json.loads(self.page_timestamps) if page_name not in ts: ts[page_name] = {} if start is not None: ts[page_name]['start'] = start if end is not None: ts[page_name]['end'] = end s = ts[page_name].get('start') if s is not None: ts[page_name]['duration'] = end - s self.page_timestamps = json.dumps(ts)