Django - Aggregate survey responses into string - django

I'm building out a survey in django. I would like to store the responses of the survey into a single string rather than a bunch of individual variables. My hope is that using this structure I can store surveys of varying lengths into a single table. I'm not sure how you loop through the survey responses and aggregate them and insert them into the db using django's ORM model. I'm guessing that you have to use raw SQL? Suggestions or URLs on where I might start appreciated. A more concrete example below.
Basic DB Design
PID=UUID
Responses=Char256
Survey example
<p>1. Item 1.<p>
<input type="radio" name="Q1" value="1">Very Inaccurate<br>
<input type="radio" name="Q1" value="2">Moderately Inaccurate<br>
<input type="radio" name="Q1" value="3">Neither Accurate or Inaccurate<br>
<input type="radio" name="Q1" value="4">Moderately Accurate<br>
<input type="radio" name="Q1" value="5">Very Accruate<br>
<p>2. Item 2.<p>
<input type="radio" name="Q2" value="1">Very Inaccurate<br>
<input type="radio" name="Q2" value="2">Moderately Inaccurate<br>
<input type="radio" name="Q2" value="3">Neither Accurate or Inaccurate<br>
<input type="radio" name="Q2" value="4">Moderately Accurate<br>
<input type="radio" name="Q2" value="5">Very Accruate<br>
<p>3. Item 3.<p>
<input type="radio" name="Q3" value="1">Very Inaccurate<br>
<input type="radio" name="Q3" value="2">Moderately Inaccurate<br>
<input type="radio" name="Q3" value="3">Neither Accurate or Inaccurate<br>
<input type="radio" name="Q3" value="4">Moderately Accurate<br>
<input type="radio" name="Q3" value="5">Very Accruate<br>
Assume the following responses
Q1: '1'
Q2: '2'
Q3: '3'
How do I insert this into my DB model as '123' rather than having a model that requires me to enter '1' into a variable q1, '2' into a variable q2, and '3' into a variable q3, etc.
Thanks!

To get you in the right direction. Either create a Question model with a name and a charfield of options. Your form would be created using a ModelForm. That way Django does most of the work for you.
An alternative is to use an external package. django-domande seems like a good survey app.

Related

How can I keep form values without using session?

