In oTree, because treatment variables are stored as models, your treatment
variable must fit into one of the field types available in Django (see oTree’s documentation on treatment variables).
In this post I’ll describe a hack to circumvent this limitation. It is kind of ugly but it works for me, and it’s the only way I have found to have lists as treatment variables.
The idea is to first convert your treatment variable into a string
and then convert the string back to its intended format.
To do so, you can use the ast
package.
For instance, if your treatment variable consists in choosing between the
two lists [1,2,3]
and [3,1,2]
at the level of the group, you
would first define a treatment field on the Group
model:
class Group(BaseGroup): # ... treatment = models.CharField()
Then inside the before_subsession_starts
method, you would turn the
chosen list into a string and assign it to treatment
(because
treatment
is a CharField
, it can only be assigned strings)
def before_session_starts(self): for group in self.get_groups(): # Turn the chosen list into a string group.treatment = '%s' %(random.choice([1,2,3],[3,1,2])
Assuming [1,2,3]
was picked, group.treatment
is now a string of the
form '[1,2,3]'
. Thus, you will need to define a method that will
convert the string group.treatment
back to a list whenever
you need it. To do so, first import the package ast
:
# Add the following to the import statements before # class Constants(BaseConstants): import ast
Then define the following method inside the Group
model:
class Group(BaseGroup): # ... def convert_to_list(self): self.treatment = ast.literal_eval(self.treatment)
You can now use your treatment variable as a list by calling
convert_to_list
. For instance, if you want to use your list
in the Decide
page, you could call convert_to_list
inside
the vars_for_template
method inside view.py
:
class Decide(Page): # ... def vars_for_template(self): #... self.group.convert_to_list()
This will make group.treatment
available as a list in the
corresponding template.
Troubleshooting
- Remember to have a look at the doc on treatments from oTree. The example above is for treatments at the group level, and you may need to adapt this according to your needs (e.g. by storing your treatment variable in the
participant.var
of the first player in the group as described in the doc). - One complication with using Django
model.CharField()
is that it may change the encoding of your string from utf-8 or ascii to unicode. If that causes trouble, you may need to redefine yourconvert_to_list
method to something like
class Group(BaseGroup): # ... def convert_to_list(self): if isinstance(self.treatment,str): self.treatment = ast.literal_eval(self.treatment) if isinstance(self.treatment,unicode): self.treatment = ast.literal_eval(self.treatment.encode("utf-8"))