oTree中的每个页面都可以包含一个表单,玩家应通过单击“下一步”按钮填写并提交该表单。要创建表单,首先需要Player
在models.py中的类中使用字段。然后,在您的Page类中,设置form_model
和form_fields
。
例如,这是models.py:
和pages.py:
当用户提交表单时,提交的数据将自动保存到玩家模型上的相应字段中。
(您也可以设置form_model ='group'而不是player;请参阅form_model ='group'。)
在2018年1月,语法从form_model = models.Player更改为form_model ='player'。 有关更多信息,请参阅oTree 2.0。
模板中的表单
在模板中,您可以显示表单。{% formfields %}
{% formfields %}
于2018年6月推出。它相当于:
如果要单独定位字段,可以改为使用:{% formfield %}
您也可以将直接放在模板中:
注意:如果您之前编写过HTML表单,则可能习惯于编写<input>元素,例如: <input type =“text”name =“contribution”>。 在oTree中,通常使用formfield更容易。 它将自动生成正确的<input> HTML,以及CSS样式,标签和错误消息。 但是,如果您想要更灵活,可以自由编写原始HTML。 请参阅高级:原始HTML小部件。
form_model = ‘group’
如果你设置form_model ='group'。 用户提交的值将存储在组模型中,而不是玩家中。 这在一些玩家代表小组做出决定的游戏中通常很有用。 例如,在最后通牒博弈实验中,玩家1提出要求而玩家2接受或拒绝。 由于每组只提供1个要求,您可以在组中定义字段:
您的页面如下所示:
在您的模板中,您将拥有:
简单的表单字段验证
玩家必须在进入下一页之前提交有效表格。如果他们提交的表单无效(例如缺失或不正确的值),则会将其重新显示给他们以及他们需要纠正的错误列表。
oTree自动验证输入。 例如,如果您有一个包含IntegerField的表单,oTree将拒绝输入,如1.5或hello。
最小和最大
例如,这是你需要一个12到24之间的整数:
如果最大/最小值未修复,则应使用{field_name} _max()
选择
如果您希望字段为包含选项列表的下拉菜单,请设置choices=
:
要使用单选按钮而不是下拉菜单,您应该将小部件设置为RadioSelect或RadioSelectHorizontal:
如果需要动态确定选择列表,请使用{field_name} _choices()
您还可以通过列出[value,display]对来为每个选项设置显示名称:
如果您这样做,用户只会看到“低”,“中”,“高”的菜单,但他们的回复将被记录为1,2或3。
设置字段后,您可以使用get_FOO_display访问人类可读的名称,如下所示:self.get_level_display()#return,例如: '中'。 但是,如果使用{field_name} _choices()动态定义选项,为了使用get _ * _ display(),还需要在models.py中的Player / Group上定义* _choices方法。
可选字段
如果字段是可选的,您可以这样使用blank=True
:
然后HTML字段将没有该required
属性。
动态表单字段验证
的min
,max
和choices
上面描述仅用于固定的(恒定)值。
如果您希望动态确定它们(例如,不同于玩家),那么您可以在Page
类中定义以下方法之一pages.py
。
{field_name} _choices()
就像choices=
在models.py中设置一样,这将设置表单字段的选项(例如下拉菜单或单选按钮)。
{field_name} _max()
max=
在models.py中设置的动态替代方法。例如:
{field_name} _min()
min
在models.py中设置的动态替代方法。
{field_name} _error_message()
这是验证字段最灵活的方法。
例如,假设玩家必须进行购买,但此次购买不能超过玩家的预算。假设您的字段被调用purchase
并且budget
:
一起验证多个字段
假设您的表单中有3个整数字段,其名称为 int1
,int2
和int3
,并且提交的值必须总和为100.您可以使用以下error_message
方法强制执行此操作:
动态确定表单域
如果您需要表单字段列表是动态的,而不是form_fields,您可以定义返回列表的方法get_form_fields(self)。 例如:
但是,如果这样做,您必须确保在模板中包含相同的{%formfield%}元素。 最简单的方法是使用{%formfields%}。
小部件
Django提供的表单输入小部件的完整列表就 在这里。
oTree另外提供:
RadioSelectHorizontal
(RadioSelect
与水平布局相同,正如您将看到的Likert量表)Slider
- 要指定步长,请执行以下操作:
Slider(attrs={'step': '0.01'})
- 要禁用显示当前值,请执行以下操作:
Slider(show_value=False)
- 要指定步长,请执行以下操作:
自定义字段的外观
{%formfields%}和{%formfield%}易于使用,因为它们使用Bootstrap样式自动输出表单字段的所有必要部分(输入,标签和任何错误消息)。
但是,如果您想要更好地控制外观和布局,可以使用Django的手动场渲染。 不要{%formfield player.my_field%},而是{{form.my_field}},只获取输入,然后根据需要定位。
请记住还要包含{{form.my_field.errors}},这样如果表单中有错误,参与者将看到错误消息。
更多信息在这里。
示例:表格中的单选按钮和其他自定义布局
假设IntegerField
您的模型中有一组:
并且您希望将它们呈现为一个类似的比例,其中每个选项都在一个单独的列中。
(首先,按照如何创建许多字段中的说明,尝试减少models.py中的代码重复。)
因为选项必须位于单独的表格单元格中,所以普通的RadioSelectHorizontal小部件在此处不起作用。
相反,您应该简单地循环遍历字段中的选项,如下所示:
如果您有许多具有相同选择数的字段,则可以将它们排列在表格中:
您还可以使用基于0的索引单独获取选项,例如 {{form.my_field.0}}为您提供了第一选择的单选按钮。 对于更精细的控制,如此处所述,您可以在字段选择上使用choice_label和tag属性。
高级:原始HTML小部件
如果和手动字段渲染 仍然不够灵活,您可以为表单输入编写原始HTML。但是,您将失去oTree自动处理的便捷功能。例如,如果表单有错误并且页面重新加载,则可能会清除用户的所有条目。{% formfield %}
要使用原始HTML,只需确保Page的每个字段form_fields
都有一个<input>
具有匹配name
属性的对应元素。
请记住,对于任何字段my_field
,您应该包括,以便如果表单中有错误,参与者将看到错误消息。{{ form.my_field.errors }}
原始HTML示例:使用JavaScript的自定义用户界面
假设您不希望用户填写表单字段,而是与某种可视应用程序进行交互,例如点击图表或玩图形游戏。或者,您希望记录额外的数据,例如他们在页面的一部分上花了多长时间,他们点击了多少次等等。
您可以在任何所需的前端框架中构建这些接口。简单的可以使用jQuery完成; 更复杂的会使用像React或Polymer这样的东西。
然后,使用JavaScript记录相关数据点并将其存储在隐藏表单字段中。例如:
然后,您可以使用JavaScript设置该输入的值,方法是选择id的元素id_my_hidden_input
,并设置其value
属性。
提交页面时,隐藏输入的值将像任何其他表单字段一样记录在oTree中。
按钮
提交表单的按钮
如果您的页面只包含1个决定,则可以省略 ,而是让用户单击其中一个按钮转到下一页。{% next_button %}
例如,假设您的models.py有,而不是单选按钮,您希望将其显示为如下按钮:offer_accepted = models.BooleanField()
首先,像往常一样放入offer_accepted
你的Page form_fields
。然后将此代码放在模板中(这些btn
类仅用于Bootstrap样式):
您可以将此技术用于任何类型的字段,而不仅仅是BooleanField
。
不提交表单的按钮
如果按钮除了提交表单之外有其他目的,请添加type="button"
到<button>
:
杂项和高级
具有动态矢量字段的表单
假设你想要一个带有n个字段向量相同的表单,除了一些数字索引,例如:
此外,假设n是可变的(范围从1到N)。
目前在oTree中,您只能在模型中定义固定数量的字段。因此,您应该在models.py
N fields(contribution_1...contribution_N...
)中定义,然后get_form_fields
如上所述使用动态返回包含这些字段的所需子集的列表。
例如,假设上面的变量n
实际上是IntegerField
玩家,它在游戏中的某个点动态设置。你可以get_form_fields
像这样使用:
带动态标签的表单字段
如果标签应包含变量,则可以在pages.py
以下位置构造字符串:
然后在模板中,将标签设置为此变量:
如果您使用此技术,您可能还需要使用动态表单字段验证。