Example #1
0
class Group(BaseGroup):
    two_third_guesses = models.FloatField()
    best_guess = models.FloatField()
    tie = models.BooleanField(initial=False)

    def set_payoffs(self):
        players = self.get_players()
        self.two_third_guesses = ((2 / 3) * sum(p.guess_value
                                                for p in players) /
                                  len(players))

        candidates = []
        smallest_difference_so_far = Constants.guess_max + 1  # initialize to largest possible difference
        tie = False
        for p in self.get_players():
            p.payoff = 0
            p.is_winner = False  # initialize to false
            difference = abs(p.guess_value - self.two_third_guesses)
            if difference < smallest_difference_so_far:
                tie = False
                candidates = [p]
                smallest_difference_so_far = difference
            elif difference == smallest_difference_so_far:
                tie = True
                candidates.append(p)

        self.tie = tie
        winners = candidates
        winners_cnt = len(winners)
        for p in winners:
            p.is_winner = True
            p.payoff = (Constants.winner_payoff /
                        winners_cnt if tie else Constants.winner_payoff)

        self.best_guess = winners[0].guess_value
Example #2
0
class Subsession(otree.models.BaseSubsession):

    name_in_url = 'exp1'

    min_value = models.FloatField(
        default=None,
        choices=CHOICES,
        doc="minimum of all decisions")

    def minimum(self):
        self.min_value = min([p.decision for p in self.get_players()])

    def set_payoffs(self):
        print 'self.min_value', self.min_value
        for p in self.get_players():
            print 'p.decision', p.decision
            assert p.decision is not None
            assert self.min_value is not None

            p.payoff = self.a + self.b * self.min_value - self.c * p.decision


    a = models.FloatField(default=200.0,doc="a+b*(minimum of all)-c*(own choice)")

    b = models.FloatField(default=400.0,doc="a+b*(minimum of all)-c*(own choice)")

    c = models.FloatField(default=200.0,doc="a+b*(minimum of all)-c*(own choice)")
Example #3
0
class Player(BasePlayer):

    # form showing whether a player approves government's reforms
    approval_choices = ((1, "Одобряю"),(0, "Не одобряю"))
    approval = models.FloatField(widget=widgets.RadioSelect, choices=approval_choices)
    approval_final = models.FloatField(widget=widgets.RadioSelect, choices=approval_choices)

    # form showing how much a player is spending on trying to overthrow the system
    vote_to_overthrow = models.FloatField(widget=widgets.SliderInput(attrs={'step': '1'}), min=0, max=Constants.max_overthrow_vote_for_player, default=3)

    # form showing how much reforms a player desires after the overthrow
    reforms_votes = models.FloatField(widget=widgets.SliderInput(attrs={'step': '1'}), min=0, max=Constants.max_reforms, default=3)
Example #4
0
class Treatment(otree.models.BaseTreatment):
    # <built-in>
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    a = models.FloatField(default=200.0,
                          doc="a+b*(minimum of all)-c*(own choice)")

    b = models.FloatField(default=400.0,
                          doc="a+b*(minimum of all)-c*(own choice)")

    c = models.FloatField(default=200.0,
                          doc="a+b*(minimum of all)-c*(own choice)")
Example #5
0
class Group(otree.models.BaseGroup):

    # <built-in>
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    players_per_group = 5

    two_third_guesses = models.FloatField()

    def set_payoffs(self):
        self.two_third_guesses = (2 / 3) * sum(
            [p.guess_value
             for p in self.get_players()]) / len(self.get_players())

        winner_so_far = None
        smallest_difference_so_far = 1000  # arbitrary big number

        for p in self.get_players():
            difference = abs(p.guess_value - self.two_third_guesses)
            if difference < smallest_difference_so_far:
                winner_so_far = p
                smallest_difference_so_far = difference
        winner_so_far.is_winner = True

        for p in self.get_players():
            if p.is_winner:
                p.payoff = Constants.winner_payoff
            else:
                p.payoff = 0
Example #6
0
class Group(otree.models.BaseGroup):

    # <built-in>
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    total_return = models.CurrencyField(
        doc="""Total return from agent's effort = [Return for single unit of
            agent's work effort] * [Agent's work effort]""")

    agent_fixed_pay = models.CurrencyField(
        doc="""Amount offered as fixed pay to agent""",
        min=Constants.min_fixed_payment,
        max=Constants.max_fixed_payment,
        verbose_name='Fixed Payment (from %i to %i)' %
        (Constants.min_fixed_payment, Constants.max_fixed_payment))

    agent_return_share = models.FloatField(
        choices=Constants.agent_return_share_choices,
        doc="""Agent's share of total return""",
        verbose_name='Return Share',
        widget=widgets.RadioSelectHorizontal())

    agent_work_effort = models.PositiveIntegerField(
        choices=range(1, 10 + 1),
        doc="""Agent's work effort, [1, 10]""",
        widget=widgets.RadioSelectHorizontal(),
    )

    agent_work_cost = models.CurrencyField(
        doc="""Agent's cost of work effort""")

    contract_accepted = models.BooleanField(
        doc="""Whether agent accepts proposal""",
        widget=widgets.RadioSelect(),
        choices=(
            (True, 'Accept'),
            (False, 'Reject'),
        ))

    def set_payoffs(self):
        principal = self.get_player_by_role('principal')
        agent = self.get_player_by_role('agent')

        if not self.contract_accepted:
            principal.payoff = Constants.reject_principal_pay
            agent.payoff = Constants.reject_agent_pay
        else:
            self.agent_work_cost = cost_from_effort(self.agent_work_effort)
            self.total_return = return_from_effort(self.agent_work_effort)

            money_to_agent = self.agent_return_share * \
                self.total_return + self.agent_fixed_pay
            agent.payoff = money_to_agent - self.agent_work_cost
            principal.payoff = self.total_return - money_to_agent
        principal.payoff += Constants.bonus
        agent.payoff += Constants.bonus

    def return_share_as_percentage(self):
        return utils.float_as_percentage(self.agent_return_share)
Example #7
0
class FormFieldModel(otree.models.BaseGroup):
    null_boolean = models.BooleanField()
    big_integer = models.BigIntegerField()
    boolean = models.BooleanField(default=False)
    char = models.CharField()
    comma_separated_integer = models.CommaSeparatedIntegerField(max_length=100)
    date = models.DateField()
    date_time = models.DateTimeField()
    alt_date_time = models.DateTimeField(
        widget=otree.forms.SplitDateTimeWidget)
    decimal = models.DecimalField(max_digits=5, decimal_places=2)
    email = models.EmailField()
    file = models.FileField(upload_to='_tmp/uploads')
    file_path = models.FilePathField()
    float = models.FloatField()
    integer = models.IntegerField()
    generic_ip_address = models.GenericIPAddressField()
    positive_integer = models.PositiveIntegerField()
    positive_small_integer = models.PositiveSmallIntegerField()
    slug = models.SlugField()
    small_integer = models.SmallIntegerField()
    text = models.TextField()
    alt_text = models.TextField(widget=otree.forms.TextInput)
    time = models.TimeField()
    url = models.URLField()
    many_to_many = models.ManyToManyField('SimpleModel', related_name='+')
    one_to_one = models.OneToOneField('SimpleModel', related_name='+')

    currency = models.CurrencyField()
    currency_choice = models.CurrencyField(choices=[('0.01',
                                                     '0.01'), ('1.20',
                                                               '1.20')])

    sent_amount = models.CurrencyField(choices=currency_range(0, 0.75, 0.05))
    slider_widget = models.IntegerField(widget=widgets.SliderInput())
