from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import csv import random import math import datetime import time import django.utils.timezone author = 'Your name here' doc = """ Studie des Teilprojektes »Maße der Bedarfsgerechtigkeit, Expertise und Kohärenz« """ class Constants(BaseConstants): name_in_url = 'typesofneed' players_per_group = None num_rounds = 1 with open('typesofneed/productivity.csv') as f: questions_productivity = list(csv.DictReader(f)) NUMBER_OF_PRODUCTIVITY_QUESTIONS = len(questions_productivity) with open('typesofneed/need.csv') as g: questions_need = list(csv.DictReader(g)) NUMBER_OF_NEED_QUESTIONS = len(questions_need) # with open('responsibility/BSJO.csv') as f: # BSJO = list(csv.DictReader(f)) TIMEOUT_SECONDS = 60 * 60 * 2 Checker = ['Winter', 'Haus', 'Trinken', 'Muehle', 'Weizen', 'Roggen', 'Sonnenblumen'] Scheite = [3000, 44, 770, 70777, 55, 55505, 9999] BSJO = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'] BSJO_short = ['B', 'C', 'D', 'E', 'I', 'J', 'K', 'L'] class Subsession(BaseSubsession): def creating_session(self): person_names = ['Müller', 'Schmidt', 'Schneider', 'Fischer', 'Weber', 'Meyer'] if self.session.config['switch_after_every_question']: person_names.extend(['Wagner', 'Becker', 'Schulz', 'Hoffmann', 'Schäfer', 'Koch', 'Bauer', 'Richter', 'Klein', 'Wolf', 'Schröder', 'Schneider', 'Neumann', 'Schwarz', 'Zimmermann' ]) players = self.get_players() is_respondi_study = self.session.config.get("is_respondi_study", False) if not is_respondi_study: treatment_list = [] if self.session.config['include_treatment_1']: treatment_list.append(1) if self.session.config['include_treatment_2']: treatment_list.append(2) if self.session.config['include_treatment_3']: treatment_list.append(3) if self.session.config['include_treatment_4']: treatment_list.append(4) if len(treatment_list) == 0: treatment_list.append(1) treatment_list.append(2) treatment_list.append(3) treatment_list.append(4) num_randomization_treatment = int(math.ceil(len(players) / len(treatment_list))) random_treatment_numbers = [] for x in range(0, num_randomization_treatment): random.shuffle(treatment_list) random_treatment_numbers.extend(treatment_list) for p in players: p.treatment_number = random_treatment_numbers.pop() for p in players: p.block_order = random.randint(1, 2) p.reversed_order_need_productivity = random.random() < 0.5 p.reversed_order_persons = random.random() < 0.5 p.participant.vars['persons'] = p.randomize_list(person_names) p.participant.vars['old_person_a'] = p.participant.vars['persons'][0] p.participant.vars['old_person_b'] = p.participant.vars['persons'][1] p.participant.vars['current_question_id'] = 0 p.participant.vars['questions_need'] = p.randomize_list(Constants.questions_need) p.participant.vars['questions_productivity'] = p.randomize_list(Constants.questions_productivity) p.participant.vars['Checker'] = p.randomize_list(Constants.Checker) p.participant.vars['Scheite'] = p.randomize_list(Constants.Scheite) if self.session.config['full_BSJO']: p.participant.vars['BSJO'] = p.randomize_list(Constants.BSJO) else: p.participant.vars['BSJO'] = p.randomize_list(Constants.BSJO_short) for x in p.participant.vars['questions_need']: p.sequence_need_vignette += str(x["situation_id"]) + " " for x in p.participant.vars['questions_productivity']: p.sequence_productivity_vignette += str(x["situation_id"]) + " " question_data = p.get_current_question() p.participant.vars['old_need_A'] = question_data['need_A'] p.participant.vars['old_need_B'] = question_data['need_B'] p.participant.vars['old_chopped_A'] = question_data['chopped_A'] p.participant.vars['old_chopped_B'] = question_data['chopped_B'] p.participant.vars['old_endowment'] = question_data['total_endowment'] class Group(BaseGroup): pass class Player(BasePlayer): treatment_number = models.PositiveIntegerField() block_order = models.IntegerField() def randomize_list(self, list): return random.sample(list, len(list)) def get_first_block(self): if self.block_order == 1: return self.participant.vars['questions_productivity'] else: return self.participant.vars['questions_need'] def get_first_block_length(self): return len(self.get_first_block()) def get_second_block(self): if self.block_order == 2: return self.participant.vars['questions_productivity'] else: return self.participant.vars['questions_need'] def is_currently_productivity(self): question_number = self.participant.vars['current_question_id'] length_of_block_one = len(self.get_first_block()) if self.block_order == 1 and question_number < length_of_block_one: return True elif self.block_order == 2 and question_number >= length_of_block_one: return True else: return False def is_currently_need(self): return (self.need_first() and self.is_block_one()) or (self.productivitiy_first() and not self.is_block_one()) def need_first(self): return self.block_order == 2 def productivitiy_first(self): return self.block_order == 1 def is_block_one(self): question_number = self.participant.vars['current_question_id'] length_of_block_one = len(self.get_first_block()) return question_number < length_of_block_one def get_length_of_second_block(self): return len(self.get_second_block()) def get_current_question(self): question_number = self.participant.vars['current_question_id'] length_of_block_one = len(self.get_first_block()) if (question_number < length_of_block_one): return self.get_first_block()[question_number] else: return self.get_second_block()[question_number - length_of_block_one] def get_current_question_name(self): question = self.get_current_question() if self.is_currently_productivity(): return "productivity_" + str(question['situation_id']) else: return "need_" + str(question['situation_id']) def has_new_names(self): current_question_id = self.participant.vars['current_question_id'] if current_question_id != 0 and self.session.config['switch_after_every_question']: return True elif self.session.config['switch_after_first_block']: return current_question_id == self.get_first_block_length() else: return False def is_new_block(self): return self.participant.vars['current_question_id'] == self.get_first_block_length() quality_fail = models.BooleanField(initial=False) dropout = models.BooleanField(initial=False) def get_timeout_seconds(self): timeout_seconds = self.session.config.get("timeout_hours", 2) * 60 * 60 return timeout_seconds def set_quality_fail(self): self.quality_fail = True self.remove_from_quota() def check_checkers(self): quality_fail = not self.CheckerWinter quality_fail |= self.CheckerHaus quality_fail |= self.CheckerTrinken quality_fail |= self.CheckerMuehle quality_fail |= self.CheckerWeizen quality_fail |= self.CheckerRoggen quality_fail |= self.CheckerSonnenblumen return quality_fail def check_scheite(self): quality_fail = not self.Scheite3000 quality_fail |= self.Scheite44 quality_fail |= self.Scheite770 quality_fail |= self.Scheite70777 quality_fail |= self.Scheite55 quality_fail |= self.Scheite55505 quality_fail |= self.Scheite9999 return quality_fail def is_displayed_respondi(self): if self.session.config.get("is_respondi_study", False): return not self.dropout and not self.quality_fail else: return not self.dropout @staticmethod def check_in_range(lower_border, value, upper_border): return lower_border <= value <= upper_border def remove_from_quota(self): if not self.session.config.get("is_respondi_study", False): return self.decrement_quotas() def decrement_quotas(self): treatment = self.treatment_number gender = self.gender age = self.age net_equivalence_income = self.net_equivalence_income if self.check_in_range(18, age, 29): self.decrement_quota('quota_age_18_to_29', treatment) elif self.check_in_range(30, age, 39): self.decrement_quota('quota_age_30_to_39', treatment) elif self.check_in_range(40, age, 49): self.decrement_quota('quota_age_40_to_49', treatment) elif self.check_in_range(50, age, 59): self.decrement_quota('quota_age_50_to_59', treatment) elif self.check_in_range(60, age, 69): self.decrement_quota('quota_age_60_to_69', treatment) if gender == 0: self.decrement_quota('quota_female', treatment) elif gender == 1: self.decrement_quota('quota_male', treatment) elif gender == 2: self.decrement_quota('quota_diverse', treatment) if self.check_in_range(0, net_equivalence_income, 1100): self.decrement_quota('quota_income_less_than_1100', treatment) elif self.check_in_range(1100, net_equivalence_income, 1500): self.decrement_quota('quota_income_1100_to_1500', treatment) elif self.check_in_range(1500, net_equivalence_income, 2000): self.decrement_quota('quota_income_1500_to_2000', treatment) elif self.check_in_range(2000, net_equivalence_income, 2600): self.decrement_quota('quota_income_2000_to_2600', treatment) elif self.check_in_range(2600, net_equivalence_income, math.inf): self.decrement_quota('quota_income_more_than_2600', treatment) def decrement_quota(self, key, treatment): self.session.vars['actual_' + key + '_' + str(treatment)] -= 1 need_type_sickness = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Heizen, um nicht lebensbedrohlich krank zu werden") need_type_decency = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Heizen, um nicht zu frieren") need_type_participation = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Heizen für gemeinsames Beisammensein im Gemeindehaus") need_type_luxury = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Heizen zum Betreiben der eigenen Sauna") def get_own_type_of_need(self): if self.treatment_number == 1: return ['need_type_sickness'] elif self.treatment_number == 2: return ['need_type_decency'] elif self.treatment_number == 3: return ['need_type_participation'] else: return ['need_type_luxury'] def get_other_types_of_need(self): if self.treatment_number == 1: return_list = ['need_type_decency', 'need_type_participation', 'need_type_luxury'] elif self.treatment_number == 2: return_list = ['need_type_sickness', 'need_type_participation', 'need_type_luxury'] elif self.treatment_number == 3: return_list = ['need_type_decency', 'need_type_sickness', 'need_type_luxury'] else: return_list = ['need_type_decency', 'need_type_participation', 'need_type_sickness'] return self.randomize_list(return_list) # Seite 3-10 (Vignettes) for i in range(1, Constants.NUMBER_OF_PRODUCTIVITY_QUESTIONS + 1, 1): locals()["justice_productivity_" + str(i) + "_A"] = models.PositiveIntegerField() locals()["justice_productivity_" + str(i) + "_B"] = models.PositiveIntegerField() del i for i in range(1, Constants.NUMBER_OF_NEED_QUESTIONS + 1, 1): locals()["justice_need_" + str(i) + "_A"] = models.PositiveIntegerField( doc="Endowment: " + str(Constants.questions_need[i - 1]["need_A"])) locals()["justice_need_" + str(i) + "_B"] = models.PositiveIntegerField() del i # Seite 11 (Fragen zur Studie: Kriterien Entscheidung) kriterien = models.LongStringField(max_length=1000, # blank=True, doc="Criteria relevant for the participants' decision", widget=widgets.Textarea(attrs={'style': 'width: 30em;'})) # Page 11a (Likert scale on decision criteria) criteria_likert_need = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8), label="Jede Person sollte so viel Holz bekommen, wie sie braucht.", doc="Likert scale (1-7) on the importance of need for the " "participants' decision") criteria_likert_productivity = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8), label="Jede Person sollte das Holz bekommen, das sie geschlagen hat.") criteria_likert_equality = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8), label="Jede Person sollte gleich viel Holz bekommen.") # Seite 12 (Kontrollfrage) checker_gerechtigkeit = models.LongStringField( # blank=True, widget=widgets.Textarea) # Seite 13 (Kontrollfrage) CheckerWinter = models.BooleanField(widget=widgets.CheckboxInput()) CheckerHaus = models.BooleanField(widget=widgets.CheckboxInput()) CheckerTrinken = models.BooleanField(widget=widgets.CheckboxInput()) CheckerMuehle = models.BooleanField(widget=widgets.CheckboxInput()) CheckerWeizen = models.BooleanField(widget=widgets.CheckboxInput()) CheckerRoggen = models.BooleanField(widget=widgets.CheckboxInput()) CheckerSonnenblumen = models.BooleanField(widget=widgets.CheckboxInput()) # Seite 14 (Kontrollfrage) Scheite3000 = models.BooleanField(widget=widgets.CheckboxInput()) Scheite44 = models.BooleanField(widget=widgets.CheckboxInput()) Scheite770 = models.BooleanField(widget=widgets.CheckboxInput()) Scheite70777 = models.BooleanField(widget=widgets.CheckboxInput()) Scheite55 = models.BooleanField(widget=widgets.CheckboxInput()) Scheite55505 = models.BooleanField(widget=widgets.CheckboxInput()) Scheite9999 = models.BooleanField(widget=widgets.CheckboxInput()) # Seite 15 (Fragen zur Studie: Manipulationscheck) responsibilityNeed = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), ) responsibilityProductivity = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), ) # Seite 16 (Einstellungen: Locus of control) locusOfControl = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), ) # Seite 17 (Einstellungen zu Armut in Deutschland) attitudePoverty = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Wer in Deutschland arm ist, ist dies, weil sie/er...") attitudeSocialAssistance = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Wer in Deutschland auf Sozialhilfe (Hartz IV) angewiesen ist, ist dies, weil sie/er...") attitudeHomeless = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Wer in Deutschland auf der Straße lebt, tut dies, weil sie/er...") attitudeWorkingPoor = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Wer in Deutschland nicht genügend verdient, um seinen Lebensunterhalt zu sichern, ist in dieser Lage, weil sie/er...") # Seite 18 (Einstellungen zu Reichstum in Deutschland) attitudeWealth = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Wer in Deutschland reich ist, ist dies, weil sie/er...") attitudeMillionaires = models.PositiveIntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), label="Wer in Deutschland Millionär/in ist, ist dies, weil sie/er...") # Seite 19 (Einschätzung Arm/Reich) thresholdPoor = models.CurrencyField(min=0) thresholdWealthy = models.CurrencyField(min=0) # Seite 20 (Einstellung Grundsicherung) conditionalityOfBasicSecurity = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect) # ! # Seite 21 (Einstellung Gerechtigkeit) BSJO_A = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Eine Gesellschaft ist gerecht, wenn jede Person ausreichend Essen, Wohnraum, Kleidung sowie Zugang zu Bildung und medizinischer Versorgung hat.") BSJO_B = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn Personen, die hart arbeiten, mehr verdienen als andere.") BSJO_C = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn alle die gleichen Lebensbedingungen haben.") BSJO_D = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn Personen, die aus angesehenen Familien stammen, dadurch Vorteile im Leben haben.") BSJO_E = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Eine Gesellschaft ist gerecht, wenn sie sich um die Schwachen und Hilfsbedürftigen kümmert, unabhängig davon, was diese der Gesellschaft zurückgeben können.") BSJO_F = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn Personen, die es im Laufe ihres Lebens zu Ansehen und Wohlstand gebracht haben, auch im Alter davon profitieren.") BSJO_G = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Eine Gesellschaft ist gerecht, wenn die Einkommensunterschiede zwischen den Menschen gering sind.") BSJO_H = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Eine Gesellschaft ist gerecht, wenn Unterschiede in Einkommen und Vermögen die Leistungsunterschiede zwischen Menschen widerspiegeln.") BSJO_I = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn jede Person nur das bekommt, was sie sich durch eigene Anstrengungen erarbeitet hat.") BSJO_J = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn Personen, die Kinder oder pflegebedürftige Angehörige zu versorgen haben, besondere Unterstützung und Vergünstigungen erhalten.") BSJO_K = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn Einkommen und Vermögen in unserer Gesellschaft an alle Personen gleich verteilt werden.") BSJO_L = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect, label="Es ist gerecht, wenn diejenigen, die in einer Gesellschaft oben stehen, bessere Lebensbedingungen haben als diejenigen, die unten stehen.") # Seite 22 (Soziodemografische Fragen) gender = models.IntegerField(choices=[[0, 'weiblich'], [1, 'männlich'], [2, 'divers']], # blank = True, label='Mit welchem Geschlecht identifizieren Sie sich?') age = models.PositiveIntegerField(label='Wie alt sind Sie (in Jahren)?') familyStatus = models.IntegerField( label='Wie lautet Ihr Familienstand? Sollten Sie in einer Lebenspartnerschaft leben/gelebt haben, behandeln Sie diese bitte als Ehe', choices=[[1, 'ledig'], [2, 'verheiratet'], [3, 'geschieden'], [4, 'Ehe aufgehoben'], [5, 'verwitwet'], [6, 'anderes'], ], ) children = models.PositiveIntegerField(label='Wie viele Kinder haben Sie?') householdSize = models.PositiveIntegerField( label='Mit wie vielen anderen Personen leben Sie in einem Haushalt (wenn Sie alleine leben, geben Sie bitte 0 an)?') childrenInHousehold = models.PositiveIntegerField( label='Wie viele der Personen in Ihrem Haushalt sind Kinder unter 14 Jahren?') ownIncome = models.CurrencyField(label='Wie hoch ist Ihr eigenes Einkommen (netto, pro Monat)?') householdIncome = models.CurrencyField(label='Wie hoch ist das Einkommen Ihres Haushalts (netto, pro Monat)?') ownWealth = models.CurrencyField(label='Wie hoch ist Ihr eigenes Vermögen?') householdWealth = models.CurrencyField(label='Wie hoch ist das Vermögen Ihres Haushalts?') def get_net_equivalence_income(self): return (self.householdIncome / ( 1 + 0.5 * (self.householdSize - self.childrenInHousehold) + 0.3 * self.childrenInHousehold)) net_equivalence_income = models.CurrencyField() # Seite 23 (Politische Einstellung) politicalAttitude = models.IntegerField(widget=widgets.RadioSelect, choices=range(1, 8, 1), ) # Seite 24 (Welche Partei würden Sie wählen?) party = models.IntegerField(choices=[[1, 'CDU/CSU'], [2, 'SPD'], [3, 'GRÜNE'], [4, 'FDP'], [5, 'DIE LINKE'], [6, 'AfD'], [7, 'FREIE WÄHLER'], [8, 'Sonstige'], ], widget=widgets.RadioSelect(), label="Welche Partei würden Sie wählen, wenn morgen Bundestagswahl wäre?") partyOther = models.StringField(blank=True, label='Wenn Sie »Sonstige« ausgewählt haben: Bitte geben Sie den Namen der Partei an, die Sie wählen würden') # Seite 25 (Bildungsabschluss) degree = models.IntegerField(choices=[[1, 'ohne allgemeinen Schulabschluss'], [2, 'noch in schulischer Ausbildung'], [3, 'Haupt- oder Volksschulabschluss'], [4, 'Abschluss der polytechnischen Oberschule'], [5, 'Realschul- oder gleichwertiger Abschluss'], [6, 'Fachhochschul- oder Hochschulreife'], [7, 'Lehre/Berufsausbildung im dualen System'], [8, 'Fachschulabschluss'], [9, 'Fachhochschulabschluss'], [10, 'Hochschulabschluss'], [11, 'Bachelor'], [12, 'Master'], [13, 'Magister'], [14, 'Diplom'], [15, 'Promotion'], [16, 'Habilitation'], ], label="Welcher ist ihr höchster Bildungsabschluss?") # Seite 26 (Beruf) occupation = models.StringField(label="Bitte nennen Sie Ihre berufliche Tätigkeit") branch = models.StringField(label="Bitte nennen Sie den Bereich, in dem Sie tätig sind") ### Weitere Fragen (Faukes Mail vom 5.3.2019) is_smoker = models.BooleanField( label="Rauchen Sie gegenwärtig, zum Beispiel (E-)Zigaretten, Pfeifen oder Zigarren?", widget=widgets.RadioSelect) # wenn ja, wie viele Zigaretten, Pfeifen oder Zigarren rauchen Sie pro Tag (geben Sie bitte ungefähr den täglichen Durchschnitt der letzten Woche an)? cigarettes_per_day = models.PositiveIntegerField(max=100, label="Zigaretten pro Tag") pipes_per_day = models.PositiveIntegerField(max=100, label="Pfeifen pro Tag") cigars_per_day = models.PositiveIntegerField(max=100, label="Zigarren/Zigarillos pro Tag") e_cigarettes_per_day = models.FloatField(min=0, label="Milliliter E-Liquid pro Tag") has_cardiovascular_disease = models.BooleanField( label="Leiden Sie zur Zeit an einer Herz-Kreislaufkrankheit oder haben Sie früher an einer Herz-Kreislaufkrankheit gelitten?", widget=widgets.RadioSelect) has_metabolic_disease = models.BooleanField( label="Leiden Sie zur Zeit an einer Stoffwechselkrankheit oder haben Sie früher an einer Stoffwechselkrankheit gelitten?", widget=widgets.RadioSelect) risk_taking = models.PositiveIntegerField(choices=range(1, 8, 1), widget=widgets.RadioSelect) sequence_need_vignette = models.StringField(initial="") sequence_productivity_vignette = models.StringField(initial="") reversed_order_need_productivity = models.BooleanField() reversed_order_persons = models.BooleanField() device = models.IntegerField(label="Auf welcher Art von Gerät bearbeiten Sie diese Studie?", choices=[ [1, 'Computer/Laptop'], [2, 'Tablet'], [3, 'Smartphone'], [4, 'Anderes'], ])