Skip to content

Advanced usage

OpenQuestion's GUI can handle standard survey development and therefore this section is only intended for more advanced use cases. Where noted, certain topics are relevent only to OpenQuestion's administrator(s).

Accessing the Python Shell (for administrators)

From the command line (where the OpenQuestion is below the current directory) run the app server with the --shell option. This will drop you into a Python interpreter that has access to OpenQuestion's priviledged code and database.

anvil-app-server --app OpenQuestion --shell

Accessing the Python Shell (for survey developers)

Developers can also interact with OpenQuestion's server code and databases from Python. The administrator must first generate a token (a so-called Uplink key) and associate it with OpenQuestion as follows:

 anvil-app-server --app OpenQuestion --uplink-key <you-secret-key>

Admins, be careful when creating an Uplink key

Uplink keys should be long, secure, and random. Do not share the key with anyone except for those who you want to have access to OpenQuestion's privileged server code and databases

Developers can now connect to OpenQuestion with Python code by following these steps:

pip install anvil-uplink
import anvil.server

# connecting to OpenQuestion
anvil.server.connect("[uplink-key goes here]", url="ws://your-runtime-server:3030/_/uplink")

Once sucessfully connected, developers will have priviledged access to OpenQuestion's server code and databases from their Python environment.

JSON representation of surveys

OpenQuestion represents surveys as a Python dictionary (stored as a JSON object in the backend database). The following two examples show the dict representation of two surveys: one that is simple, followed by one that is more complex. By studying these structures, one can learn how to create and modify surveys programatically (also, see the sections pertaining to working with the Forms table).

In general, the survey dict is a nested, somewhat self-similar structure. For example,

  • The survey itself contains sections (a type of widget)
  • Sections contain the typical UI widgets (e.g., text_box, drop_down, etc)
  • The UI widgets contain all of the properties set in the survey designer (title, placeholder, mandatory flag, branching logic, etc)
Simple survey (click)
my_survey={
  "title": "simple survey",
  "settings": {
  "survey_color": "#2196F3",
  "thank_you_msg": "#Thank you!"
  },
  "num_widgets": 2,
  "widgets": [
    {
      "id": 0,
      "type": "section",
      "logic": None,
      "title": "section",
      "widgets": [
        {
          "id": 1,
          "type": "text_box",
          "logic": None,
          "title": "what's your name?",
          "number": False,
          "mandatory": True,
          "placeholder": "placeholder here"
        }
      ]
    }
  ]
}
A more complex survey (click)
my_survey={
  "title": "science survey",
  "settings": {
  "survey_color": "#2196F3",
  "thank_you_msg": "#Thank you!"
  },
  "num_widgets": 22,
  "widgets": [
    {
      "id": 0,
      "type": "section",
      "logic": None,
      "title": "About you",
      "widgets": [
        {
          "id": 1,
          "text": "This is a survey about **you** and **science**.\n\nFor more information about science click [here](https://en.wikipedia.org/wiki/Science).\n\n- these \n- are \n- bullets\n\nThis is scientifically proven to be the cutest image:\n\n<img src=\"https://i.imgur.com/gPb2phg.gif\" width=\"191\" height=\"200\">\n\n",
          "type": "markdown",
          "logic": None,
          "title": "",
          "placeholder": "markdown supported"
        },
        {
          "id": 2,
          "type": "text_box",
          "logic": None,
          "title": "What is your name?",
          "number": False,
          "mandatory": False,
          "placeholder": "name goes here"
        },
        {
          "id": 7,
          "type": "date",
          "logic": None,
          "title": "What is your date of birth?",
          "format": "%Y-%m-%d",
          "mandatory": False,
          "placeholder": "date goes here"
        },
        {
          "id": 3,
          "type": "text_area",
          "logic": None,
          "title": "Tell me about yourself",
          "placeholder": "text goes here"
        },
        {
          "id": 4,
          "type": "drop_down",
          "logic": None,
          "title": "What is your highest completed educational level?",
          "options": "high school diploma\ncollege diploma or university degree\nI have do not have a high school diploma",
          "mandatory": True,
          "placeholder": "select from here"
        },
        {
          "id": 11,
          "type": "radio_button",
          "logic": None,
          "title": "Are you interested in science?",
          "options": "Yes\nNo"
        }
      ]
    },
    {
      "id": 5,
      "type": "section",
      "logic": None,
      "title": "About you and science",
      "widgets": [
        {
          "id": 8,
          "type": "check_box",
          "logic": None,
          "title": "Which scientific topics are you interested in? (check all that apply)",
          "options": "mathematics\ngeography\ndata science\nstatistics\nphysics\nneuroscience"
        },
        {
          "labels": "not satisfied\nmeh\nvery satisfied",
          "min_val": "0",
          "value": "50",
          "type": "slider",
          "title": "How satisfied were you with your last science course? ",
          "id": 10,
          "logic": None,
          "step": "1",
          "max_val": "100"
        },
        {
          "id": 12,
          "type": "text_area",
          "logic": {
            "func": "any",
            "conditions": [
              {
                "id": 10,
                "title": "How satisfied were you with your last science course? ",
                "value": 40,
                "comparison": "<"
              }
            ]
          },
          "title": "In your opinion, what would improve science education?",
          "placeholder": "Explain here"
        }
      ]
    }
  ]
}