Example #8
0
class Player(BasePlayer):
    def score_round(self):
        # update player payoffs
        if self.solution == self.user_total:
            self.is_correct = True
            self.payoff_score = 1
        else:
            self.is_correct = False
            self.payoff_score = c(0)

    def set_task_score(self):
        op_scores = []
        for op in self.get_others_in_group():
            op_scores.append(int(op.participant.vars['task_2_score']))
        self.participant.vars['task_2_op_scores'] = op_scores

    task_timer = models.PositiveIntegerField(
        doc="""The length of the real effort task timer.""")

    solution = models.PositiveIntegerField(
        doc="this round's correct summation")

    user_total = models.PositiveIntegerField(
        min=1,
        max=9999,
        doc="user's summation",
        widget=widgets.TextInput(attrs={'autocomplete': 'off'}))

    is_correct = models.BooleanField(doc="did the user get the task correct?")

    payoff_score = models.FloatField(doc='''score in this task''')
Example #9
0
class Group(otree.models.BaseGroup):

    # <built-in>
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    players_per_group = 2

    total_return = models.MoneyField(
        doc="""Total return from agent's effort = [Return for single unit of agent's work effort] * [Agent's work effort]"""
    )

    agent_fixed_pay = models.MoneyField(
        doc="""Amount offered as fixed pay to agent"""
    )

    agent_return_share = models.FloatField(
        doc="""Agent's share of total return""",
    )

    agent_work_effort = models.PositiveIntegerField(
        doc="""Agent's work effort, [1, 10]""",
    )


    agent_work_cost = models.MoneyField(
        doc="""Agent's cost of work effort"""
    )

    contract_accepted = models.NullBooleanField(
        doc="""Whether agent accepts proposal""",
        widget=widgets.RadioSelect(),
    )

    # choices
    def agent_fixed_pay_choices(self):
        return money_range(-Constants.max_fixed_payment, Constants.max_fixed_payment, 0.50)

    def agent_work_effort_choices(self):
        return range(1, 10+1)

    def agent_return_share_choices(self):
        return Constants.agent_return_share_choices

    def set_payoffs(self):
        principal = self.get_player_by_role('principal')
        agent = self.get_player_by_role('agent')

        if not self.contract_accepted:
            principal.payoff = Constants.reject_principal_pay
            agent.payoff = Constants.reject_agent_pay
        else:
            self.agent_work_cost = cost_from_effort(self.agent_work_effort)
            self.total_return = return_from_effort(self.agent_work_effort)

            money_to_agent = self.agent_return_share*self.total_return + self.agent_fixed_pay
            agent.payoff = money_to_agent - self.agent_work_cost
            principal.payoff = self.total_return - money_to_agent
Example #10
0
class Group(otree.models.BaseGroup):
    # <built-in>
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    def set_payoffs(self):
        for p in self.get_players():
            p.payoff = 50

    in_all_groups_wait_page = models.FloatField(initial=0)
Example #11
0
class Subsession(otree.models.BaseSubsession):

    name_in_url = 'exp3'

    endowment = models.MoneyField(
        default=20.00,
        doc="payoff = p(endowment-contribution)+a/N*sum(contribution)")

    a = models.FloatField(
        default=2.0,
        doc="payoff = p(endowment-contribution)+a/N*sum(contribution)")
Example #12
0
class Subsession(otree.models.BaseSubsession):

    name_in_url = 'public_goods'

    endowment = models.PositiveIntegerField(
        default=100, doc="""Amount allocated to each player""")

    efficiency_factor = models.FloatField(
        default=1.8, doc="""The multiplication factor in group contribution""")

    question_correct = 92
