Home > wq Framework > wq Configuration Object

wq Configuration Object

The wq Configuration object describes the global settings and navigation structure of a wq-powered website/app and its corresponding REST API. The configuration object is typically generated by the Python service (wq.db) and provided to the JavaScript client (wq.app) in order to set common expectations on the layout of the application.

The basic format of the wq Configuration Object is:

{
    // Global Settings
    "site_title": "[Project Name]",
    "logo": "/path/to/logo.png",
    "material": {
        "theme": {
            "primary": "#7500ae",
            "secondary": "#0088bd"
        }
    },
    "map": {
        "bounds": [[-180, -70], [180, 70]]
    },

    // Navigation Structure
    "router": {
        "base_url": ""
    },
    "store": {
        "service": "",
        "defaults": {
            "format": "json"
        }
    },
    "pages": {
        "[model_name]": {
            "list": true,
            "url": "[model_name]s",
            "form": [...]
        },
        "[simple_page]": {
            "url": "[simple_page]"
        }
    }
}

In the default project layout, wq.db exports the configuration object to the JavaScript module app/js/data/config.js. This module is imported by app/js/[myproject].js which passes it along to wq.init().

Global Settings

The following configuration options can be set by updating the corresponding WQ_CONFIG key (which is defined in db/[myproject]/settings/base.py in the default layout.)

Option Description
logo Path to image to to display in site Header
site_title Title to display in Header and browser title bar. (Defaults to settings.PROJECT_NAME)
backgroundSync Whether to sync form submissions in the background (true, default) or wait until the form is submitted before navigating (false). Can be overridden on a per-page basis.
debug Enable debug mode in @wq/router and other modules. (Defaults to settings.DEBUG)
material Configuration for @wq/material including site theme
map Configuration for @wq/map including default geographical bounds
[plugin name] Configuration options for other registered plugins.

Navigation Structure

In addition to the global settings, the wq configuration object also describes the URL structure of the application. This is done through the following sections:

Option Description
router Configuration for @wq/router, including the base url of the application (if not at website root URL.)
store Configuration for @wq/store, including the service URL for the REST API (if not also at website root URL.)
pages Page-specific configuration for all registered models and routes.

These three sections of the wq configuration object are generated by wq.db automatically, and should not be specified manually except in advanced use cases. Page-specific configuration can be supplied when registering models and pages with the router, as described below.

Page Registration

The primary configuration section in the wq configuration object is pages, which contains detailed information about the URL structure of the application. For example, the pages configuration is used by @wq/app to map URL requests to page templates to render, and also to provide hints to @wq/store and @wq/model as to the structure of the REST API containing the actual data.

As its name implies, the pages section summarizes all of the available “pages” in the application. The section is a mapping of page “names” to simple configuration objects describing each respective page. Pages fall into two categories depending on whether or not they are backed by a database table (i.e. ORM model in a Django application).

  • Pages backed by a database table are indicated with "list": true. The name of these pages is the name of the underlying database model. Marking a page as "list": true implies the presence of list, detail, and edit views for a database entity - all with corresponding URLs defined relative to the url property defined for the page. List pages are configured in wq.db with rest.router.register_model().
# myapp/rest.py
from wq.db import rest
from .models import MyModel
rest.router.register_model(
    MyModel,
    fields="__all__",
    
    cache="all", # wq configuration
    
    my_custom_flag=True, # Custom configuration
)
  • Pages without a corresponding model do not have the list property set, and have only a single URL which is specified by the url property. By convention, the name of these pages is usually the same as the URL. These pages are configured in wq.db with rest.router.add_page().
# myapp/rest.py
from wq.db import rest

rest.router.add_page("about", {"url": "about"})

The full listing of page configuration options is described below.

General Options

Name Usage
list Boolean; set automatically by register_model. Sets whether or this is a list page or a simple page. If true, a minimum of three routes will be generated: [model_name]_list, [model_name]_detail, and [model_name]_edit. If false or unset, it there will be a single route with the same name as the page.
url The URL of the page. For simple pages, this is conventionally the same as the name of the page. For list views, it is typically the verbose plural name of the model (without spaces). The list view will be rendered at [url]/, while detail and edit views will be constructed from this value as [url]/[item_id] and [url]/[item_id]/edit, respectively.
name The name of the page, usually based on the model class name. Must be unique in the configuration; if two models have identical class names this property can be overridden to avoid conflicts.
show_in_index Whether to link to this route in the default Index / NavMenu.
verbose_name Singular friendly name for page / model to show in navigation and Index / NavMenu.
order Relative ranking within Index / NavMenu
section Name of subheading to group related links in Index / NavMenu
icon Registered [icon] to use for link in Index / NavMenu
description Description text to use for link in Index / NavMenu
map Map configuration for the @wq/map plugin. See the @wq/map documentation for more details.

Additional Options for List Pages

As noted above, “list” pages are typically backed by ORM models which in turn correspond to database tables.

