oTree/django 中的强制滑块

Mandatory slider in oTree/django

我想使用 oTree 作为进行实验的替代方案。为此,我正在寻找在表格中包含强制性滑块问题的可能性,即。 e.在您能够继续下一个问题之前,您需要移动滑块。一开始,我尝试修改 oTrees survey template 以实现未来使用的解决方案,但无法将 fieldtracker 等常用方法集成到项目中。

这是 models.py 和 views.py 文件的两个修改版本(但目前经过多次不成功的尝试后还没有真正发挥作用),它们提示了我想去的方向.有没有办法让它发挥作用?

# -*- coding: utf-8 -*-   
## models.py
# <standard imports>
from __future__ import division

from django.db import models
from django_countries.fields import CountryField
from model_utils import FieldTracker,

from otree import widgets
from otree.constants import BaseConstants
from otree.db import models
from otree.models import BaseSubsession, BaseGroup, BasePlayer

class Constants(BaseConstants):
    name_in_url = 'survey'
    players_per_group = None
    num_rounds = 1


class Subsession(BaseSubsession):
    pass


class Group(BaseGroup):
    pass

class Player(BasePlayer):
    def set_payoff(self):
        """Calculate payoff, which is zero for the survey"""
        self.payoff = 0

    q_country = CountryField(
        verbose_name='What is your country of citizenship?')

    q_age = IntegerFielder(verbose_name='What is your age?',
                                        min=13, max=125,
                                        initial=25,
                                        widget=widgets.SliderInput())

    q_gender = models.CharField(initial=None,
                                choices=['Male', 'Female'],
                                verbose_name='What is your gender?',
                                widget=widgets.RadioSelect())

    tracker = FieldTracker()


    crt_bat = models.PositiveIntegerField()
    crt_widget = models.PositiveIntegerField()
    crt_lake = models.PositiveIntegerField()

第二个文件来了:

# -*- coding: utf-8 -*-
##views.py
from __future__ import division
from . import models
from ._builtin import Page, WaitPage
from otree.common import Currency as c, currency_range
from .models import Constants, integerfieldcustom

class Demographics(Page):

    form_model = models.Player
    form_fields = ['q_country',
                  'q_age',
                  'q_gender']
    check_age = q_age.tracker.has_changed()

    def q_age_error_message(self, ):
        if Demographics.check_age == False:
            return 'You must move the slider before you can continue'


class CognitiveReflectionTest(Page):

    form_model = models.Player
    form_fields = ['crt_bat',
                  'crt_widget',
                  'crt_lake']

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

page_sequence = [
    Demographics,
    CognitiveReflectionTest
]

提前致谢!

默认情况下,Django assumes an input is required

我认为这意味着如果您只是删除初始值,它将自我验证。

另外,你调用了一个名为 "IntegerFielder()." 的东西你是说 models.IntegerField() 还是有一个我们没有看到的导入?

有两种方法:在客户端仅使用 JS,在服务器端使用 Django。

简单的JS解决方案: 在模板中添加:

  {% block scripts %}
  <script>
  var SliderTouched = false;
  var selector = $('[data-slider] input[type="range"]');
  selector.change(function() {
    SliderTouched = true;
  });


  $( ".form" ).submit(function( event ) {
    if (!SliderTouched){
    event.preventDefault();}
  });
  </script>
  {% endblock %}

因此,在用户触发 change 事件之前,SliderTOuched var 将设置为 False,从而阻止提交表单。这是一种紧凑的方式,但您必须自己处理向用户显示错误消息。

=================

较长的服务器端解决方案如下:

models.py中定义一个附加字段:

    class Player(BasePlayer):
        checkslider = models.IntegerField(blank=True)

views.py 中,除了您的滑块字段外,还要传递这个额外的字段来检查滑块是否已更改:

    class MyPage(Page):
        form_model = models.Player
        form_fields = ['q_age', 'checkslider']


        def checkslider_error_message(self, value):
            if not value:
                return 'Please make your decision using slider'

在模板中将这个隐藏的额外字段插入到 html:

  <input type="hidden" name="checkslider" value="" id="id_checkslider"/>

并在更改滑块后立即将此字段设置为当前滑块值:

  {% block scripts %}
    <script>
      var selector = $('[data-slider] input[type="range"]');
      selector.change(function() {
        $('#id_checkslider').val(selector.val());
      });
    </script>
  {% endblock %}

我建议对 Philipp 的回答稍作修改。

如果参与者触摸滑块,但 returns 滑块移动到默认起始位置,上面的代码仍会触发错误消息。

为了解决这个问题,我使用了以下脚本:

{% block scripts %}
    <script>
        $('input[name=q_age]').on('input', function(){
            $('#id_checkslider').val(1);
        });
    </script>
{% endblock %}

触摸滑块时,代码将 checksliderNone 更改为 1,即使参与者将滑块设置为默认起始位置也是如此。