Example #13
0
class Player(otree.models.BasePlayer):
    # <built-in>
    group = models.ForeignKey(Group, null = True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>
    
    decision = models.FloatField(
        default=None,
        choices=CHOICES,
        doc="degree to which capital requirement is accomodated",
        widget = widgets.RadioSelect()
    )
Example #14
0
class Player(otree.models.BasePlayer):
    # <built-in>
    match = models.ForeignKey(Match, null=True)
    treatment = models.ForeignKey(Treatment, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    decision = models.FloatField(
        default=None,
        choices=[(1, '100 %'), (0.8, '80 %'), (0.6, '60 %'), (0.4, '40 %'),
                 (0.2, '20 %'), (0, '0 %')],
        doc="degree to which capital requirement is accomodated")
Example #15
0
class Treatment(otree.models.BaseTreatment):
    # <built-in>
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    endowment = models.MoneyField(
        default=20.00,
        doc="payoff = p(endowment-contribution)+a/N*sum(contribution)")

    a = models.FloatField(
        default=2.0,
        doc="payoff = p(endowment-contribution)+a/N*sum(contribution)")

    def contribution_choices(self):
        return money_range(0, self.endowment, 1.00)
Example #16
0
class Player(otree.models.BasePlayer):
    def other_player(self):
        """Returns other player in group. Only valid for 2-player groups."""
        return self.get_others_in_group()[0]

    from_other_player = models.PositiveIntegerField()

    is_winner = models.BooleanField(initial=False)
    in_all_groups_wait_page = models.FloatField(initial=0)

    group_id_before_p1_switch = models.PositiveIntegerField()

    def role(self):
        # you can make this depend of self.id_in_group
        return ''
Example #17
0
class Subsession(otree.models.BaseSubsession):

    name_in_url = 'exp1'

    min_value = models.FloatField(default=None,
                                  choices=[(1, '100 %'), (0.8, '80 %'),
                                           (0.6, '60 %'), (0.4, '40 %'),
                                           (0.2, '20 %'), (0, '0 %')],
                                  doc="minimum of all decisions")

    def minimum(self):
        self.min_value = min(p.decision for p in self.players)

    def set_payoffs(self):
        for p in self.players:
            p.payoff = p.treatment.a + p.treatment.b * p.subsession.min_value - p.treatment.c * p.decision
Example #18
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>
    training_my_profit = models.CurrencyField(
        verbose_name='My profit would be')

    price = models.CurrencyField(
        min=0,
        max=Constants.maximum_price,
        doc="""Price player chooses to sell product for""")

    quality = models.CurrencyField(
        min=0,
        max=Constants.maximum_price,
        doc="""Price player chooses to produce with quality equal to""")

    share = models.FloatField(min=0, max=1)
Example #19
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    fw = models.CurrencyField(min=0)
    bet = models.PositiveIntegerField(min=0,
                                      max=100,
                                      widget=widgets.SliderInput())
    rt = models.FloatField()
    is_winner = models.BooleanField()

    def feedback_time(self):
        round_number = self.subsession.round_number
        if self.group.subgroup_type in (Constants.sg1, Constants.sg3):
            return True
        return round_number % 3 == 0

    def decide_time(self):
        if self.group.subgroup_type in (Constants.sg3, Constants.sg2):
            return self.subsession.round_number in (1, 4, 7)
        return True

    def gadd_payoff(self, winner, pw):
        X = Constants.gadd_endowment
        alpha_t = self.bet / 100.
        rtp = (Constants.win_perc if winner else Constants.loose_perc) / 100.
        self.payoff = float(X * (alpha_t * rtp))
        increment = X * (alpha_t * (1 + rtp) + (1 - alpha_t))
        self.fw = pw + increment

    def gmul_payoff(self, winner, pw):
        alpha_t = self.bet / 100.
        rtp = (Constants.win_perc if winner else Constants.loose_perc) / 100.
        self.payoff = float(pw * alpha_t * rtp)
        self.fw = pw * (alpha_t * (1 + rtp) + (1 - alpha_t))

    def set_payoff(self):

        # retrieve the last whealt
        fw = self.last_fw()

        # check if is winner
        self.is_winner = (random.randint(0, 99) <= Constants.win_chance)

        # payoff ccompute
        if self.group.group_type == Constants.gadd:
            self.gadd_payoff(self.is_winner, fw)
        else:
            self.gmul_payoff(self.is_winner, fw)

    def last_fw(self):
        previous = self.in_previous_rounds()
        first = not previous
        if first and self.group.group_type == Constants.gadd:
            return 0
        elif first and self.group.group_type == Constants.gmul:
            return Constants.gmul_endowment
        return previous[-1].fw

    def current_wealth(self):
        if self.group.subgroup_type == Constants.sg1:
            cw = self.last_fw()
        else:
            round_idx = self.subsession.round_number - 1
            if round_idx in (0, 3, 6):
                cw = self.last_fw()
            elif round_idx in (1, 2):
                players = self.in_previous_rounds()
                cw = players[0].last_fw()
            elif round_idx in (4, 5):
                players = self.in_previous_rounds()
                cw = players[3].last_fw()
            elif round_idx in (7, 8):
                players = self.in_previous_rounds()
                cw = players[6].last_fw()

        if self.group.group_type == Constants.gadd:
            cw += Constants.gadd_endowment
        return cw

    def previous_bet(self):
        if self.subsession.round_number == 1:
            return None
        return self.in_previous_rounds()[-1].bet
Example #20
0
class Session(models.OTreeModel):
    class Meta:
        app_label = "otree"
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']

    _ft = FieldTrackerWithVarsSupport()
    vars: dict = models._PickleField(default=dict)
    config: dict = models._PickleField(default=dict, null=True)

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    code = models.CharField(
        default=random_chars_8,
        max_length=16,
        null=False,
        unique=True,
        doc="Randomly generated unique identifier for the session.",
    )

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk',
    )
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk',
    )
    is_mturk = models.BooleanField(default=False)

    def mturk_num_workers(self):
        assert self.is_mturk
        return int(self.num_participants /
                   settings.MTURK_NUM_PARTICIPANTS_MULTIPLE)

    mturk_use_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    # use Float instead of DateTime because DateTime
    # is a pain to work with (e.g. naive vs aware datetime objects)
    # and there is no need here for DateTime
    mturk_expiration = models.FloatField(null=True)
    mturk_qual_id = models.CharField(default='', max_length=50)

    archived = models.BooleanField(
        default=False,
        db_index=True,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"),
    )

    comment = models.TextField(blank=True)

    _anonymous_code = models.CharField(default=random_chars_10,
                                       max_length=10,
                                       null=False,
                                       db_index=True)

    is_demo = models.BooleanField(default=False)

    _admin_report_app_names = models.TextField(default='')
    _admin_report_num_rounds = models.CharField(default='', max_length=255)

    num_participants = models.PositiveIntegerField()

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    @property
    def use_browser_bots(self):
        return self.config.get('use_browser_bots', False)

    def mock_exogenous_data(self):
        '''
        It's for any exogenous data:
        - participant labels (which are not passed in through REST API)
        - participant vars
        - session vars (if we enable that)
        '''
        if self.config.get('mock_exogenous_data'):
            import shared_out as user_utils

            with otree.db.idmap.use_cache():
                user_utils.mock_exogenous_data(self)
                otree.db.idmap.save_objects()
                # need to save self because it's not in the idmap cache
                self.save()

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def get_participants(self):
        return list(self.participant_set.order_by('id_in_session'))

    def mturk_worker_url(self):
        # different HITs
        # get the same preview page, because they are lumped into the same
        # "hit group". This is not documented, but it seems HITs are lumped
        # if a certain subset of properties are the same:
        # https://forums.aws.amazon.com/message.jspa?messageID=597622#597622
        # this seems like the correct design; the only case where this will
        # not work is if the HIT was deleted from the server, but in that case,
        # the HIT itself should be canceled.

        # 2018-06-04:
        # the format seems to have changed to this:
        # https://worker.mturk.com/projects/{group_id}/tasks?ref=w_pl_prvw
        # but the old format still works.
        # it seems I can't replace groupId by hitID, which i would like to do
        # because it's more precise.
        subdomain = "workersandbox" if self.mturk_use_sandbox else 'www'
        return "https://{}.mturk.com/mturk/preview?groupId={}".format(
            subdomain, self.mturk_HITGroupId)

    def mturk_is_expired(self):
        # self.mturk_expiration is offset-aware, so therefore we must compare
        # it against an offset-aware value.
        return self.mturk_expiration and self.mturk_expiration < time.time()

    def mturk_is_active(self):
        return self.mturk_HITId and not self.mturk_is_expired()

    def advance_last_place_participants(self):
        # django.test takes 0.5 sec to import,
        # if this is done globally then it adds to each startup
        # it's only used here, and often isn't used at all.
        # so best to do it only here
        # it gets cached
        import django.test

        client = django.test.Client()

        participants = self.get_participants()

        # in case some participants haven't started
        unvisited_participants = []
        for p in participants:
            if p._index_in_pages == 0:
                unvisited_participants.append(p)
                client.get(p._start_url(), follow=True)

        if unvisited_participants:
            # that's it -- just visit the start URL, advancing by 1
            return

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            try:
                current_form_page_url = p._current_form_page_url
                if current_form_page_url:
                    resp = client.post(
                        current_form_page_url,
                        data={
                            otree.constants.timeout_happened: True,
                            otree.constants.admin_secret_code:
                            ADMIN_SECRET_CODE,
                        },
                        follow=True,
                    )
                    # not sure why, but many users are getting HttpResponseNotFound
                    if resp.status_code >= 400:
                        msg = ('Submitting page {} failed, '
                               'returned HTTP status code {}.'.format(
                                   current_form_page_url, resp.status_code))
                        content = resp.content
                        if len(content) < 600:
                            msg += ' response content: {}'.format(content)
                        raise AssertionError(msg)

                else:
                    # it's possible that the slowest user is on a wait page,
                    # especially if their browser is closed.
                    # because they were waiting for another user who then
                    # advanced past the wait page, but they were never
                    # advanced themselves.
                    start_url = p._start_url()
                    resp = client.get(start_url, follow=True)
            except:
                logging.exception("Failed to advance participants.")
                raise

            # do the auto-advancing here,
            # rather than in increment_index_in_pages,
            # because it's only needed here.
            otree.channels.utils.sync_group_send_wrapper(
                type='auto_advanced',
                group=auto_advance_group(p.code),
                event={})

    def get_room(self):
        from otree.room import ROOM_DICT

        try:
            room_name = RoomToSession.objects.get(session=self).room_name
            return ROOM_DICT[room_name]
        except RoomToSession.DoesNotExist:
            return None

    def _get_payoff_plus_participation_fee(self, payoff):
        '''For a participant who has the given payoff,
        return their payoff_plus_participation_fee
        Useful to define it here, for data export
        '''

        return self.config[
            'participation_fee'] + payoff.to_real_world_currency(self)

    def _set_admin_report_app_names(self):

        admin_report_app_names = []
        num_rounds_list = []
        for app_name in self.config['app_sequence']:
            models_module = otree.common.get_models_module(app_name)
            app_label = get_app_label_from_name(app_name)
            try:
                select_template([
                    f'{app_label}/admin_report.html',
                    f'{app_label}/AdminReport.html'
                ])
            except TemplateDoesNotExist:
                pass
            else:
                admin_report_app_names.append(app_name)
                num_rounds_list.append(models_module.Constants.num_rounds)

        self._admin_report_app_names = ';'.join(admin_report_app_names)
        self._admin_report_num_rounds = ';'.join(
            str(n) for n in num_rounds_list)

    def _admin_report_apps(self):
        return self._admin_report_app_names.split(';')

    def _admin_report_num_rounds_list(self):
        return [int(num) for num in self._admin_report_num_rounds.split(';')]

    def has_admin_report(self):
        return bool(self._admin_report_app_names)
