Changes between Version 17 and Version 18 of JoinedResourceController


Ignore:
Timestamp:
11/19/09 23:56:44 (12 years ago)
Author:
Dominic König
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • JoinedResourceController

    v17 v18  
    1 [[TOC]]
    2 
    31= Joined Resource Controller =
    42
    5   * Code: [https://code.launchpad.net/~flavour/sahana/sahanapy-trunk Main Trunk] Revision 358+
    6 
    7 The main controller function of the REST Interface is:
    8 
    9     * '''shn_rest_controller''' (defined in models/01_RESTlike_controller.py)
    10 
    11 The [wiki:S3XRC XML Interface] supports in-line XSLT transformation in order to support various XML formats.
    12 
    13 The [wiki:S3XRC JSON Interface] can be used for Ajax access to resources.
    14 
    15 == Joined Resources ==
    16 
    17 This extends the single-table [wiki:BluePrintRESTImplementation REST Implementation].
    18 
    19 A joined resource request is a request to a table ("joined resource" or "component") in dependency of a join to another table ("primary resource" or simply "resource"), e.g.:
    20 
    21   * the list of addresses (=component) of a person (=resource).
    22 
    23 There are different ways how "Joined Resources" can be seen:
    24 
    25 a) as subtables of database tables
    26 b) as structured properties of object classes
    27 c) as component classes within data compounds
    28 
    29 In this implementation, component resources can be joined 1:1 or N:1 to their primary resources, either by 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.
    30 
    31 == Model ==
    32 
    33 Example for definition of a joined resource in the model:
    34 
    35 {{{
    36 resource = 'image'
    37 table = module + '_' + resource
    38 db.define_table(table, timestamp, uuidstamp, deletion_status,
    39                 pr_pe_id,
    40                 opt_pr_image_type,
    41                 Field('title'),
    42                 Field('image', 'upload', autodelete=True),
    43                 Field('description'),
    44                 Field('comment'),
    45                 migrate=migrate)
    46 
    47 # Joined Resource
    48 s3xrc.model.add_component(module, resource,
    49     multiple=True,
    50     joinby='pr_pe_id',
    51     deletable=True,
    52     editable=True,
    53     list_fields = ['id', 'opt_pr_image_type', 'image', 'title','description'])
    54 }}}
    55 
    56 where:
    57 
    58   - '''module''' is the name of the module in which the joined resource is defined (prefix)
    59   - '''resource''' is the name of the joined resource
    60   - '''multiple''' indicates whether this is a 1:N (True) or 1:1 (False) join, defaults to True
    61   - '''joinby''' describes the join keys:
    62     - pass a single field name for natural joins (same key field in both tables)
    63     - pass a dictionary of ''tablename=fieldname'' pairs for primary/foreign key matching, in which:
    64       - ''tablename'' is the name of the respective primary table
    65       - ''fieldname'' the name of the foreign key in the joined table that points to the ''id'' field in the primary table
    66       - e.g. {{{joinby = dict(pr_person='person_id')}}}
    67   - '''fields''' is a list of the fields in the joined resource that shall appear in list views:
    68     - if omitted or set to None, all readable fields will be included
    69 
    70 No definitions are required at the primary resource, just define the table as usual.
    71 
    72 == Controller ==
    73 
    74 As usual:
    75 
    76 {{{
    77 def person():
    78     crud.settings.delete_onvalidation = shn_pentity_ondelete
    79     return shn_rest_controller(module, 'person', main='first_name', extra='last_name',
    80         pheader=shn_pr_pheader,
    81         onvalidation=lambda form: shn_pentity_onvalidation(form, table='pr_person', entity_class=1),
    82         onaccept=None)
    83 }}}
    84 
    85 New: 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.
    86 
    87 If you pass a function or lambda, it has to take 5 arguments:
    88   - '''resource''' = name of the primary resource
    89   - '''record_id''' = id of the primary resource record
    90   - '''representation''' = data format of the request
    91   - '''next=None''' = backlink URL to reproduce the request (with empty method)
    92   - '''same=None''' = backlink URL to reproduce the request (with empty method and containing the string '[id]' instead of the primary resource record id)
    93 
    94 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).
    95 
    96   * '''NOTE:''' Callbacks from CRUD settings (defined as 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. To invoke on Joined Requests, need to define in the {{{jrlayer.add_jresource()}}} or later using {{{jrlayer.set_attr()}}}
    97 
    98 === Options ===
    99 There are some options which can be set before invoking the REST controller:
    100 {{{
    101 def kit():
    102     "RESTlike CRUD controller"
    103     response.s3.pdf = URL(r=request, f='kit_export_pdf')
    104     response.s3.xls = URL(r=request, f='kit_export_xls')
    105     if len(request.args) == 2:
    106         crud.settings.update_next = URL(r=request, f='kit_item', args=request.args[1])
    107     return shn_rest_controller(module, 'kit', main='code', onaccept=lambda form: kit_total(form))
    108 }}}
    109 
    110 The {{{response.s3.pdf}}} & {{{response.s3.xls}}} provide the {{{view/formats.html}}} with an alternate URL to provide a customised version of the PDF/XLS output available when clicking on the icon ({{{response.s3.rss}}} is also available).
    111 
    112 {{{
    113 def report_overdue():
    114     "Report on Overdue Invoices - those unpaid 30 days after receipt"
    115     response.title = T('Overdue Invoices')
    116     overdue = datetime.date.today() - timedelta(days=30)
    117     response.s3.filter = (db.fin_invoice.date_out==None) & (db.fin_invoice.date_in < overdue)
    118     s3.crud_strings.fin_invoice.title_list = response.title
    119     s3.crud_strings.fin_invoice.msg_list_empty = T('No Invoices currently overdue')
    120     return shn_rest_controller(module, 'invoice', deletable=False, listadd=False)
    121 }}}
    122 
    123 The {{{response.s3.filter}}} provides a filter which is used in the list view to show the desired subset of records (note that the s3.crud_strings can also be customised - when done in the Controller like this, they are good for just this request).
    124 == Argument Lists ==
    125 
    126 URL format:
    127 
    128 {{{
    129 http://host/application/module/resource/<arguments>?<vars>
    130 }}}
    131 
    132 The argument list is interpreted as follows:
    133 
    134   * '''empty argument list''' is a LIST attempt to the primary resource
    135   * '''<id>''' is a READ attempt on the record #<id> of the primary resource
    136   * '''<method>''' is a <method> attempt on the primary resource
    137   * '''<method>/<id>''' is a <method> attempt on the record #<id> of the primary resource
    138   * '''<id>/<joined_resource>''' is a LIST attempt to the joined resource for the record #<id> of the primary resource
    139   * '''<joined_resource>?id_label=XXX''' is a LIST attempt to the joined resource for the record of the primary resource with that label
    140   * '''<id>/<joined_resource>/<method>''' is a <method> attempt on the joined resource for the record #<id> of the primary resource
    141   * '''<joined_resource>/<method>?id_label=XXX''' analogous.
    142 
    143 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.
    144 
    145 The data format of the request can be passed:
    146 
    147   * as extension to the primary resource, e.g. http://localhost:8000/sahana/pr/person.xml/1
    148   * as extension to the joined resource, e.g. http://localhost:8000/sahana/pr/person/1/address.xml
    149   * as variable "format", e.g. http://localhost:8000/sahana/pr/person/1/address?format=xml
    150 
    151   '''Policy:''' ''"?format="'' overrides ''joined resource extension'' overrides ''resource extension''
    152 
    153 == Plug-In Resource Actions ==
    154 
    155 You may plug in custom resource actions to shn_rest_controller, e.g. if you have a custom search function for a resource.
    156 
    157 Example:
    158 This adds a ''search_simple'' method to the ''person'' resource, which calls the ''shn_pr_person_search_simple'' function:
    159 
    160 {{{
    161 # Plug into REST controller
    162 jrlayer.set_method(module, 'person', None, None, 'search_simple', shn_pr_person_search_simple )
    163 }}}
    164 
    165 Arguments of jrlayer.set_method:
    166 
    167   * '''module''' = name of the module of the primary resource
    168   * '''resource''' = name of the primary resource
    169   * '''jmodule''' = name of the module of the joined resource (if any, maybe None)
    170   * '''jresource''' = name of the joined resource (if any, maybe None)
    171   * '''method''' = name of the method
    172   * '''action''' = the function or lambda to invoke for that method (to remove a plug-in action, just pass None here)
    173 
    174 The action method in turn has to take plenty of arguments:
    175 
    176   * '''module'''
    177   * '''resource'''
    178   * '''record_id'''
    179   * '''method'''
    180   * '''jmodule=None'''
    181   * '''jresource=None'''
    182   * '''jrecord_id=None'''
    183   * '''joinby=None'''
    184   * '''multiple=True'''
    185   * '''representation="html"'''
    186   * '''onvalidation=None'''
    187   * '''onaccept=None'''
     3moved to [wiki:RESTController REST Controller]