Using the Forms table

The Forms table contains all surveys that are created in OpenQuestion.

Interacting with tables

For more information on the the API used for interacting with tables, please see Anvil's DataTables documentation.

The Forms table has the following columns:

  • form_id: A long, random, secure, and unique string
  • title: The survey title
  • last_modified: A Python datetime object
  • schema: A JSON representation of the survey's structure (does not contain submission data)
  • submissions: A CSV media object which accumulates submissions
  • opening_date: A Python datetime object for an opening date
  • closing_date: A Python datetime object for an closing date

Adding a survey

The following example demonstrates how to programatically add a survey to the Forms table.

from anvil.tables import app_tables

my_survey={
  "title": "simple survey",
  "settings": {
  "survey_color": "#2196F3",
  "thank_you_msg": "#Thank you!"
  },
  "num_widgets": 2,
  "widgets": [
    {
      "id": 0,
      "type": "section",
      "logic": None,
      "title": "section",
      "widgets": [
        {
          "id": 1,
          "type": "text_box",
          "logic": None,
          "title": "what's your name?",
          "number": False,
          "mandatory": True,
          "placeholder": "placeholder here"
        }
      ]
    }
  ]
}

app_tables.forms.add_row(
    form_id='you secure survey ID', # A long, random, secure, and unique string
    title='simple survey', 
    schema=my_survey, # A Python dictionary following OpenQuestion's expected format
    submissions=None,
    opening_date=None,
    closing_date=None)

Deleting a survey

The following example demonstrates how to programatically delete a survey from the Forms table.

from anvil.tables import app_tables

# Searching based on title property but any other search parameter can be used. 
# See Anvil's Datatable documentation https://anvil.works/docs/data-tables/data-tables-in-code
row=app_tables.forms.get(title='simple survey')
row.delete()

Modifying a survey

The following example demonstrates how to programatically modify a survey from the Forms table.

from anvil.tables import app_tables

row=app_tables.forms.get(title='simple survey')

# modifying the survey's title
row['title']='My new title'

Using the Users table

OpenQuestion stores developer and administrator information in the Users table. Note that users in this case refers to survey developers and app admins (not end users who fill out the survey).

Adding a user

Please see this section on adding developers and admins as users in OpenQuestion.

Deleting a user

Users can be deleted from the Users table as follows:

# get a user from the Users table
some_user=app_tables.users.get(email='your_username@example.com')
some_user.delete()

Adding data to submissions using query strings:

OpenQuestion allows survey developers to add additional data to a submission by accepting a query string in the survey's URL.

For example, in addition to the form's ID, the following survey passes foo=42, along with the data that is inputted by an end user, to the submissions table.

https://your-app-url/#?form_id=<uuid>&foo=42

This example adds another parameter to the query string. That is, it also passes bar=baz to the submission's table.

https://your-app-url/#?form_id=<uuid>&foo=42&bar=baz

When an end user submits a response, a new column is created for every parameter in the query string and the new row in the submissions table will contain the value(s). When a parameter matches an existing column header in the submissions table, the parameter's value is merged (a new column is not created). Note that query strings can be unique to each submission since new parameters are added as new columns.