如果 StringField 输入不在我的字典中,OTree / Django 将播放器发送到结果/退出页面

OTree / Django send player to results/ exit page if StringField input not in my dict

我正在和自己一起使用 OTree:https://otree.readthedocs.io/en/self/

在我实验的第一页,我要求玩家通过 StringField 提供访问代码/他们的入学编号。如果他们的输入不在我在常量中的字典中,我想将他们直接发送到一个页面,在那里我告诉他们“抱歉,你不能参与”,他们唯一的选择是单击下一步按钮并退出实验。

我试过以下方法:

在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

在pages.py

class ExcludedPlayer(Page):
    def is_displayed(self):
        return self.player.access == False

page_sequence = [Matriculation, ExcludedPlayer, P1_Decision, P2_Decision, ResultsWaitPage, Results]

问题是 access 的值没有通过我的 if 语句更新。

我的第二个问题是,即使显示了 ExcludedPlayer 页面(b/c 我将 access 的初始值设置为 False),播放器也会被定向到其他页面(P1_Decision、ResultsWaitPage、结果)点击下一步后。如何为被排除的玩家结束游戏?

感谢您的帮助!

第一个问题:

要更新 access 字段,您需要在某处调用 matriculation_not_found 方法。这样做的好地方是 Matriculation class:

中的 otree built-in 方法 before_next_page
class Matriculation(Page):

    def before_next_page(self):
        self.player.matriculation_not_found()

或较新的 otree 版本(no-self 格式):

class Matriculation(Page):

    @staticmethod
    def before_next_page(player, timeout_happened):
        player.matriculation_not_found()

你的第二个问题:

防止被排除的玩家看到即将到来的页面的最简单方法是删除 next-button。只需从 ExcludedPlayer.html 模板中删除以下行:

{{ next_button }}

如果出于某种原因您不希望这样,您还可以在 is_displayed 方法中检查每个即将到来的页面是否允许访问。例如 P1_Decision 页面:

class P1_Decision(Page):
    
    def is_displayed(self):
        return self.player.access

在新的 no-self 格式中同样如此:

class P1_Decision(Page):
    
    @staticmethod
    def is_displayed(player):
        return player.access

另一种选择是将 ExcludedPlayers 页面换成以后的应用程序(我们称之为 'exculuded_players_app')并跳过使用 app_after_this_page 之间的页面(和应用程序)方法:

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'

在新的 no-self 格式中同样如此:

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'