Name Usage
verbose_name_plural Plural friendly name of the model (default verbose_name + "s") to show in navigation. Set automatically by register_model.
form A representation of the model schema, in the form of an array of field definitions (see below). Set automatically by register_model.
per_page Default number of results that will be returned per page in paginated lists. This can be overridden by the limit url argument. (Note: if you are setting per_page to a high number like 1000, cache="all" might be what you really need.)
lookup Name of identifier column to use when looking up objects for detail views, and to use as the id attribute in serialized JSON data. Defaults to the model primary key.
cache Controls whether some or all of the model data is stored for offline use (see below)
background_sync Controls whether record submissions are synced in the background (while navigating), or foreground (before navigating). Defaults to the global setting.
postsave Controls which page is displayed after a record is submitted (see below).
postdelete Controls which page is displayed after a record is deleted (see below).

cache Configuration

The cache option configures which records from the model are cached for offline use (by @wq/model). Five caching modes are available:

cache= Description
"first_page" (Default) The first 50 (or per_page) items will be stored offline; subsequent records can be accessed through pagination.
"all" The entire dataset will be stored for offline use. (Useful for domain values / foreign keys)
"filter" Specify a custom filter for the offline cache. Requests for additional data are not cached and will always hit the server.
"autoupdate" An initial set of filtered records will be cached. Requests for additional data are cached and will only hit the server if no local results are found.
"none" None of the dataset will be stored offline; every list and detail view will require a network request.

Note that the "filter" and "autoupdate" options assume that a cache_filter Python function will be registered with wq.db’s router to do the actual filtering:

# myapp/rest.py
from wq.db import rest
from .models import MyModel

def user_filter(qs, request):
    if request.user.is_authenticated:
        return qs.filter(user=request.user)
    else:
        return qs.none()

rest.router.register_model(
    MyModel,
    fields="__all__",
    
    cache_filter=user_filter,
    
    # Implied:
    # cache="filter"
)

See the router registration documentation for more information about the cache_filter option and how it is interpreted by wq.db.

postsave and postdelete

By default, the next step after saving a record is to return to the list view / outbox (for background synced records) or to return to the detail view (for foreground synced records). This behavior can be customized with the postsave configuration option. postsave can take two forms: a template name, or a URL with Mustache-style placeholders.

Suppose there are two models, Site and Observation. The postsave for Observation might be any of the following:

postsave= Description
"observation_list" Return to the list of observations and outbox (default for background synced records).
"observation_detail" Return to the detail page for the current observation (default for foreground synced records).
"site_detail" Return to the detail page for the site referenced by the current observation’s foreign key.
"sites//observations" Return to the list of observations filtered by the referenced site.
"observations/new?site_id=" Start a new observation for the same site.

postdelete has similar semantics as postsave, but does not support variable placeholders or returning to detail views, since the object has already been deleted by the time the postdelete action is executed. The default for postdelete is always to return to the list view.

Form Fields

The configuration object for each list page includes an XLSForm-inspired representation of the schema for the model. This information is used by the <AutoForm/> component to automatically generate the appropriate form inputs for editing a page. Certain properties are also used by @wq/app to handle choice lookups and relationships between models.

The form attribute is an array of wq field definitions, which are JSON objects with any of the following attributes. Where applicable, the corresponding concepts in the XLSForm Question and Django Field definitions are listed.

wq Field XLSForm Question Django Field Usage
name name name Internal name for the field
type type (derived from class) XLSForm type (e.g. int, string, select1, binary. The group and repeat types are used together with the children attribute (below).
label label verbose_name User-friendly label for the field
hint hint help_text Longer description of the field or how the user should populate it
bind.required bind.required (opposite of null) Whether the field is required or optional. The format bind: {required: true} is for compatibility with the XLSForm syntax.
wq:length n/a max_length Maximum allowed length for string fields
choices choices (derived from choices) An array of valid choices for enum-style fields on the model in the format {'name': '(user-friendly name)', 'value': '(internal value)'}. This information is surfaced in the [model_name]_edit [rendering context] as [field_name]_choices, with a selected flag set on the currently selected option when editing an existing record.
wq:ForeignKey n/a (derived from model name) This is used by @wq/app to automatically retreive a list of choices from the referenced model when rendering a form. The list of potential parent records is surfaced in the [model_name]_edit [rendering context] as [field_name]_list, with id and label attributes for each record in the parent model, and a selected flag set on the currently selected parent when editing an existing record. Note that the referenced model should also be registered in the configuration object for all of this this to work.
filter n/a n/a An optional filter to apply to the list of potential parent records referenced by a ForeignKey. This is passed to model.filter() on the parent model.
children children (c.f. related_name and inline formsets) This defines a nested list of fields that represent sub-observations or a “tall schema” structure. The structure is an array of fields in the same format as the top-level form array. If the field type is group, the nested fields will be repeated once in the form. If the field type is repeat, the fields can be repeated multiple times, with a button to add additional sub-observations. The nested observations would normally be stored in an auxilary table with a ForeignKey pointing to this one. The auxilary table does not need be registered with the configuration separately.
initial n/a n/a Configuration for determining how to generate nested repeat observations when creating a “new” record. By default, no nested records will be displayed at first, but a button will be provided to add one or more nested records. To simulate Django’s default of 3 nested inline forms, set initial to “3”. To leverage an EAV structure (where each nested record corresponds to a row in a separate “Attribute” or “type” table), set initial to an object specifying the name of the type model and a filter (if any) to use with model.filter() when generating the list, e.g. {"type_model": "attribute", "filter": {"active": true}.