Git Product home page Git Product logo

questions's Introduction

Questions

Documentation Status

Questions is a Python form library that uses the power of SurveyJS for the UI. The philosophy behind Questions is that modern form rendering usually requires integrating some complex Javascript widgets anyway, so why not skip the markup generation completely?

https://www.delaguardia.com.mx/questions.gif

In Questions, forms are defined in Python similarly to other form frameworks, but everything on the front end is handled by SurveyJS. This provides a lot of benefits:

  • Nice, integrated UI, with powerful Javascript widgets.
  • SurveyJS is compatible with Angular2, JQuery, KnockoutJS, React and VueJS. Questions makes sure that you get the right files for each version.
  • More than 20 question types, from simple text inputs and dropdowns to elaborate widgets like dynamic panels and checkbox matrices.
  • Multiple look and feel options (themes), including Bootstrap CSS support.
  • Full client side validation (plus server side checking, too).
  • Use simple text expressions in question declarations to control which questions to show depending on the answers to previous ones.
  • Complex forms can be defined easily using class composition.
  • Easy multi-page forms, with no state-keeping headaches.
  • Create forms directly from JSON definitions using SurveyJS form creator.
  • Generate Python code from dynamic JSON import.
  • Minimal code for simple apps. If you just need a form or two, you are set.
  • Zero Javascript code option. If you can use a CDN, no need to install or download any javascript.
  • Out of the box integration with popular third party widgets, like select2 and ckeditor.
  • Supports the creation of tests and quizzes, by defining "correct" answers to the questions, and optionally setting a maximum time to finish.

How the Code Looks

To get a feel for how Questions works, nothing better than looking at a simple example:

from questions import Form
from questions import TextQuestion
from questions import RadioGroupQuestion


class SimpleForm(Form):
    name = TextQuestion()
    email = TextQuestion(input_type="email", required="True")
    favorite_number = TextQuestion(title="What is your favorite number?",
        input_type="number")
    language = RadioGroupQuestion(title="Favorite Language",
        choices=["Python", "Other"])
    version = RadioGroupQuestion(title="Preferred Python Version",
        choices=["Python 2", "Python 3"],
        visible_if="{language} = 'Python'")

This is a fairly conventional way to define forms, so no surprises here, but look at the way the input_type parameter allows us to use different HTML5 text input methods. Pay special attention to the last line, where we use the visible_if parameter to only show the Python version question if the answer to the language question is "Python". Defining "live" form behavior in this way is something that is usually out of scope for server side code, but Questions' SurveyJS integration allows us to do it.

Full Working Multi-page Flask Application

Let's show how easy things can be if your applications needs are simple. The following is a complete application using the popular Flask web framework:

from flask import Flask
from flask import redirect
from flask import request

from questions import Form
from questions import FormPage
from questions import TextQuestion
from questions import DropdownQuestion


class PageOne(Form):
    name = TextQuestion()
    email = TextQuestion(input_type="email", required="True")


class PageTwo(Form):
    country = DropdownQuestion(choices_by_url={"value_name": "name",
        "url": "https://restcountries.eu/rest/v2/all"})
    birthdate = TextQuestion(input_type="date")


class Profile(Form):
    page_one = FormPage(PageOne, title="Identification Information")
    page_two = FormPage(PageTwo, title="Additional Information")


app = Flask(__name__)

@app.route("/", methods=("GET",))
def form():
    form = Profile()
    return form.render_html()

@app.route("/", methods=("POST",))
def post():
    form_data = request.get_json()
    # Here, we would save to a database or something
    print(form_data)
    return redirect("/thanks")

@app.route("/thanks")
def thanks():
    return "Thanks for your information"

if __name__ == "__main__":
    app.run()

By default, Questions uses a CDN for fetching the Javascript resources, which is why all that is needed to run the above code is installing Flask and Questions. Of course, it is possible to install all the dependencies yourself and configure Questions to use your installation, but sometimes this is all that's required to get a full working application.

Admittedly, our application doesn't do much, but we get a working form that you can fill and submit in your browser. See how easy it is to get a multi-page form with navigation buttons. Also, notice how get_json is the only Flask request call we need to get the form data.

As the code shows, defining a multiple page form is very simple, and allows us to keep the form pages logically separated, and even using them independently or in combination with other forms with little additional work.

Finally, take a look at the choices_by_url parameter in the DropdownQuestion, which allows us to get the dropdown choices from separate, restful web services.

License and Documentation

Credits

This package was created with Cookiecutter and the audreyr/cookiecutter-pypackage project template.

questions's People

Contributors

cguardia avatar joan-qida avatar pyup-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

questions's Issues

default_value has no effect for DropdownQuestion

Hello! I have encountered an issue with using the default_value parameter in the questions package. When using this parameter for DropdownQuestion type questions, it does not apply and the default selected value is not displayed.

