wiki:JoinedResourceController

Version 2 (modified by Dominic König, 13 years ago) ( diff )

--

Joined Resource Controller

The Joined Resource Controller provides a RESTful API for joined resources analogous to the generic shn_rest_controller.

A joined resource request is a request on a resource ("joined resource") in dependence of a join to another table ("primary resource").

In this implementation, these joins can be 1:1 or 1:N, and they can be natural joins (same key field in both tables) or primary/foreign key matches, where the primary key is always the 'id' field in the primary table.

The controller function for this is:

  • shn_jr_rest_controller (defined in models/01_jr_controller.py)

Model

Example for definition of a joined resource in the model:

resource = 'image'
table = module + '_' + resource
db.define_table(table, timestamp, uuidstamp, deletion_status,
                pr_pe_id,
                opt_pr_image_type,
                Field('title'),
                Field('image', 'upload', autodelete=True),
                Field('description'),
                Field('comment'),
                migrate=migrate)

# Joined Resource
jrlayer.add_jresource(module, resource,
    multiple=True,
    joinby='pr_pe_id',
    fields = ['id', 'opt_pr_image_type', 'image', 'title','description'])

where:

  • module is the name of the module in which the joined resource is defined (prefix)
  • resource is the name of the joined resource
  • multiple indicates whether this is a 1:N (True) or 1:1 (False) join, defaults to True
  • joinby describes the join keys:
    • pass a single field name for natural joins (same key field in both tables)
    • pass a dictionary of tablename=fieldname pairs for primary/foreign key matching, in which:
      • tablename is the name of the respective primary table
      • fieldname the name of the foreign key in the joined table that points to the id field in the primary table
  • fields is a list of the fields in the joined resource that shall appear in list views:
    • if omitted or set to None, all readable fields will be included

No definitions are required at the primary resource, just define the table as usual.

  • Of course, shn_jr_rest_controller is deletion status aware.

Controller

shn_jr_rest_controller takes (almost) the same settings and arguments as shn_rest_controller:

def person():
    crud.settings.delete_onvalidation=shn_pentity_ondelete
    return shn_jr_rest_controller(module, 'person', main='first_name', extra='last_name',
        pheader=shn_pr_pheader,
        onvalidation=lambda form: shn_pentity_onvalidation(form, table='pr_person', entity_class=1),
        onaccept=None)

"Almost" means with exception of the optional pheader argument: This helps you to display some information about the primary resource record in the view while operating on a joined resource (e.g. the person's name and ID, when displaying a list of available images for this person). You may pass static content, or a function or lambda to produce content, which is to be forwarded as pheader variable to the view.

If you pass a function or lambda, it has to take 5 arguments:

  • resource = name of the primary resource
  • record_id = id of the primary resource record
  • representation = data format of the request
  • next=None = backlink URL to reproduce the request (with empty method)
  • same=None = backlink URL to reproduce the request (with empty method and containing the string '[id]' instead of the primary resource record id)

These backlinks can be used to reproduce the original request after doing something on the primary resource (e.g., edit or change the selected record).

  • NOTE: Callbacks from CRUD settings (like in the example above) as well as onvalidation and onaccept callbacks are only invoked at requests on the main resource, but not at joined requests.

Argument Lists

URL format:

http://host/application/module/resource/<arguments>?<vars>

The argument list is interpreted as follows:

  • empty argument list is a LIST attempt to the primary resource
  • <id> is a READ attempt on the record #<id> of the primary resource
  • <method> is a <method> attempt on the primary resource
  • <method>/<id> is a <method> attempt on the record #<id> of the primary resource
  • <id>/<joined_resource> is a LIST attempt to the joined resource for the record #<id> of the primary resource
  • <joined_resource>?id_label=XXX is a LIST attempt to the joined resource for the record of the primary resource with that label
  • <id>/<joined_resource>/<method> is a <method> attempt on the joined resource for the record #<id> of the primary resource
  • <joined_resource>/<method>?id_label=XXX analogous.

You may even pass the record ID of the joined resource at the end of the arguments list to access a particular record - which would produce an error message if these two records do not belong together.

Plug-In Resource Actions

You may plug in custom resource actions to shn_jr_rest_controller, e.g. if you have a custom search function for a resource.

Example: This adds a search_simple method to the person resource, which calls the shn_pr_person_search_simple function:

# Plug into REST controller
jrlayer.set_method(module, 'person', None, None, 'search_simple', shn_pr_person_search_simple )

Arguments of jrlayer.set_method:

  • module = name of the module of the primary resource
  • resource = name of the primary resource
  • jmodule = name of the module of the joined resource (if any, maybe None)
  • jresource = name of the joined resource (if any, maybe None)
  • method = name of the method
  • action = the function or lambda to invoke for that method (to remove a plug-in action, just pass None here)

The action method in turn has to take plenty of arguments:

  • module
  • resource
  • record_id
  • method
  • jmodule=None
  • jresource=None
  • jrecord_id=None
  • joinby=None
  • multiple=True
  • representation="html"
  • onvalidation=None
  • onaccept=None
Note: See TracWiki for help on using the wiki.