I have one form page with pagination. I want to keep the form values as the user goes to the previous or next page, using pagination. I know that it can be done using the session scope. However, here I don't want to use session scope. Does anyone have any ideas on how to do this without using session? Please let me know.
Here is my form page:
<cfoutput>
<form action="#buildUrl(action='survey.save_surveyresults',querystring='surveyId=#rc.surveyid#')#" method="post">
<input type="hidden" name="id" value="0">
<input type="hidden" name="surveyid" value="#rc.surveyId#">
<div class="container-fluid">
<div class="row">
<div class="control-group">
<label class="label-control" for="name">Name</label>
<div class="controls">
<input type="text" name="name" id="name" required="true" placeholder="enter your name" value="#rc.name#">
</div>
</div>
<div class="control-group">
<label class="label-control" for="email">Email</label>
<div class="controls">
<input type="text" name="email" id="email" required="true" placeholder="enter your Email" value="#rc.email#">
</div>
</div>
<cfloop query="rc.questions" startrow="#startrow#" maxrows="#perpage#">
<!--- because we have all questions and answers in query we can use switch instead calling template or view
for each question, so its simplify directory structures, questions directory is not necessary now --->
<h3>#CurrentRow#<cfif rc.questions.isrequired><strong>*</strong></cfif>. #rc.questions.question#<h3>
<cfswitch expression="#rc.questions.template#">
<fieldset>
<cfcase value="textbox">
<input type="text" class="input-xlarge" name="#template#_#questionid#" id="question_#questionid#">
</cfcase>
<cfcase value="multiplechoice">
<cfloop list="#answer#" delimiters="," index="i">
<div class="controls">
<label>
<input type="radio" name="#template#_#questionid#" id="question_#questionid#" value="#answerID#" >
<span class="lbl">#i#</span>
</label>
</div>
</cfloop>
</cfcase>
<cfcase value="multiplechoiceother">
<cfloop list="#answer#" delimiters="," index="i">
<div class="controls">
<label>
<input type="radio" name="#template#_#questionid#" id="question_#questionid#" value="#answerID#" >
<span class="lbl">#i#</span>
</label>
</div>
</cfloop>
<div class="control-group">
<label class="label-control" for="other">Other</label>
<div class="controls">
<input type="text" class="input-xlarge" name="#template#_#questionid#" id="question_#questionid#">
</div>
</div>
</cfcase>
</fieldset>
</cfswitch>
</cfloop>
<p></p><br />
<cfif startrow GT 1>
Previous
</cfif>
<cfif (startrow + perpage - 1) lt rc.questions.recordcount>
Next
<cfelse>
<button type="submit" name="submit" class="btn btn-success">Finish</button>
</cfif>
</div>
</div>
</div>
</form>
</cfoutput>
You could break the form up into different sections and have it all in one page. You can hide/show parts of the form using JavaScript based on which 'page' of the form they are one.
This makes going forward or backward in the form a snap since it is not submitted until they are done with the whole form and the values they entered will still be there.. and is pretty easy to handle with jQuery or other JavaScript libraries.
As Dan said - save submitted values in hidden fields.
One issue I see with your HTML is that Previous/Next pages are just links - not submit buttons. So make sure that when clicking those links users are submitting the form - not just going to a different url.
Here's a simple snippet of code that will embed all your form variables into hidden fields. You would place this code inside the form handler on the page you are submitting to. Note Lucas' answer as well. Your form may not be submitting correctly for reasons of badly formed..er...form.
<Cfloop collection="#form#" item="fItem">
<cfoutput>
<input type="hidden" name="#fItem#" value="#form[fItem]#"/>
</cfoutput>
</cfloop>
Again .. this would go _inside" of the form on the subsequent page. This is fairly common in multipart forms (shopping carts with multiple steps, profile entries etc).
Bear in mind that with the approaches above, you need to re-validate your form values on the server side every time you submit them (or at the very least before your final processing).
What you make up for in server memory, you may lose in terms of traffic and load times, depending on scale so I would advise that you proceed with caution. Increasing production traffic unnecessarily can result in financial impacts, and often server memory can be cheaper than extended increased traffic outlay; it comes down to your requirements and scale at the end of the day.
Shipping form variables around also increases your attack surface for malicious injection of form data, so while you may be concerned with session variables being altered on you (curious to hear more on this), you are already opening yourself up by shipping this data around as plain text. Do not rely on client-side validation for this (or any) data.

Accessing variables of a dynamic form

I am creating a form with cfloop and need to access each variable individually when submitting the form. I need to use the selected entries of the form in a loop that will add my selections to a database.
This is my form:
<form method="post">
<input type="hidden" name="isPost" value="1">
...
<cfoutput>
<cfloop query="client_admin_surveys">
<input type="text" size="35" name="surveyID" id="surveyID" value="#id#">
<input type="text" size="35" name="surveyName" id="surveyName" value="#name#">
<input type="checkbox" name="amplify" id="amplify">
<input type="checkbox" name="enchance" id="enchance">
<input type="checkbox" name="pacify" id="pacify">
<input type="checkbox" name="pacifyUrgent" id="pacifyUrgent">
</cfloop>
</cfoutput>
...
<input type="submit" name="submit" value="Submit">
</form>
After posting the form, the results group all of my selections because I have the same "name" for my form elements. I tried adding an i count next to each name to make it different but then I got a bit confused about how to process the fields.
You started down the correct path when you added the counter - go back and add that, something like:
<input type="checkbox" name="amplify#client_admin_surveys.currentRow#" id="amplify">
Would work.
I also sometimes like to add a form field for the 'counter' on the processing page
<input type="hidden" name="counter" value="#client_admin_surveys.recordCount#" />
Then on the processing page, you can loop over the counter and access the form fields using bracket notation
<cfloop from="1" to="#form.counter#" indexd="i">
<cfset thisAmplify = form["amplify" & i] />
<cfset thisEnhance = form["enhance" & i] />
<!---- more logic here --->
</cfloop>

How to make Chrome respect the names of my fields and not attempt to autocomplete

