web2py survey dynamic forms with nested choices

130 views
Skip to first unread message

NGNZONE

unread,
Oct 12, 2019, 12:54:05 PM10/12/19
to web2py-users

Situation Description

First things first, I am not a very experience web2py developer but I have learned the basics of the framework, so please pardon me if my questions are not so constructive. I started working on a survey application which will enable users to create multiple choice questions. A question will have a number of choices, and when the user selects a particular choice, a corresponding score will be added to a sub total. That is if the survey is about Fruits for instance, if a user selects oranges, 5 will be added to the sub total for that section, if another user selects Mangoes, 10 will be added to the sub total and so on. The attached screenshot survey_layout will better explain what I am talking about. It has three columns, the first column is the question, the second, the corresponding choices and the third column the score linked to each choice. [Survey layout][1] There are six sections in the survey, and each section has a sub_total which is generated from the score value of each choice the user chooses on each of the questions. Finally the sub_totals will be added up to give a grand total for the entire survey and it can then be interpreted. What I have done so far is as seen on the follow screenshots




Questions:

1.How do I create my models in such a way that the user can dynamically create questions for the survey for each section on the page and when the user takes the survey, each choice the user selects, will correspond to a score value which can be tracked and summed up to give the section totals?

2.How will my form be defined to output all the questions for each section one after the other on the screen? I have tried using SQLFORMS but don't know exactly how to achieve this.

  1. Thinking of using pagination to separate the sections so the page will not be too long. any better option?

References: I have watched the web2py survey by MASSIMO DI PIERRO where I learn how to do what I have done so far.

Thanks in advance


create_survey.png
models.png
survey_layout.jpg
take_survey.png

Val K

unread,
Oct 12, 2019, 4:03:32 PM10/12/19
to web2py-users
# db_0.py
# shortcut for `not null` field creation
def req_field(*args, **kwargs):
    kwargs['notnull'] = True
    kwargs['required'] = True
    return Field(*args, **kwargs)

# shortcut for reference field creation, `notnull` by default
def FK(ref_table, **kwargs):
    if 'notnull' not in kwargs:
        kwargs['notnull'] = True
        kwargs['required'] = True
    return Field(ref_table, 'reference %s' % ref_table, **kwargs)

# SURVEY MODEL:
#-------------------[ SURVEY ]-------------------
t_name = 'survey'
db.define_table(t_name,
    req_field('name',  'string'),
)
#-------------------[ QUESTION ]-------------------
t_name = 'question'
db.define_table(t_name,
    req_field('content',  'string'),
)
#-------------------[ ANSWER ]-------------------
t_name = 'answer'
db.define_table(t_name,
    req_field('content',  'string'),
)
#-------------------[ SECTION ]-------------------
t_name = 'section'
db.define_table(t_name,
    req_field('name',  'string'),
)
#-------------------[ SURVEY_QUESTION ]-------------------
t_name = 'survey_question'
db.define_table(t_name,
    FK('survey'),
    FK('section'),
    FK('question'),
)
__UNIQUE_INDEXES__[t_name] = ['survey', 'section', 'question'] # or maybe just ['survey', 'question']?

#-------------------[ SURVEY_QUESTION_ANSWER ]-------------------
t_name = 'survey_question_answer'
db.define_table(t_name,
    FK('survey_question'),
    FK('answer'),
    req_field('score', 'integer', default = 0),
)
__UNIQUE_INDEXES__[t_name] = ['survey_question', 'answer']


# RESULTS MODEL :
#-------------------[ SURVEY_USER_RESULT ]-------------------
# if record exists then `user` check `answer` to `question` from `survey`
t_name = 'survey_user_result'
db.define_table(t_name,
    FK('survey_question_answer'),
    FK('auth_user'),
)
__UNIQUE_INDEXES__[t_name] = ['survey_question_answer', 'auth_user']

# assuming SQLite
def __create_indexes__():
    def make_uniq(tbl, cols):
        sql_str = \
            'CREATE UNIQUE INDEX IF NOT EXISTS %(index_name)s ON %(table_name)s ( %(col_names)s );' \
             % dict( index_name = idx_name,
                     table_name = tbl,
                     col_names = ','.join(["'%s'"%_ for _ in cols])
               )
        db.executesql(sql_str)
    def create_indexes():
        for t in __UNIQUE_INDEXES__:
            args = __UNIQUE_INDEXES__[t]
            if isinstance(args[0], basestring): # single index
                args = [args]
            for a in args:
                make_uniq(t, list(a))
    create_indexes()

# to create indexes uncomment line below, it is required to be run only once 
#__create_indexes__()  # after index creation you can comment this line again