Example #21
0
class Group(otree.models.BaseGroup):
    def set_payoffs(self):
        for p in self.get_players():
            p.payoff = 50

    in_all_groups_wait_page = models.FloatField(initial=0)
Example #22
0
class BasePlayer(models.Model):
    """
    Base class for all players.
    """
    class Meta:
        abstract = True
        index_together = ['participant', 'round_number']
        ordering = ['pk']

    id_in_group = models.PositiveIntegerField(
        null=True,
        db_index=True,
        doc=("Index starting from 1. In multiplayer games, "
             "indicates whether this is player 1, player 2, etc."))

    # don't modify this directly! Set player.payoff instead
    _payoff = models.CurrencyField(
        null=True,
        doc="""The payoff the player made in this subsession""",
        default=0)

    participant = models.ForeignKey('otree.Participant',
                                    related_name='%(app_label)s_%(class)s')

    session = models.ForeignKey('otree.Session',
                                related_name='%(app_label)s_%(class)s')

    round_number = models.PositiveIntegerField(db_index=True)

    _group_by_arrival_time_arrived = models.BooleanField(default=False)
    _group_by_arrival_time_grouped = models.BooleanField(default=False)
    _group_by_arrival_time_timestamp = models.FloatField(default=None,
                                                         null=True)

    def __getattribute__(self, name):
        try:
            return super(BasePlayer, self).__getattribute__(name)
        except AttributeError:
            raise AttributeError(
                ATTRIBUTE_ERROR_MESSAGE.format(name)) from None

    # it's _name instead of name because people might define
    # their own name field
    def _name(self):
        return self.participant.__unicode__()

    @property
    def payoff(self):
        return self._payoff

    @payoff.setter
    def payoff(self, value):
        if value is None:
            value = 0
        delta = value - self._payoff
        self._payoff += delta
        self.participant.payoff += delta
        # should save it because it may not be obvious that modifying
        # player.payoff also changes a field on a different model
        self.participant.save()

    @property
    def id_in_subsession(self):
        return self.participant.id_in_session

    def __repr__(self):
        id_in_subsession = self.id_in_subsession
        if id_in_subsession < 10:
            # 2 spaces so that it lines up if printing a matrix
            fmt_string = '<Player  {}>'
        else:
            fmt_string = '<Player {}>'
        return fmt_string.format(id_in_subsession)

    def role(self):
        # you can make this depend of self.id_in_group
        return ''

    def in_round(self, round_number):
        return in_round(type(self), round_number, participant=self.participant)

    def in_rounds(self, first, last):
        return in_rounds(type(self), first, last, participant=self.participant)

    def in_previous_rounds(self):
        return self.in_rounds(1, self.round_number - 1)

    def in_all_rounds(self):
        '''i do it this way because it doesn't rely on idmap'''
        return self.in_previous_rounds() + [self]

    def get_others_in_group(self):
        return [p for p in self.group.get_players() if p != self]

    def get_others_in_subsession(self):
        return [p for p in self.subsession.get_players() if p != self]

    def __unicode__(self):
        return self._name()

    def _GroupClass(self):
        return self._meta.get_field('group').rel.to

    @property
    def _Constants(self):
        return get_models_module(self._meta.app_config.name).Constants

    @classmethod
    def _ensure_required_fields(cls):
        """
        Every ``Player`` model requires a foreign key to the ``Subsession`` and
        ``Group`` model of the same app.
        """
        subsession_model = '{app_label}.Subsession'.format(
            app_label=cls._meta.app_label)
        subsession_field = models.ForeignKey(subsession_model)
        ensure_field(cls, 'subsession', subsession_field)

        group_model = '{app_label}.Group'.format(app_label=cls._meta.app_label)
        group_field = models.ForeignKey(group_model, null=True)
        ensure_field(cls, 'group', group_field)