I have two different forms on my home page: one for logins and one for registrations. As you can see from the code, the forms have inputs with different names:
<h3> Log In </h3>
<form action="/login/" method="POST" class="form-vertical" style="padding-top: 5px">
<input id="id_login_username" type="text" name="login_username" maxlength="25" />
<input type="password" name="login_password" id="id_login_password" /><br>
<button type="submit" class="btn btn-info">Login</button>
</form>
<h3> Sign Up <small>(It's free!)</small></h3>
<form action="/register/" method="POST" class="form-vertical" style="padding-top: 5px">
<input id="id_register_username" type="text" name="register_username" maxlength="25" />
<input type="text" name="register_email" id="id_register_email" />
<input type="password" name="register_password" id="id_register_password" />
<input type="password" name="register_password2" id="id_register_password2" /><br>
<button type="submit" class="btn">Submit</button>
</form>
Which renders to this in Chrome:
What can be causing this? And how can I fix it?
That's a really good question and I'm sorry to say I have no idea. Did
you try to register once and also login at least once? If so, that
"might" be what's causing it as browsers come complete with the
"autoremember" feature.
Assuming autofill is enabled (it is by default), the reason it autofills the rest is because chrome's autofill server works on regular expressions, not exact matches.
All the regular expressions used for the various fields can be found in autofill_regex_constants.cc.utf8.
From there you can see that the expression for email field is "e.?mail" and for username it is "user.?name|user.?id|nickname|maiden name|title|prefix|suffix"
It appears a similar question has been asked before:
What is the correct way to stop form input boxes auto-completing?
There is an autocomplete attribute you can use in form fields.
<input id="id_login_username" type="text" name="login_username" maxlength="25" autocomplete="off" />

How to get checked value by cfloop in coldfusion

How can I get the checked values from some checkboxes using cfloop in coldfusion?
The checkboxes are created dynamically from a database query. ie:
<cfloop query="GetDataMaterial">
<input type="checkbox" name="MaterialID" value="#MaterialID#" />
</cfloop>
The form field will contain a comma-separated list of all values that are checked with the same form name.
For instance:
<input type="checkbox" name="MaterialID" value="1">
<input type="checkbox" name="MaterialID" value="2">
<input type="checkbox" name="MaterialID" value="4">
<input type="checkbox" name="MaterialID" value="8">
<input type="checkbox" name="MaterialID" value="16">
<input type="checkbox" name="MaterialID" value="32">
If the user Checks all of them, you'll get, assuming your form does a post:
form.MaterialID: "1,2,4,8,16,32"
If the user checks the first and last, you'll get
form.MaterialID: "1,32"
So, if you want to loop over them, you can
<cfloop list="#form.MaterialId#">
...
</cfloop>
Don't forget to have index="i" and use it to loop through the list of checkbox
<cfloop list="#form.MaterialId#" index="i">
<cfoutput>#i#</cfoutput>
</cfloop>

Django nested formsets

I have an edit object view that contains a formset(one or many if this matters), now I want to create a page that can display multiple edit object forms and submit it in a single form.
What is the correct way to achieve this task?
I found a solution.
I can enumerate my objects on edit page and use different prefixes for formsets based on these indexes. Here is an example:
First, you need enumeration, I achieved it using same input(checkbox) name with incremental values:
<input type="checkbox" name="counter" value="0">
...
<input type="checkbox" name="counter" value="1">
...
Counter numbers is the formset and other data serial numbers:
<!--Ordinary inputs-->
<input type="text" name="data0" value="value0">
<input type="text" name="data1" value="value1">
<!--Formsets-->
<input type="text" id="test0-0-data" name="test0-0-data" value="something">
<input type="text" id="test0-1-data" name="test0-1-data" value="something">
<input type="hidden" name="test0-TOTAL_FORMS" id="id_test0-TOTAL_FORMS" value="2">
<input type="hidden" name="test0-INITIAL_FORMS" id="id_test0-INITIAL_FORMS" value="0">
<input type="text" id="test1-0-data" name="test1-0-data" value="something">
<input type="hidden" name="test1-TOTAL_FORMS" id="id_test1-TOTAL_FORMS" value="1">
<input type="hidden" name="test1-INITIAL_FORMS" id="id_test1-INITIAL_FORMS" value="0">
Then if code you populate formsets like this:
counter = request.POST.getlist('counter')
for i in counter:
TestFormset = modelformset_factory(Test, form=TestForm)
test_formset = TestFormset(request.POST, prefix='test'+i, queryset=Test.objects.none())
I achieved HTML structure above with JavaScript.