高级特性

这些高级特性大多数在oTree Studio中不被支持。

附加模型

当单个玩家就需要存储几十上百个数据点时,附加模型非常有用。例如存在一系列出价,刺激与反馈时。这常与 实时页面 一起使用。

这里 有很多例子。

一个附加模型应当链接到另一个模型上:

class Bid(ExtraModel):
    player = models.Link(Player)
    amount = models.CurrencyField()

每当用户出价时,将其存到数据库中:

Bid.create(player=player, amount=500)

之后,你就可以提取出玩家出价的列表:

bids = Bid.filter(player=player)

一个附加模型可以有多个链接:

class Offer(ExtraModel):
    sender = models.Link(Player)
    receiver = models.Link(Player)
    group = models.Link(Group)
    amount = models.CurrencyField()
    accepted = models.BooleanField()

此时你就可以以多种方式查询:

this_group_offers = Offer.filter(group=group)
offers_i_accepted = Offer.filter(receiver=player, accepted=True)

对于更加复杂的过滤与排序,你应当使用列表操作:

offers_over_500 = [o for o in Offer.filter(group=group) if o.amount > 500]

参考心理学实验的例子,如斯特鲁普测试,它们展示了如何从CSV表格中的每一行中生成附加模型的数据。

To export your ExtraModel data to CSV/Excel, use 自定义数据导出.

Reading CSV files

注解

This feature is in beta (new in oTree 5.8.2)

To read a CSV file (which can be produced by Excel or any other spreadsheet app), you can use read_csv(). For example, if you have a CSV file like this:

name,price,is_organic
Apple,0.99,TRUE
Mango,3.79,FALSE

read_csv() will output a list of dicts, like:

[dict(name='Apple', price=0.99, is_organic=True),
 dict(name='Mango', price=3.79, is_organic=False)]

You call the function like this:

rows = read_csv('my_app/my_data.csv', Product)

The second argument is a class that specifies the datatype of each column:

class Product(ExtraModel):
    name = models.StringField()
    price = models.FloatField()
    is_organic = models.BooleanField()

(Without this info, it would be ambiguous whether TRUE is supposed to be a bool, or the string 'TRUE', etc.)

read_csv() does not actually create any instances of that class. If you want that, you must use .create() additionally:

rows = read_csv('my_app/my_data.csv', Product)
for row in rows:
    Product.create(
        name=row['name'],
        price=row['price'],
        is_organic=row['is_organic'],
        # any other args:
        player=player,
    )

The model can be an ExtraModel, Player, Group, or Subsession. It’s fine if it also contains other fields; they will be ignored by read_csv().

模板

template_name

如果模板需要有一个与你的页面类不同的名字(例如你在不同的页面中共享同一模板),设置 template_name 即可。例如:

class Page1(Page):
    template_name = 'app_name/MyPage.html'

CSS/JS 与基模板

为将相同的JS/CSS包含在一个应用的所有页面中,可将其放入一个 static file 中,也可将其放入一个可包含的模板。

静态文件

下面说明了如何在页面中包含图片(或任何静态文件如.css, .js,等等)。

在你的oTree项目的根文件夹中,有一个 _static/ 文件夹。将文件放在这里,例如 puppy.jpg.然后,在你的模板中,你可以通过 {{ static 'puppy.jpg' }} 获取文件的URL。

要显示图片,使用 <img> 标签,如:

<img src="{{ static 'puppy.jpg' }}"/>

上面我们将文件保存在 _static/puppy.jpg,但是实际上更好的做法是创建一个子文件夹,起名为你应用的名字,并存为 _static/your_app_name/puppy.jpg ,这使得文件组织有条理,并避免了名字冲突。

此时你的HTML代码变为:

<img src="{{ static 'your_app_name/puppy.jpg }}"/>

(如果你愿意的话,你也可以将静态文件放入你的应用文件夹,在子文件夹 static/your_app_name 中。)

如果静态文件在你更改了之后仍不改变,这是因为你的浏览器缓存了这个文件。重载整个页面即可(通常快捷键是 Ctrl+F5)

如果你需要视频或者高解析度的图片,更好的做法是将其存储在线上别的地方并使用URL进行引用。因为大文件使得上传 .otreezip文件非常缓慢。

等待页面

自定义等待页面模板

You can make a custom wait page template. For example, save this to your_app_name/MyWaitPage.html:

{{ extends 'otree/WaitPage.html' }}
{{ block title }}{{ title_text }}{{ endblock }}
{{ block content }}
    {{ body_text }}
    <p>
        My custom content here.
    </p>
{{ endblock }}

然后在等待页面中使用这一模板:

class MyWaitPage(WaitPage):
    template_name = 'your_app_name/MyWaitPage.html'

此时你可以如寻常一样使用 vars_for_template 。实际上, body_texttitle_text 属性就是设置 vars_for_template 的简略方式;下面两段代码是等价的:

class MyWaitPage(WaitPage):
    body_text = "foo"
class MyWaitPage(WaitPage):

    @staticmethod
    def vars_for_template(player):
        return dict(body_text="foo")

如果你想全局应用你的自定义等待页面模板,将其保存在 _templates/global/WaitPage.html.oTree将自动地在所有地方使用它替换内置的等待页面。

货币

为将”points”自定义为别的名字如”tokens” 或 “credits”, 设置 POINTS_CUSTOM_NAME ,例如 POINTS_CUSTOM_NAME = 'tokens'.

你可以改变真实世界货币的小数位数,通过设置 REAL_WORLD_CURRENCY_DECIMAL_PLACES。如果额外的小数位数显示出来但总是0,那么你应当重置数据库。