Here's a minimal code example that demonstrates this issue:

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from questions import DropdownQuestion, Form, FormPage
import uvicorn

class Page(Form):
    person = DropdownQuestion(
        title="Full name",
        choices=["George Corbyn", "Stanley Castillo", "Ida Stanley"],
        default_value="Stanley Castillo",
    )

class Profile(Form):
    page = FormPage(Page, title="Author")

def form():
    html = Profile().render_html()
    return HTMLResponse(html)

if __name__ == "__main__":
    app = FastAPI()
    app.get("/")(form)
    uvicorn.run(app, host="0.0.0.0", port=8888)

In this example, the default_value has no effect, and the default selected value "Stanley Castillo" is not set in the dropdown list.
I have also tested this issue with other question types that inherit from ChoicesQuestion, and they also do not apply the default_value.

I expected that when using the default_value parameter in the DropdownQuestion definition, the default selected value would be displayed in the input field.

Env:
questions package version: 0.8.0
Python version: 3.11
Operating system: Linux

Default value in question

  • Questions version: Latest
  • Python version:
  • Operating System: windows 10 pro

Description

Hi! I use Question to administer a questionnairse with most of the questions are not required or mendatory. So if some one doesn't respond to a couple of questions, I end up with no variables name for these questions in my csv dataframe.

I'm wondering is there a way to have default values il all the questions?

Thanks Carlos

Installation doc is incomplete ?

  • Questions version: 0.5.0a2
  • Python version: 3.7.0
  • Operating System: Mac OS 10.13.6

Description

I try to get the simple "Full Working Multi-page Flask Application" from README working.
form.py contains this code (in my example).

What I Did

virtualenv-3.7 .
bin/pip install flask
bin/pip install questions
export FLASK_APP=form.py
bin/flask run

I needed to install typing-extensions, which is not in documentation and causes traceback at flask startup : ModuleNotFoundError: No module named 'typing_extensions'

bin/pip install typing-extensions

Then, flask can start, but accessing http://127.0.0.1:5000/ causes this traceback:

 * Serving Flask app "form.py"
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[2020-12-10 22:53:39,162] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/laurent/instances/questions/form.py", line 32, in form
    return form.render_html()
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/form.py", line 376, in render_html
    survey_js = self.render_js(form_data=form_data)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/form.py", line 357, in render_js
    platform=self.platform,
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/templates.py", line 123, in get_survey_js
    html_id=html_id,
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/templates.py", line 28, in _render_template
    template = env.get_template(filename)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/jinja2/environment.py", line 883, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/jinja2/environment.py", line 857, in _load_template
    template = self.loader.load(self, name, globals)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/jinja2/loaders.py", line 115, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/jinja2/loaders.py", line 249, in get_source
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: survey_js.jquery.jinja
127.0.0.1 - - [10/Dec/2020 22:53:39] "GET / HTTP/1.1" 500 -

What step is missing here to get this survey_js.jquery.jinja ? I can help for completing the documentation ...

The `visible_if` condition does not work in dynamic panels

I want to be able to optionally display fields in dynamic panels. But the display predicate visible_if doesn't work in the dynamic panel. I expect that in the example below, the SocialMediaForm.account field should only appear when the service field of the dynamic panel element is set to 'Instagram'. I've tried every possible way to make the condition in the visible_if str, but I still can't achieve the expected behavior. All my attempts have resulted in either the account field always visible or not being displayed in the form. How can I solve this problem?

from flask import Flask, redirect, request

app = Flask(__name__)

from questions import (
    DropdownQuestion,
    Form,
    FormPage,
    FormPanel,
    TextQuestion,
)


class SocialMediaForm(Form):
    service = DropdownQuestion(choices=["Twitter", "Instagram", "Snapchat"])
    account = TextQuestion(visible_if="{service} == 'Instagram'")


class ProfileForm(Form):
    social_media = FormPanel(
        SocialMediaForm,
        title="Social Media Accounts",
        dynamic=True,
        panel_count=1,
    )


class Survey(Form):
    mainpage = FormPage(ProfileForm, title="Main")


@app.route("/", methods=("GET",))
def form():
    form = Survey()
    return form.render_html()


@app.route("/", methods=("POST",))
def post():
    data = request.get_json()
    print(data)
    return redirect("/")


if __name__ == "__main__":
    app.run()

Panels seem to be broken

  • Questions version: latest
  • Python version: 3.8
  • Operating System: mac OS

Description

When i try the panels example from the docs i get the following error thrown when the .render_html() function is called on the final ProfileForm class object: {AttributeError}'Survey' object has no attribute 'questions'

Switching between themes has lost its relevance

The official SurveyJS website says that some of the names for the themes are out of date. These themes are defined in questions.settings.SURVEY_JS_THEMES, but questions.templates.get_theme_css_resources function does not support them. Since these themes are obsolete, it would probably be wise to disable their support altogether. What is really missing, however, is support for the modern DefaultV2 theme. At the moment I was able to implement its support, with a very simple stub:

