Defining repeated fields in oTree Studio

532 views
Skip to first unread message

Peter Cock

unread,
Aug 9, 2021, 8:16:12 AM8/9/21
to oTree help & discussion
Hello all,

Is it possible to follow this example within oTree Studio?

https://otree.readthedocs.io/en/latest/misc/tips_and_tricks.html#how-to-make-many-fields

i.e. I want to end up with something like this in the app's __init__.py file:

def make_field(label):
    return models.IntegerField(
        choices=[1,2,3,4,5],
        label=label,
        widget=widgets.RadioSelect,
    )

class Player(BasePlayer):
    q1 = make_field('I am quick to understand things.')
    q2 = make_field('I use difficult words.')
    q3 = make_field('I am full of ideas.')
    q4 = make_field('I have excellent ideas.')

I can't see how to do this from the "Models >  Player" page in oTree Studio.

Thank you,

Peter

P.S. I was actually looking for a built in field defined as an array (of booleans, or integers, etc) rather that just a single value - but presume this is not commonly needed in oTree.

Peter Cock

unread,
Aug 9, 2021, 10:51:41 AM8/9/21
to oTree help & discussion
I can get most of the functionality I want under oTree "Lite" (v5.2.8) with this simple approach:

class Player(BasePlayer):
    example1 = models.BooleanField(label='1')
    example2 = models.BooleanField(label='2')
    example3 = models.BooleanField(label='3')
    example4 = models.BooleanField(label='4')
    example5 = models.BooleanField(label='5')

And then rather than handling the display settings with repetitive optional arguments when defining the field, I can do that in the HTML template based on the example here:

https://otree.readthedocs.io/en/latest/forms.html?highlight=formfield#example-radio-buttons-in-tables-and-other-custom-layouts

However, while that above works, if the user misses a field, there is an error. The devserver debug information suggests fixing by adding:

{% formfield_errors "example1" %}
{% formfield_errors "example2" %}
...
{% formfield_errors "example5" %}

Another aside, the hint could use the now recommended {{ formfield "example1" }} style over the older {% ... %} style.

Can we nest templates to put that inside the for loop? That would put the error next to the field which would be ideal. I found this does not work:

{% formfield_errors {{ field }} %}

Or, does oTree Lite need an all fields version of formfield_errors (like formfields_errors) to match formfield and formfields (plural)? Or could these default to all fields if no qualifier is given?

Thanks,

Peter

Chris @ oTree

unread,
Aug 9, 2021, 11:50:36 AM8/9/21
to oTree help & discussion
On Monday, August 9, 2021 at 8:51:41 AM UTC-6 p.j.a...@googlemail.com wrote:
I can get most of the functionality I want under oTree "Lite" (v5.2.8) with this simple approach:

class Player(BasePlayer):
    example1 = models.BooleanField(label='1')
    example2 = models.BooleanField(label='2')
    example3 = models.BooleanField(label='3')
    example4 = models.BooleanField(label='4')
    example5 = models.BooleanField(label='5')

And then rather than handling the display settings with repetitive optional arguments when defining the field, I can do that in the HTML template based on the example here:

https://otree.readthedocs.io/en/latest/forms.html?highlight=formfield#example-radio-buttons-in-tables-and-other-custom-layouts

However, while that above works, if the user misses a field, there is an error.

Make the field optional with blank=True. See the multi_select app here: https://www.otreehub.com/projects/otree-snippets/
 
The devserver debug information suggests fixing by adding:

{% formfield_errors "example1" %}
{% formfield_errors "example2" %}
...
{% formfield_errors "example5" %}

Another aside, the hint could use the now recommended {{ formfield "example1" }} style over the older {% ... %} style.

Can we nest templates to put that inside the for loop? That would put the error next to the field which would be ideal. I found this does not work:

{% formfield_errors {{ field }} %}

{{ formfield_errors field }}

Peter Cock

unread,
Aug 9, 2021, 12:04:21 PM8/9/21
to oTree help & discussion
I found {{ formfield field }} works - which can be very elegant, and {{ formfield_errors field }} would be great - but it seems to fail:

otree.templating.errors.TemplateRenderingError: Error while rendering the PRINT tag: TypeError: argument must be a string (line 17, in "formfield_errors")

Is that an oversight?

Peter

Chris @ oTree

unread,
Aug 9, 2021, 12:07:16 PM8/9/21
to Peter Cock, oTree help & discussion
Ok I will check that. 

Sent from my phone

On Aug 9, 2021, at 10:04 AM, 'Peter Cock' via oTree help & discussion <ot...@googlegroups.com> wrote:

I found {{ formfield field }} works - which can be very elegant, and {{ formfield_errors field }} would be great - but it seems to fail:
--
You received this message because you are subscribed to the Google Groups "oTree help & discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to otree+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/otree/4807d993-8274-4f19-8624-d15095c91d36n%40googlegroups.com.

Chris @ oTree

unread,
Aug 9, 2021, 12:38:57 PM8/9/21
to oTree help & discussion
Works fine for me.

class MyPage(Page):
    form_model = 'player'
    form_fields = ['a']

    @staticmethod
    def vars_for_template(player: Player):
        return dict(field='a')

then in template:

{{ formfield_errors field }}



Peter Cock

unread,
Aug 10, 2021, 7:06:52 AM8/10/21
to oTree help & discussion
I'm sure I replied to this last night, but evidently not. Apologies if that message shows up later.

Chris' snippet was going in a different direction - but I solved the error display problem with a little lucky and experimentation. A simplified example:

<table class="table">
    {{ for field in form }}
        <tr>
            <th>#{{ field.label }}</th>
            <td>
                <p>
                {{ for choice in field }}
                    {{ choice }}<br />
                {{ endfor }}
                </p>
                {{ formfield_errors field.name }}
            </td>
        </tr>
    {{ endfor }}
</table>

What I had been missing was given a loop variable field, I could use field.name to get the field's name as a string suitable for {{ formfield field.name }} or {{ formfield_errors field.name }}, which is reasonably concise.

Working example here:


However, on testing it became clear that bypassing the default control rendering misses out on data entry validation. These tradeoffs are hinted at in the documentation:


So, in the end I have gone for the default control rendering using {{ formfield ... }} which is concise, but apparently requires verbose repetitive field definition in oTree Studio (as per my original query). Now clicking on "next" scrolls to the first unanswered field. Changes here:


I remain puzzled as too why I can use either {{ formfield field }} or {{ formfield field.name }} but only {{ formfield_errors field.name }} and not {{ formfield_errors field }} (which gives a TypeError):


Regards,

Peter

Reply all
Reply to author
Forward
0 new messages