Home

wq Configuration Object

wq version: 0.7.8 1.0 1.1
Docs > API Conventions

wq Configuration Object

The wq Configuration object is a JSON structure that describes the URL structure of a website (/web app) and its corresponding REST API. It assumes the website and the API share the same URL structure; see My Website is its own REST API for the motivation behind this approach. The configuration object is typically generated by a REST service (e.g. wq.db) and provided to a JavaScript client (e.g. wq.app) in order to set common expectations on the layout of the application.

The basic format of the wq Configuration Object is:

{
    'pages': {
        '[model_name]': {'list': true, 'url': '[model_name]s', 'form': [...]},
        '[simple_page]': {'url': '[simple_page]'}
    }
}

The object is typically stored in the JavaScript module app/js/data/config.js. This module is imported by app/js/[myapp]/config.js, which can be used to add additional configuration sections, e.g. for wq/app.js plugins. Generally, you should not customize the pages configuration section directly, since doing so may cause wq.app and wq.db to become out of sync. Instead, you can provide arbitrary configuration parameters by supplying additional arguments to wq.db.rest.

# 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
)

Configuration Options

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.js to map URL requests to page templates to render, and also to provide hints to wq/store.js and wq/model.js 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).

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, it is assumed that there will be a set of templates named [model_name]_list, [model_name]_detail, and optionally [model_name]_edit. If false or unset, it is assumed that there will be a single template 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.
once Whether to only render this page once or every time it is opened during a browsing session. The default is false (render every time), which is usually acceptable and is the recommended setting for list pages. The primary use for this value is with simple pages such as overview maps. Setting once to true in this case means that the user can browse around the application then come back to the overview map and find it in the same position as when they left.
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.

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
form A representation of the model schema, in the form of an array of field definitions (see below)
map Map configuration for the wq/map.js plugin. See the wq/map.js documentation for more details.
can_add
can_edit
can_delete
Server-defined flags indicating which permissions the current user has on the model. These flags are used as template rendering context variables for showing and hiding available options to the user. They are automatically computed and enforced by wq.db based on information from django.contrib.auth and ANONYMOUS_PERMISSIONS.
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)
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 (new in wq 1.0) configures which records from the model are cached for offline use. It fully replaces the partial, max_local_pages, and reversed options in older versions of wq (see Pagination and Caching). Four 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)
"none" None of the dataset will be stored offline; every list and detail view will require a network request.
"filter" Specify a custom filter for the offline cache. The full dataset can be accessed via pagination. Note that this option assumes 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/{{site_id}}/observations" Return to the list of observations filtered by the referenced site.
"observations/new?site_id={{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

As of wq 1.0, the configuration object for each list page includes an XLSForm-inspired representation of the schema for the model. This information can be used by the wq maketemplates command to automatically generate a Mustache HTML <form> template for editing a page. Certain properties are also used by wq/app.js to handle choice lookups and relationships between models (which are harder to bake into an HTML template). The form configuration thus replaces the parents, children, and choices page configuration options available in wq 0.8 and earlier.

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 template 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.js 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 template 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}.

FIXME: The nested/repeat stuff is pretty advanced (it requires custom DRF serializers on the wq.db side) - it should probably be moved to the patterns docs.