Example #23
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    player_name = models.CharField(max_length=255)
    avatar = models.CharField(max_length=255)

    genero = models.CharField(
        max_length=30, widget=widgets.RadioSelectHorizontal(),
        choices=[Constants.hombre, Constants.mujer], verbose_name="Seleccióne su género")

    # bloque 1
    block_1_last_question_clicked = models.IntegerField(default=0, widget=widgets.HiddenInput())

    satisfecho_con_la_vida = models.PositiveIntegerField(
        verbose_name=(
            "En una escala del 1 al 10, donde 1 es nada satisfecho y 10 "
            "totalmente satisfecho, en general ¿qué tan satisfecha(o) se "
            "encuentra usted con su vida? Usted puede escoger cualquier "
            "número entre 1 y 10."), choices=range(1,11),
            widget=widgets.RadioSelectHorizontal(), default=1)

    cuartos_en_el_hogar = models.PositiveIntegerField(
        widget=widgets.SliderInput(), max=20,
        verbose_name=("¿Cuántos cuartos hay en su hogar sin contar pasillos, ni baños?"), min=1, default=1)

    cuantos_cuartos_se_usan_para_dormir = models.PositiveIntegerField(
        widget=widgets.SliderInput(), max=20,
        verbose_name=("Y de esos cuartos, ¿cuántos usan para dormir?"), min=1, default=1)

    habitantes = models.PositiveIntegerField(
        widget=widgets.SliderInput(), max=20,
        verbose_name=("¿Cuántas personas viven en su hogar contando ancianos y niños?"), min=1, default=1)

    focos = models.PositiveIntegerField(
        widget=widgets.SliderInput(), max=50,
        verbose_name=(
            "Contando todos los focos que utiliza para iluminar su hogar, "
            "incluyendo los de techos, paredes y lámparas de buró o piso, "
            "dígame, ¿Cuántos focos tiene en su vivienda?"), min=1, default=1)

    con_quien_vive = models.CharField(
        verbose_name=("¿Con quién vive actualmente?"), max_length=255, default="---",
        choices=["---", "Solo", "Con una pareja", "Con amigos", "Con esposo(a)", "Con familia", "Otro"])

    cuenta_con_automovil = models.BooleanField(
        verbose_name=("Automóvil propio excluyendo taxis"),
        widget=widgets.RadioSelectHorizontal(), default=False)
    cuantos_automovil = models.PositiveIntegerField(default=0)

    cuenta_con_televisor = models.BooleanField(
        verbose_name=("Televisor"),
        widget=widgets.RadioSelectHorizontal(), default=False)
    cuantos_televisor = models.PositiveIntegerField(default=0)

    cuenta_con_celular = models.BooleanField(
        verbose_name=("Teléfono Celular"),
        widget=widgets.RadioSelectHorizontal(), default=False)
    cuantos_celular = models.PositiveIntegerField(default=0)

    cuenta_con_computadora = models.BooleanField(
        verbose_name=("Computadora de escritorio o portátil"),
        widget=widgets.RadioSelectHorizontal(), default=False)
    cuantos_computadora = models.PositiveIntegerField(default=0)

    cuenta_con_bano = models.BooleanField(
        verbose_name=("Baño completo con regadera y excusado para uso exclusivo del hogar"),
        widget=widgets.RadioSelectHorizontal(), default=False)
    cuantos_bano = models.PositiveIntegerField(default=0)

    cuenta_con_servidumbre = models.BooleanField(
        verbose_name=("Personas de servicio doméstico como limpieza, jardinero o chofer"),
        widget=widgets.RadioSelectHorizontal(), default=False)
    cuantos_servidumbre = models.PositiveIntegerField(default=0)

    tarjeta_de_credito = models.BooleanField(
        verbose_name=("Cuenta usted con tarjeta de crédito"),
        widget=widgets.RadioSelectHorizontal(), default=False)

    altura = models.FloatField(
        verbose_name=("Aproximadamente, ¿qué estatura tiene usted? (en metros)"),
        min=0, widget=widgets.SliderInput(attrs={'step': '0.01', 'max': '2.5'}), default=0)

    peso = models.PositiveIntegerField(
        verbose_name=("Aproximadamente, ¿qué peso tiene usted? (en kilogramos)"),
        min=0, max=200, widget=widgets.SliderInput(), default=0)

    ejercicio_fisico = models.BooleanField(
        verbose_name=("Durante las últimas dos semanas, ¿ha realizado usted ejercicio físico fuera del trabajo?"),
        widget=widgets.RadioSelectHorizontal(), default=False)

    cigarrillo = models.BooleanField(
        verbose_name=("Durante las últimas dos semanas, ¿ha fumado algún cigarrillo o puro?"),
        widget=widgets.RadioSelectHorizontal(), default=False)

    vive_con_padre = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(), default=False)
    vive_con_madre = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(), default=False)

    edad_padre = models.PositiveIntegerField(
        choices=range(30, 101), default=30)
    edad_madre = models.PositiveIntegerField(
        choices=range(30, 101), default=30)

    padre_habla_dialecto_indigena = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(), default=False)
    madre_habla_dialecto_indigena = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(), default=False)

    padre_habla_lengua_extranjera = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(), default=False)
    madre_habla_lengua_extranjera = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(), default=False)

    nivel_educacion_padre = models.CharField(
        choices=["---", "Primaria", "Secundaria", "Preparatoria", "Universitario"],
        max_length=50, default="---")
    nivel_educacion_madre = models.CharField(
        choices=["---", "Primaria", "Secundaria", "Preparatoria", "Universitario"],
        max_length=50, default="---")

    # bloque 2
    block_2_last_question_clicked = models.IntegerField(default=0, widget=widgets.HiddenInput())

    riqueza_hogar_14_anios = models.PositiveIntegerField(
        widget=widgets.RadioSelectHorizontal(),
        verbose_name=(
            "Comparando el hogar donde vivía a los 14 años con todos los "
            "hogares actuales de México y usando una escala de 1 a 10, en la "
            "que 1 son los hogares más pobres y 10 son los más ricos, ¿dónde "
            "pondría usted su hogar de ese entonces?"),
        choices=range(1, 11), default=1)

    TRABAJOS = ("---", "Patrón o empleador ", "Trabajador por cuenta propia ",
            "Empleado u obrero del sector público",
            "Empleado u obrero del sector privado", "Servicio Doméstico (por pago)",
            "Quehaceres del hogar (sin pago) ", "Trabajador sin pago ",
            "Fuerzas armadas y del orden")

    padre_trabajaba_14_anios = models.BooleanField(widget=widgets.RadioSelectHorizontal(), default=False)
    madre_trabajaba_14_anios = models.BooleanField(widget=widgets.RadioSelectHorizontal(), default=False)
    padre_ocupacion_14_anios = models.CharField(max_length=255, choices=TRABAJOS, default=TRABAJOS[0])
    madre_ocupacion_14_anios = models.CharField(max_length=255, choices=TRABAJOS, default=TRABAJOS[0])
    padre_trabajo_servicios_medicos_14_anios = models.BooleanField(widget=widgets.RadioSelectHorizontal(), default=False)
    madre_trabajo_servicios_medicos_14_anios = models.BooleanField(widget=widgets.RadioSelectHorizontal(), default=False)

    CON_QUIEN_VIVIA = (
        "---", "Solo con el padre", "Solo con la madre",
        "Con ambos, padre y madre", "Con otra familia", "Otra persona")
    con_quien_vivia_14_anios = models.CharField(
        verbose_name=("Cuando usted tenía alrededor de 14 años ¿con quién vivía?"),
        choices=CON_QUIEN_VIVIA, default=CON_QUIEN_VIVIA[0], max_length=255)

    MUCHO_REGULAR_POCO_NADA = ["---", "Mucho", "Regular", "Poco", "Nada"]
    padre_emocionalmente_cerano_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    madre_emocionalmente_cerano_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    padre_entendia_problemas_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    madre_entendia_problemas_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    padre_actividades_escolares_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    madre_actividades_escolares_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    padre_actividades_tiempo_libre_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    madre_actividades_tiempo_libre_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    padre_reglas_claras_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])
    madre_reglas_claras_14_anios = models.CharField(
        max_length=20, choices=MUCHO_REGULAR_POCO_NADA, default=MUCHO_REGULAR_POCO_NADA[0])

    relacion_padres_14_anios = models.CharField(
        verbose_name=("¿La relación entre sus padres generalmente era: excelente, buena, regular, mala o muy mala?"),
        max_length=20, default="---",
        choices=["---", "Excelente", "Buena", "Regular", "Mala", "Muy mala"])

    FAMILIA_FRECUENCIA = ("Siempre", "Frecuentemente", "Pocas veces", "Nunca", "Omitir")
    familia_frecuencia_insultos_14_anios = models.CharField(
        verbose_name=("¿Con qué frecuencia ocurrían INSULTOS, GRITOS o AMENAZAS en su familia?"),
        max_length=20, choices=FAMILIA_FRECUENCIA, default=FAMILIA_FRECUENCIA[-1])
    familia_frecuencia_cercania_14_anios = models.CharField(
        verbose_name=("¿Con qué frecuencia los miembros de su familia se sentían muy cercanos los unos de los otros?"),
        max_length=20, choices=FAMILIA_FRECUENCIA, default=FAMILIA_FRECUENCIA[-1])
    frequencia_miedos_14_anios = models.CharField(
        verbose_name=("¿Con qué frecuencia la/lo molestaban miedos o preocupaciones?"),
        max_length=20, choices=FAMILIA_FRECUENCIA, default=FAMILIA_FRECUENCIA[-1])

    madre_trabajo_por_ingreso_desde_que_nacio = models.BooleanField(
        verbose_name=("¿Su madre trabajo por un ingreso en algún momento desde que usted nació hasta el día de hoy?"),
        widget=widgets.RadioSelectHorizontal(), default=False)

    madre_trabajo_periodos_de_su_vida_0_4_anios = models.BooleanField(
        verbose_name=("0 a 4 años de edad"), widget=widgets.RadioSelectHorizontal(), default=False)

    madre_trabajo_periodos_de_su_vida_5_9_anios = models.BooleanField(
        verbose_name=("5 a 9 años de edad"), widget=widgets.RadioSelectHorizontal(), default=False)

    madre_trabajo_periodos_de_su_vida_10_14_anios = models.BooleanField(
        verbose_name=("10 a 14 años de edad"), widget=widgets.RadioSelectHorizontal(), default=False)

    madre_trabajo_periodos_de_su_vida_15_19_anios = models.BooleanField(
        verbose_name=("15 a 19 años de edad"), widget=widgets.RadioSelectHorizontal(), default=False)

    tiene_hermanos = models.BooleanField(
        verbose_name=("¿Tiene usted hermanos o hermanas?"),
        widget=widgets.RadioSelectHorizontal(), default=False)

    numero_de_hermano_que_es_usted = models.PositiveIntegerField(
        verbose_name=(
            "Ahora piense en sus hermanos ordenándolos del mayor al menor "
            "aunque hayan fallecido y dígame qué número de hermano es usted."),
        choices=range(1, 11), default=1, widget=widgets.RadioSelectHorizontal())

    HERMANOS_1_10 = ["---"] + [str(i) for i in range(1, 11)]
    hermanos_que_son = models.CharField(choices=HERMANOS_1_10, max_length=10, default=HERMANOS_1_10[0])
    hermanas_que_son = models.CharField(choices=HERMANOS_1_10, max_length=10, default=HERMANOS_1_10[0])
    hermanos_viven_con_usted_actualmente = models.CharField(choices=HERMANOS_1_10, max_length=10, default=HERMANOS_1_10[0])
    hermanas_viven_con_usted_actualmente = models.CharField(choices=HERMANOS_1_10, max_length=10, default=HERMANOS_1_10[0])
    hermanos_trabajan_por_pago_actualmente = models.CharField(choices=HERMANOS_1_10, max_length=10, default=HERMANOS_1_10[0])
    hermanas_trabajan_por_pago_actualmente = models.CharField(choices=HERMANOS_1_10, max_length=10, default=HERMANOS_1_10[0])

    espera_trabajar_remonerado_mayor_parte_de_su_vida = models.BooleanField(
        widget=widgets.RadioSelectHorizontal(),
        verbose_name=("¿Espera usted trabajar de forma remunerada la mayor parte de su vida?"), default=False)

    TRABAJO_FUTURO = [
        "---", "Asalariado", "Auto-empleado", "Dueño de negocio",
        "Dueño de empresa", "Ninguna de las anteriores"]
    de_que_manera_espera_trabajar = models.CharField(
        verbose_name="¿De qué manera espera trabajar?",
        choices=TRABAJO_FUTURO, max_length=100, default=TRABAJO_FUTURO[0])

    cuanto_cree_que_ganaria_en_30_anios = models.PositiveIntegerField(
        widget=widgets.SliderInput(), max=100000,
        verbose_name=(
            "Imagine que usted tiene 30 años el día de hoy y está trabajando "
            "de forma remunerada. ¿Cuánto cree que ganaría al mes por su trabajo?"), default=0)

    cree_que_tendra_hijo = models.CharField(
        verbose_name="Cree que usted tenga un hijo en algún momento de la vida?",
        choices=["---", "Si", "No", "Ya lo tuvo"], max_length=100, default="---")

    edad_de_primer_hijo = models.PositiveIntegerField(
        verbose_name=("¿A qué edad espera tener su primer hijo?"), choices=range(1, 100), default=0)

    edad_tuvo_primer_hijo = models.PositiveIntegerField(
        verbose_name=("¿A qué edad tuvo a su primer hijo?"), choices=range(1, 100), default=0)

    # BLOQUE 3
    block_3_last_question_clicked = models.IntegerField(default=0, widget=widgets.HiddenInput())

    RANGO_1_10 = range(1, 11)

    hogar_actual_vs_mexico = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Comparando su hogar actual con todos los hogares actuales de México y usando una escala de 1 a 10, en la que 1 son los hogares más pobres y 10 son los más ricos, ¿dónde pondría usted su hogar actual?"))

    cuanto_depende_de_usted_que_le_vaya_bien = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("En una escala del 1 al 10, donde 1 es “nada depende de usted” y 10 es “todo depende de usted”, ¿qué tanto depende de usted misma(o) que le vaya bien en este año y el próximo?"))

    gobierno_o_sociedad_pobreza = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Pobreza"))
    gobierno_o_sociedad_delincuencia = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Delincuencia"))
    gobierno_o_sociedad_narcotrafico = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Narcotráfico"))
    gobierno_o_sociedad_corrupcion = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Corrupción"))
    gobierno_o_sociedad_educacion = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Mala o Poca Educación"))
    gobierno_o_sociedad_discriminacion = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Discriminación"))
    gobierno_o_sociedad_adicciones_y_enfermedades = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0],
        widget=widgets.RadioSelectHorizontal(), verbose_name=("Atención de adicciones y enfermedades"))

    dispuesto_a_tomar_riesgos = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("En una escala del 1 al 10, donde 1 es nada dispuesto y 10 totalmente dispuesto, ¿qué tan dispuesto está a tomar riesgos?"))

    describe_como_persona_abstengo_hacer_cosas_hoy = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Me abstengo de cosas hoy para poder tener más mañana"))
    describe_como_persona_retrazo_cosas = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Tiendo a retrasar cosas aun cuando sería mejor hacerlas de una vez"))
    describe_como_persona_asumo_gente_tiene_mejores_intenciones = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Mientras no esté convencido de lo contrario, siempre asumo que la gente tiene las mejores intenciones"))
    describe_como_persona_no_entiendo_pelea_no_le_beneficia = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("No entiendo por qué alguna gente dedica su vida a pelear por una causa que no les beneficia directamente"))
    describe_como_persona_ayudo_al_que_me_ayudo = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Realizo un gran esfuerzo para ayudar a alguien que me ha ayudado antes"))
    describe_como_persona_me_vengo = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Si alguien me hace algo malo a propósito, trataré de regresárselo"))

    que_tan_impulsivo_se_considera = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("En una escala del 1 al 10, donde 1 es totalmente y 10 es nada, ¿qué tan impulsivo se considera?"))

    dispuesto_a_confiar = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Confiar en otras personas"))
    dispuesto_a_compartir = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Compartir algo con otras personas sin nada a cambio"))
    dispuesto_a_regresar_favor = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Regresar un favor a un extraño"))
    dispuesto_a_castigar = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Castigar a alguien debido a una conducta injusta aun cuando es costoso. Ej. Decirle a una persona que no tire basura en la calle aun cuando esa persona se puede enojar y decirle algo."))

    que_tan_paciente_se_considera = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("En una escala del 1 al 10, donde 1 es muy paciente y 10 es muy impaciente, ¿qué tan paciente o impaciente se considera? Usted puede escoger cualquier número entre 1 y 10."))

    acuerdo_con_educacion_genera_ingreso = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("El nivel educativo determina el nivel de ingreso de una persona"))
    acuerdo_con_hombres_mas_trabajo_que_mujeres = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Cuando no hay mucho trabajo, los hombres deberían de tener preferencia a un trabajo antes que las mujeres"))
    acuerdo_con_esposa_que_gana_mas_genera_dinero = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("La esposa que gana más dinero que el esposo genera problemas"))
    acuerdo_con_no_se_puede_confiar_en_nadie = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Hoy en día, no se puede confiar en nadie más"))
    acuerdo_con_camino_de_mi_vida = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("El camino de mi vida depende de mí"))
    acuerdo_con_he_logrado_lo_que_merezco = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("En comparación con otros, no he logrado lo que merezco"))
    acuerdo_con_logros_suerte = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Lo que se logra en la vida es principalmente una cuestión de destino o suerte"))
    acuerdo_con_otros_deciden_por_mi = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Frecuentemente tengo la sensación de que otros toman decisiones sobre mi vida"))
    acuerdo_con_puedo_influir_en_condicion_social = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Si uno es social o políticamente activo, se puede influir en las condiciones sociales"))
    acuerdo_con_trabajar_duro_exito = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Hay que trabajar duro para alcanzar el éxito"))
    acuerdo_con_dudo_de_mi_mismo = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Si enfrento dificultades en la vida, frecuentemente dudo de mí mismo"))
    acuerdo_con_oportunidades_dadas_por_condiciones_sociales = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Las oportunidades que tengo en la vida están determinadas por las condiciones sociales"))
    acuerdo_con_habilidades_mas_que_esfuerzo = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Las habilidades con las que nací son más importantes que todo el esfuerzo que yo pueda hacer"))
    acuerdo_con_poco_control_de_la_vida = models.PositiveIntegerField(
        choices=RANGO_1_10, default=RANGO_1_10[0], widget=widgets.RadioSelectHorizontal(),
        verbose_name=("Tengo poco control sobre las cosas que suceden en mi vida"))

    TOTALMENTE_MUCHO_REGULAR_POCO_NADA = ("---", "Totalmente", "Mucho", "Regular", "Poco", "Nada")
    que_tanto_es_es_reservado = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Es reservado(a)"))
    que_tanto_es_confiable = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Es generalmente confiable"))
    que_tanto_es_flojo = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Tiende a ser flojo(a)"))
    que_tanto_es_relajado = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Es relajado(a) o maneja bien el estrés"))
    que_tanto_es_artista = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Tiene intereses artísticos"))
    que_tanto_es_sociable = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Es extrovertido(a) o sociable"))
    que_tanto_es_falla_en_los_demas = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Tiende a encontrar fallas en los demás"))
    que_tanto_es_nervioso = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Se pone nervioso(a) fácilmente"))
    que_tanto_es_imaginador = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Tiene una imaginación activa"))

    que_tanto_lo_describe_ideas_me_distraen = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Algunas veces nuevas ideas y proyectos me distraen de mis proyectos e ideas anteriores"))
    que_tanto_lo_describe_contratiempos_desanima = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Los contratiempos no me desaniman"))
    que_tanto_lo_describe_persona_trabajadora = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Soy una persona muy trabajadora"))
    que_tanto_lo_describe_pierdo_interes = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Me obsesiono con ideas o proyectos por un tiempo, pero pierdo el interés rápidamente."))
    que_tanto_lo_describe_persigo_diferentes_metas = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Frecuentemente me pongo una meta pero más tarde persigo una diferente."))
    que_tanto_lo_describe_dificultades_para_concentracion = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Tengo dificultades para mantener mi concentración en proyectos que toman más de unos cuantos meses en completarse."))
    que_tanto_lo_describe_termino_lo_que_comienzo = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Termino todo lo que comienzo"))
    que_tanto_lo_describe_efuerzo_en_mi_trabajo = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Pongo mucho esfuerzo en los trabajos que realizo"))
    que_tanto_lo_describe_malos_habitos = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Me cuesta romper malos hábitos"))
    que_tanto_lo_describe_cosas_inapropiadas = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Frecuentemente digo cosas inapropiadas"))
    que_tanto_lo_describe_resisto_tentaciones = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Soy muy bueno para resistir tentaciones"))
    que_tanto_lo_describe_me_arrepiento = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Hago cosas que se sienten bien en el momento pero después me arrepiento de ellas"))
    que_tanto_lo_describe_hago_cosas_sin_pensar = models.CharField(
        choices=TOTALMENTE_MUCHO_REGULAR_POCO_NADA, default=TOTALMENTE_MUCHO_REGULAR_POCO_NADA[0],
        max_length=30, verbose_name=("Frecuentemente hago cosas sin pensar en todas las opciones"))

    apuesta_loteria_1000 = models.PositiveIntegerField(
        verbose_name=("Imagine un juego de lotería con diez boletos numerados del 1 al 10, cuyo premio al número ganador es de $1,000. ¿Cuánto estaría dispuesto a pagar por un boleto para participar en ella?"),
        min=0, max=1000, widget=widgets.SliderInput(), default=0)

    donar_1000 = models.PositiveIntegerField(
        verbose_name=("Imagine la siguiente situación: El día de hoy usted recibe inesperadamente $1,000. ¿Cuánto consideraría donar a una buena causa?"),
        min=0, max=1000, widget=widgets.SliderInput(), default=0)

    pagan_100_esperar_3_meses = models.PositiveIntegerField(
        min=1000, max=50000,  widget=widgets.SliderInput(),
        verbose_name=("¿Cuánto le tendrían que pagar dentro de tres meses para que pueda esperar este tiempo?"), default=0)
    que_tanto_lo_describe_1_anio = models.PositiveIntegerField(
        min=1000, max=50000,  widget=widgets.SliderInput(),
        verbose_name=("Y ahora, ¿cuánto le tendrían que pagar dentro de un año para que pueda esperar ese tiempo?"), default=0)

    # bloque 4
    block_4_last_question_clicked = models.IntegerField(default=0, widget=widgets.HiddenInput())

    # MUJERES
    mestruando = models.BooleanField(
        verbose_name="¿Se encuentra usted menstruando el día de hoy?", default=False, widget=widgets.RadioSelectHorizontal())

    fecha_ultima_regla = models.DateField(
        default=lambda: timezone.now().date(),
        verbose_name="Fecha de comienzo de última regla (si no recuerda con precisión, favor de indicar la fecha más próxima).")
    fecha_siguiente_regla = models.DateField(
        default=lambda: timezone.now().date(),
        verbose_name="Fecha esperada de comienzo de siguiente regla (si no puede calcular con precisión, favor de indicar la fecha más próxima independientemente de si usted es regular o irregular)")

    anticonceptivos = models.BooleanField(
        verbose_name="¿Utiliza pastillas anticonceptivas?", default=False, widget=widgets.RadioSelectHorizontal())

    duracion_del_sangrado = models.PositiveIntegerField(
        verbose_name=("¿Normalmente, cuántos días dura el sangrado?"),
        widget=widgets.SliderInput(), default=5, min=1, max=10)

    # HOMBRES
    trabaja_empresa_dependencia_publica = models.BooleanField(
        verbose_name="Actualmente se encuentra trabajando en alguna empresa o dependencia pública?",
        default=False, widget=widgets.RadioSelectHorizontal())

    fecha_busqueda_empleo = models.DateField(
        default=lambda: timezone.now().date(),
        verbose_name="Aproximadamente, cuando fue la última fecha en que buscó empleo?.")
    fecha_fin_de_estudios  = models.DateField(
        default=lambda: timezone.now().date(),
        verbose_name="Fecha en la que dio por terminados sus estudios?")

    discriminacion_laboral = models.BooleanField(
        verbose_name="Desde su perspectiva, alguna vez ha sido victima de discriminación laboral?",
        default=False, widget=widgets.RadioSelectHorizontal())

    que_tanto_presencio_discriminacion = models.PositiveIntegerField(
        verbose_name=("En una escala del 1 al 10, que tanto ha presenciado discriminación, para usted o algún compañero, en el campo laboral?"),
        widget=widgets.SliderInput(), default=5, min=1, max=10)


    # Bloque 5
    FIGURE_CHOICES_6 = ['---', '1', '2', '3', '4', '5', '6']

    fig1 = models.CharField(
        verbose_name="fig1.jpg",
        max_length=10, choices=FIGURE_CHOICES_6, default=FIGURE_CHOICES_6[0])
    fig2 = models.CharField(
        verbose_name="fig2.jpg",
        max_length=10, choices=FIGURE_CHOICES_6, default=FIGURE_CHOICES_6[0])
    fig3 = models.CharField(
        verbose_name="fig3.jpg",
        max_length=10, choices=FIGURE_CHOICES_6, default=FIGURE_CHOICES_6[0])
    fig4 = models.CharField(
        verbose_name="fig4.jpg",
        max_length=10, choices=FIGURE_CHOICES_6, default=FIGURE_CHOICES_6[0])

    FIGURE_CHOICES_8 = ['---', '1', '2', '3', '4', '5', '6', '7', '8']
    fig5 = models.CharField(
        verbose_name="fig5.jpg",
        max_length=10, choices=FIGURE_CHOICES_8, default=FIGURE_CHOICES_8[0])
    fig6 = models.CharField(
        verbose_name="fig6.jpg",
        max_length=10, choices=FIGURE_CHOICES_8, default=FIGURE_CHOICES_8[0])
    fig7 = models.CharField(
        verbose_name="fig7.jpg",
        max_length=10, choices=FIGURE_CHOICES_8, default=FIGURE_CHOICES_8[0])
    fig8 = models.CharField(
        verbose_name="fig8.jpg",
        max_length=10, choices=FIGURE_CHOICES_8, default=FIGURE_CHOICES_8[0])
    fig9 = models.CharField(
        verbose_name="fig9.jpg",
        max_length=10, choices=FIGURE_CHOICES_8, default=FIGURE_CHOICES_8[0])
    fig10 = models.CharField(
        verbose_name="fig10.jpg",
        max_length=10, choices=FIGURE_CHOICES_8, default=FIGURE_CHOICES_8[0])