# !!! if indexes or tablenames/fields will be changed (even order of fields in __UNIQUE_INDEXES__[tbl])
#     you should somehow drop old-existing indexes first (there are dozen utils for SQLite) 

Val K

unread,
Oct 12, 2019, 5:11:12 PM10/12/19
to web2py-users
If you want to create/edit survey using one page you have to use JavaScript (I don't see another non-horrible way).
If you want only web2py/python implementation you have to organize your application to edit one entity per page/request,  i.e. you can do something as follows:
/surveys - returns grid of surveys with references to 
   /surveys/<survey> (per row) that returns  grid of  sections + references to
        /surveys/<survey>/<section> that returns grid of questions + references to 
              /surveys/<survey>/<section>/<question> that returns grid (or form with `select multiple` ) of answers with scores

 

  

On Saturday, October 12, 2019 at 7:54:05 PM UTC+3, NGNZONE wrote:

NGNZONE

unread,
Oct 16, 2019, 3:53:59 AM10/16/19
to web2py-users
Thanks Val K, I appreciate the elaborate explanation.
I will try the suggestions ASAP
Regards

António Ramos

unread,
Oct 17, 2019, 6:16:46 AM10/17/19
to web...@googlegroups.com
apart from that you can use google forms and use google api script to call your app webservice and send the json to your table.
This way you can let users create rapidly forms to question users.Then in web2py you can just show the json as a table.


--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/web2py/576ef875-3e96-4477-bb24-fd03170b6ec2%40googlegroups.com.

ngn zone

unread,
Oct 17, 2019, 9:03:21 AM10/17/19
to web...@googlegroups.com
Okay, sounds interesting, I will check that out
Thanks

NGNZONE

unread,
Oct 18, 2019, 1:14:13 PM10/18/19
to web2py-users
Hello Ramos, your solution means that I will have to get this survey always online, but this app will at some point run offline for local users.
So google forms might not be very fitting in this context.
To unsubscribe from this group and stop receiving emails from it, send an email to web...@googlegroups.com.

NGNZONE

unread,
Oct 18, 2019, 2:10:15 PM10/18/19
to web2py-users
I tried to implement your sugggested model in my db.py file, and wrote the views, but the challenge I found was that it simple create a series of dropdown fields from the references we created in the question table. this still takes me back to the original challenge. 
What I tried was:
db.define_table('answer',
                Field('question',db.question),
                Field('choices', 'list:string'),
                Field('score', 'list:integer'),
                )
This gives me an opportunity to enter a series of options, but all are store in a single row. So the  challenge is how do I get the choices that appear in the check-boxes as labels correspond to the respective scores. 
Note that I do not need to pre-populate the table with choices, since the choices will be made by the users taking the survey. 
So I need to design the form in a way that the survey manager can add question with different choices  and or number of choices , as well as scores. and when a user selects a particular choice, the selected button should send the corresponding value to a variable that I can further process.
Each Question has completely different types of choices, some have yes or no, some have five choices, some three and so on, same with the score is not having a consistent pattern, some questions have score 0, 5,10,15,20, others 10,20, 50 and so on.
As seen on the screenshot, if the user at the front end click on the checkbox Always availble, the corresponding score of 10 should be added to the sub_total variable.
If another user clicks on Not Available 5 should be added to the sub_total and so on.
Summarily, the checkbox labels are to be directly connected to the score and both will be defined during survey creation.
Regards
Screenshot from 2019-10-18 18-29-12.png

Val K

unread,
Oct 18, 2019, 6:19:00 PM10/18/19
to web2py-users
'list:string' are definitely RDBMS-anti-pattern: try to count  users that checked A-answer to B-question  from B-section from C-survey and `you`ll see your problems multiplied`(c). 
If 'list:string' seems suitable then you don't need RDBMS at all, you would better use pickle or json or another simpler solution

ngn zone

unread,
Oct 19, 2019, 1:55:57 AM10/19/19
to web...@googlegroups.com
The truth is I need some light on which direction to take. as you have said, I need RDBMS, but talking of json or pickle I will need some help on how to go about it.
Any link to a tutorial or example?
Thanks Val


--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/web2py/4d916ba6-4569-4d0c-b4cc-78ba1da9f762%40googlegroups.com.

ngn zone

unread,
Oct 21, 2019, 7:12:04 AM10/21/19
to web...@googlegroups.com
Thanks Val, I have googled search and came across react JS which can facilitate front end so I am looking at it.


On Fri, Oct 18, 2019 at 11:19 PM Val K <valq...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages