Flexible lab experiment in otree
I found an answer to the second part of the question here https://github.com/oTree-org/otree-docs/issues/2.

It turns out that in oTree,  the variable form which is passed to the template is iterable. Thus one the following code does the job:

{% for field in form %}
        {% formfield field %}
    {% endfor %}


Regarding the first part of the question, I contacted a programmer working at oTree. He confirmed that, in its current version, oTree can only define a fixed number of field. He advised to define in model.py a large maximal number of fields and then use get_form_fields in views.py to dynamically return a list with desired subset of fields.

Notice that if you want to create a really large maximal number of fields, the trick presented in the question using loop and exec remains — I believe — the easiest way to proceed.