第一部分:简单的调查问卷(适用于PyCharm用户)

我们来创建一个简单的问卷调查–在第一个页面上,将询问参与人的姓名与年龄,之后在第二个页面上,将此信息展示给参与人.

创建应用

使用 cd 命令进入你创建的oTree项目文件夹,(文件夹中包含一个 settings.py 文件)。假设命名文件夹为 oTree,你应该使用下面的指令:

cd oTree

然后,创建应用:

otree startapp my_simple_survey

然后在PyCharm中,前往刚刚创建的 my_simple_survey 文件夹。

Define models

打开 app.py 并找到含有 class Player(BasePlayer): 的那行,在这里定义数据库中玩家表有哪些列。让我们添加下面两个字段:

  • name (StringField, 意为文本型数据)
  • age (一个正整数字段)
class Player(BasePlayer):
    name = models.StringField()
    age = models.IntegerField()

定义模板

此调查问卷包含2个页面:

  • 页面1:玩家输入姓名与年龄
  • 页面2:玩家看到他们在之前的页面输入的数据

So, let’s make 2 HTML template files.

不妨将第一个页面命名为 MyPage.html ,填入内容如下:

{% extends "global/Page.html" %}

{% block title %}
    Enter your information
{% endblock %}

{% block content %}

    Please enter the following information.

    {% formfields %}

    {% next_button %}

{% endblock %}

第二个模板命名为 Results.html.

{% extends "global/Page.html" %}

{% block title %}
    Results
{% endblock %}

{% block content %}

    <p>Your name is {{ player.name }} and your age is {{ player.age }}.</p>

    {% next_button %}
{% endblock %}

Define pages

现在定义页面,页面包含了如何显示HTML模板的控制逻辑。

Since we have 2 templates, we need 2 Page classes. The names should match those of the templates (MyPage and Results).

首先定义 MyPage.这个页面包含一个表单,我们需要定义 form_modelform_fields.

class MyPage(Page):
    form_model = 'player'
    form_fields = ['name', 'age']

现在来定义 Results. 这一页面不含有表单或其他特殊属性,所以我们只需要写“pass”。

class Results(Page):
    pass

If there is already a WaitPage, you can delete that, because WaitPages are only necessary for multi-player games.

Then, set your page_sequence to MyPage followed by Results. So, all in all, your pages should look like this:

class MyPage(Page):
    form_model = 'player'
    form_fields = ['name', 'age']


class Results(Page):
    pass


page_sequence = [
    MyPage,
    Results
]

在settings.py中定义session config

现在打开在项目文件夹最上方的 settings.py 并在 SESSION_CONFIGS 中增加一个条目。

SESSION_CONFIGS = [
    dict(
        name='my_simple_survey',
        num_demo_participants=3,
        app_sequence=['my_simple_survey']
    ),
]

启动服务器

输入:

otree devserver

然后打开你的浏览器,输入网站 http://localhost:8000 即可测试此调查问卷。

处理错误

如果你的代码中有错误,那么命令行会显示“traceback”(报错信息),一般格式如下:

Traceback (most recent call last):
  File "C:\oTree\chris\manage.py", line 10, in <module>
    execute_from_command_line(sys.argv, script_file=__file__)
  File "c:\otree\core\otree\management\cli.py", line 170, in execute_from_command_line
    utility.execute()
  File "C:\oTree\venv\lib\site-packages\pkg\core\management\__init__.py", line 328, in execute
    pkg.setup()
  File "C:\oTree\venv\lib\site-packages\pkg\__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "C:\oTree\venv\lib\site-packages\pkg\apps\registry.py", line 108, in populate
    app_config.import_models(all_models)
  File "C:\oTree\venv\lib\site-packages\pkg\apps\config.py", line 198, in import_models
    self.models_module = import_module(models_module_name)
  File "C:\Python27\Lib\importlib\__init__.py", line 37, in import_module
    __import__(name)
  File "C:\oTree\chris\public_goods_simple\models.py", line 40
    self.total_contribution = sum([p.contribution for p in self.get_players()])
       ^
IndentationError: expected an indented block

之所以称为“traceback”是因为它可以沿着代码调用链追踪错误。第一步你应当查看报错信息的最后一行。具体来说,在最后一条记录中找到文件名和行号。在上面的例子中,即 "C:\oTree\chris\public_goods_simple\models.py", line 40.之后转到对应文件的对应行号。检查在traceback最后一行中提到的错误。在本例中,错误是 IndentationError: expected an indented block (这表明了问题应当与代码缩进有关)。尝试修复这个错误并重新运行之前的命令。

有些时候traceback的最后一行没有指向你代码的一部分。如下例中的traceback,最后一行指向 /site-packages/easymoney.py,这并不是你的应用的一部分,而是一个外部的包:

Traceback:
File "/usr/local/lib/python3.5/site-packages/pkg/core/handlers/base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.5/site-packages/pkg/pages/generic/base.py" in view
  71.             return player.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/pkg/utils/decorators.py" in _wrapper
  34.             return bound_func(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/pkg/pages/decorators/cache.py" in _wrapped_view_func
  57.         response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/pkg/utils/decorators.py" in bound_func
  30.                 return func.__get__(player, type(player))(*args2, **kwargs2)
File "/usr/local/lib/python3.5/site-packages/pkg/utils/decorators.py" in _wrapper
  34.             return bound_func(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/pkg/pages/decorators/cache.py" in _cache_controlled
  43.             response = viewfunc(request, *args, **kw)
File "/usr/local/lib/python3.5/site-packages/pkg/utils/decorators.py" in bound_func
  30.                 return func.__get__(player, type(player))(*args2, **kwargs2)
File "/usr/local/lib/python3.5/site-packages/otree/pages/abstract.py" in dispatch
  315.                 request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/pkg/pages/generic/base.py" in dispatch
  89.         return handler(request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/otree/pages/abstract.py" in get
  814.         return super(FormPageMixin, player).get(request, *args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/vanilla/model_views.py" in get
  294.         context = player.get_context_data(form=form)
File "/usr/local/lib/python3.5/site-packages/otree/pages/abstract.py" in get_context_data
  193.         vars_for_template = player.resolve_vars_for_template()
File "/usr/local/lib/python3.5/site-packages/otree/pages/abstract.py" in resolve_vars_for_template
  212.         context.update(player.vars_for_template() or {})
File "/Users/chris/oTree/public_goods/pages.py" in vars_for_template
  108.             'total_payoff': player.player.payoff + Constants.fixed_pay}
File "/usr/local/lib/python3.5/site-packages/easymoney.py" in <lambda>
  36.     return lambda player, other, context=None: player.__class__(method(player, _to_decimal(other)))
File "/usr/local/lib/python3.5/site-packages/easymoney.py" in _to_decimal
  24.         return Decimal(amount)

Exception Type: TypeError at /p/j0p7dxqo/public_goods/ResultsFinal/8/
Exception Value: conversion from NoneType to Decimal is not supported

在这种情况下,查看是否你的代码的某部分被包含在traceback中。我们可以从上面的traceback中看出它包含了文件 /Users/chris/oTree/public_goods/pages.py,这一文件正是我们项目的一部分。而错误就在该文件的108行,如traceback所提示的一样。