I’m working with OTree with self: https://otree.readthedocs.io/en/self/
On the first page of my experiment, I ask the players to provide an access code / their matriculation number via StringField. If their input is not in my dict in Constants, I want to send them directly to a page where I tell them „Sorry, you can’t participate“ with the only option for them to click the next button and exit the experiment.
I have tried the following:
in models.py
class Constants(BaseConstants):
name_in_url = 'prisoners_test1'
players_per_group = 2
num_rounds = 1
matriculation_dict = {
'123': ('Adam Smith', 'Economics'),
'124': ('Ada Lovelace', 'Programming'),
'125': ('Charles Babbage', 'Mathematics'),
}
class Player(BasePlayer):
matriculation = models.StringField(label='Please provide your Matriculation Number')
access = models.BooleanField()
def matriculation_not_found(self):
if self.matriculation in Constants.matriculation_dict:
self.access = True
else: self.access = False
in pages.py
class ExcludedPlayer(Page):
def is_displayed(self):
return self.player.access == False
page_sequence = [Matriculation, ExcludedPlayer, P1_Decision, P2_Decision, ResultsWaitPage, Results]
The problem is that the value of access is not updated through my if statement.
My second problem is that even if the page ExcludedPlayer is displayed (b/c I set initial value of access = False), the player is directed to the other pages (P1_Decision, ResultsWaitPage, Results) after clicking next. How can I end the game for the excluded player?
Thank you for your help!
To your first problem:
To update the access
field, you need to call your matriculation_not_found
method somewhere. A good place for this is the otree built-in method before_next_page
in your Matriculation
class:
class Matriculation(Page):
def before_next_page(self):
self.player.matriculation_not_found()
Or in newer otree versions (no-self format):
class Matriculation(Page):
@staticmethod
def before_next_page(player, timeout_happened):
player.matriculation_not_found()
To your second problem:
The easiest way to prevent the excluded players from seeing the upcoming pages is to remove the next-button. Simply delete the following line from the ExcludedPlayer.html
template:
{{ next_button }}
If for some reason you don't want that, you can also check on each of the upcoming pages in the is_displayed
method whether access is allowed or not. For example for the P1_Decision
page:
class P1_Decision(Page):
def is_displayed(self):
return self.player.access
And again the same in the new no-self format:
class P1_Decision(Page):
@staticmethod
def is_displayed(player):
return player.access
Another alternative would be to swap out the ExcludedPlayers
page to a later app (let's call it 'exculuded_players_app') and skip the pages (and apps) in between using the app_after_this_page
method:
class Matriculation(Page):
def before_next_page(self):
self.player.matriculation_not_found()
def app_after_this_page(self, upcoming_apps):
if not self.player.access:
return 'exculuded_players_app'
And again the same in the new no-self format:
class Matriculation(Page):
@staticmethod
def before_next_page(player, timeout_happened):
player.matriculation_not_found()
@staticmethod
def app_after_this_page(player, upcoming_apps):
if not player.access:
return 'exculuded_players_app'