Example #24
0
class Participant(models.OTreeModel, models.VarsMixin, ParticipantIDMapMixin):
    class Meta:
        ordering = ['pk']
        app_label = "otree"
        index_together = ['session', 'mturk_worker_id', 'mturk_assignment_id']

    session = djmodels.ForeignKey('otree.Session', on_delete=models.CASCADE)

    vars: dict = models._PickleField(default=dict)
    label = models.CharField(
        max_length=50,
        null=True,
        doc=(
            "Label assigned by the experimenter. Can be assigned by passing a "
            "GET param called 'participant_label' to the participant's start "
            "URL"
        ),
    )

    id_in_session = models.PositiveIntegerField(null=True)

    payoff = models.CurrencyField(default=0)

    time_started = djmodels.DateTimeField(null=True)
    mturk_assignment_id = models.CharField(max_length=50, null=True)
    mturk_worker_id = models.CharField(max_length=50, null=True)

    _index_in_pages = models.PositiveIntegerField(default=0, db_index=True)

    def _numeric_label(self):
        """the human-readable version."""
        return 'P{}'.format(self.id_in_session)

    _monitor_note = models.CharField(null=True, max_length=300)

    code = models.CharField(
        default=random_chars_8,
        max_length=16,
        # set non-nullable, until we make our CharField non-nullable
        null=False,
        # unique implies DB index
        unique=True,
    )

    # useful when we don't want to load the whole session just to get the code
    _session_code = djmodels.CharField(max_length=16)

    visited = models.BooleanField(
        default=False, db_index=True, doc="""Whether this user's start URL was opened"""
    )

    # stores when the page was first visited
    _last_page_timestamp = models.PositiveIntegerField(null=True)

    _last_request_timestamp = models.PositiveIntegerField(null=True)

    is_on_wait_page = models.BooleanField(default=False)

    # these are both for the admin
    # In the changelist, simply call these "page" and "app"
    _current_page_name = models.CharField(
        max_length=200, null=True, verbose_name='page'
    )
    _current_app_name = models.CharField(max_length=200, null=True, verbose_name='app')

    # only to be displayed in the admin participants changelist
    _round_number = models.PositiveIntegerField(null=True)

    _current_form_page_url = djmodels.URLField()

    _max_page_index = models.PositiveIntegerField()

    _is_bot = models.BooleanField(default=False)
    # can't start with an underscore because used in template
    # can't end with underscore because it's a django field (fields.E001)
    is_browser_bot = models.BooleanField(default=False)

    _timeout_expiration_time = models.FloatField()
    _timeout_page_index = models.PositiveIntegerField()

    _gbat_is_waiting = models.BooleanField(default=False)
    _gbat_page_index = models.PositiveIntegerField()
    _gbat_grouped = models.BooleanField()

    def _current_page(self):
        # don't put 'pages' because that causes wrapping which takes more space
        # since it's longer than the header
        return f'{self._index_in_pages}/{self._max_page_index}'

    # because variables used in templates can't start with an underscore
    def current_page_(self):
        return self._current_page()

    def get_players(self):
        """Used to calculate payoffs"""
        lst = []
        app_sequence = self.session.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common.get_models_module(app)
            players = models_module.Player.objects.filter(participant=self).order_by(
                'round_number'
            )
            lst.extend(list(players))
        return lst

    def _url_i_should_be_on(self):
        if not self.visited:
            return self._start_url()
        if self._index_in_pages <= self._max_page_index:
            return url_i_should_be_on(
                self.code, self._session_code, self._index_in_pages
            )
        return reverse('OutOfRangeNotification', args=[self.code])

    def _start_url(self):
        return otree.common.participant_start_url(self.code)

    def payoff_in_real_world_currency(self):
        return self.payoff.to_real_world_currency(self.session)

    def payoff_plus_participation_fee(self):
        return self.session._get_payoff_plus_participation_fee(self.payoff)

    def _get_current_player(self):
        lookup = get_page_lookup(self._session_code, self._index_in_pages)
        models_module = otree.common.get_models_module(lookup.app_name)
        PlayerClass = getattr(models_module, 'Player')
        return PlayerClass.objects.get(
            participant=self, round_number=lookup.round_number
        )