from questions import Form

class FormDefaultV2(Form):
    @property
    def required_css(self):
        return ["https://unpkg.com/survey-core/defaultV2.min.css"]

The survey form looks and works great.

Using triggers

Is it possible to implement SurveyJS triggers using this package?

Signature pad widget doesn't work

  • Questions version: 0.5.0a2
  • Python version: 3.7.0
  • Operating System: Mac OS 10.13.6

Description

I try to use Signature pad widget from SurveyJS in my form.

What I Did

Use this JSON:

{
 "pages": [
  {
   "name": "page1",
   "elements": [
    {
     "type": "signaturepad",
     "name": "question1",
     "title": "Signature"
    }
   ]
  }
 ]
}

The widget appears in the form but does nogthing : I can't use it as I can on SurveyJS "Test Survey".

Prevent sending requests to the central survey-js server

Defining the survey_id and survey_post_id arguments when creating the questions:Survey results in interstep communication with the server api.surveyjs.io.

Specifying survey_id attempts to retrieve the survey form:
https://api.surveyjs.io/public/v1/Survey/getSurvey?surveyId=123
If you specify survey_post_id, a post request is sent with the results of filling out the form:
https://api.surveyjs.io/public/v1/Survey/post/

Is there any way to send the form with these parameters to its own post handler? Apparently, the post request generated for the official api uses its own code to generate the request body. Is it possible to get the results of the form on its own side in the way that this data is defined in the survey-js framework? Perhaps the structure of the responses they generate is more correct than the one defined in the js-templates, I would like to be able to process the form results as defined by the framework developer.

BUG: survey generated gives a blank page, probably because surveyjs.azureedge.net is no longer available

  • Questions version: stable
  • Python version: 3.10.3
  • Operating System: mac os catalina

Description

My survey is not showing up.
Even if I run the simple flask app demo code from the documentation, when I run the app and open the web address, there is a blank page.
When I inspect the page, I can see the surveyjs elements. However the page is blank.

image

What I Did

there are no errors in the code are the flask app

I disabled all extensions, turned off any protection/blocking feature and tried multiple web browsers and multiple development environments.
But the problem persists.

any idea on whats going on?

The same code worked two months ago.

Multilingual survey causes traceback

  • Questions version: 0.5.0a2
  • Python version: 3.7.0
  • Operating System: Mac OS 10.13.6

Description

I try to use a multilingual SurveyJS form.

What I Did

Use this JSON:

{
 "pages": [
  {
   "name": "page1",
   "title": {
    "default": "Title",
    "fr": "Titre"
   }
  }
 ]
}

When displaying the form, I get this traceback:

  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/form.py", line 322, in js
    return self.required_js + self.extra_js
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/form.py", line 292, in extra_js
    self._construct_survey()
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/form.py", line 217, in _construct_survey
    self._add_elements(survey, self, top_level=True)
  File "/Users/laurent/instances/questions/lib/python3.7/site-packages/questions/form.py", line 238, in _add_elements
    page = Page(name=name, **element.params)
  File "pydantic/main.py", line 362, in pydantic.main.BaseModel.__init__

pydantic.error_wrappers.ValidationError: 1 validation error for Page
title
  str type expected (type=type_error.str)

Change language of the forms

  • Questions version: Latest version
  • Python version: 3.9
  • Operating System: conda in windows 10

Hi Carlos, I love the tool you developed. I'm wondering how can I change the language of the forms let say from English to French?

Thanks a lot

ReadMe example broken

  • Questions version: latest
  • Python version: 3.9
  • Operating System: MAC OS

Description

The example in the read me and the docs does not work any more. When i try to run it. The web page just says: The survey doesn't contain visible pages or questions.

Integration with surveydown

Hi! This isn't an issue but rather an initial conversation to see if you might be interested in joining forces towards a common goal of building an open-source survey platform. I've had this idea in mind for years, but just haven't gotten around to building it because I couldn't find the right platform to build it in. So instead I wrote my thoughts down in this blog post. If you read through it you'll see the connections between questions and what I have in mind.

You'll see in my post that I found a way to do something close to it using an R Shiny app, but questions looks very, very promising! You've basically done more than half the work. All that's left for what I had in mind was to build a different UI for the user. Rather than have a user define pages as functions, I'm envisioning users being able to define a survey using mostly just markdown text (something like this) along with a questions.yml file (something like this). That allows users to define their entire survey in a more literate way (more like writing a paper), and then the package will do the rest to translate that into code that renders into a survey.

SurveyJS seems like the ideal tool for this, but having a python interface to using it is absolutely key. Really love what you've got here. Over the summer I'm going to try to play around with it to see if I can build something similar to what I describe in my blog post. Would appreciate any thoughts / suggestions you have, or even direct contributions if this sounds interesting to you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.