Changes between Version 87 and Version 88 of S3/S3REST/s3_rest_controller
- Timestamp:
- 06/13/14 12:15:51 (11 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
S3/S3REST/s3_rest_controller
v87 v88 14 14 Using {{{s3_rest_controller}}}, a basic RESTful controller for the {{{pr_image}}} table can look like: 15 15 16 {{{ 16 {{{#!python 17 17 def image(): 18 18 … … 30 30 == Basic Syntax == 31 31 32 {{{ 32 {{{#!python 33 33 output = s3_rest_controller(prefix, resourcename) 34 34 }}} … … 44 44 All of the following options are set using: 45 45 46 {{{ 46 {{{#!python 47 47 s3mgr.configure(table, key=value) 48 48 }}} … … 54 54 55 55 You can specify multiple settings at once: 56 {{{ 56 {{{#!python 57 57 s3mgr.configure(table, key1=value1, key2=value2, ...) 58 58 }}} … … 62 62 You can also delete a particular setting by: 63 63 64 {{{ 64 {{{#!python 65 65 s3mgr.model.clear_config(table, "key") 66 66 }}} … … 72 72 You can define which of the CRUD functions are allowed for your resource. By default, they all are True. 73 73 74 {{{ 74 {{{#!python 75 75 s3mgr.configure(table, editable=True, # Records can be updated 76 76 insertable=True, # New records can be added … … 92 92 This setting takes a list of field names of the fields to be displayed: 93 93 94 {{{ 94 {{{#!python 95 95 s3mgr.configure(table, 96 96 list_fields=["id", "name", "location_id"]) … … 101 101 For virtual fields, you should provide a tuple of {{{(T("FieldLabel"), "fieldname")}}}, because virtual fields do not have a {{{.label}}} setting (as they are functions and not {{{Field}}} instances): 102 102 103 {{{ 103 {{{#!python 104 104 s3mgr.configure(table, 105 105 list_fields=["id", … … 113 113 To include a field from a referenced table, insert the field name as "<foreign_key>$<fieldname>", e.g.: 114 114 115 {{{ 115 {{{#!python 116 116 s3mgr.configure(table, 117 117 list_fields=["id", … … 134 134 The redirection destination can be configured per DB table, using: 135 135 136 {{{ 136 {{{#!python 137 137 s3mgr.configure(table, create_next=url) 138 138 }}} 139 {{{ 139 {{{#!python 140 140 s3mgr.configure(table, update_next=url) 141 141 }}} 142 {{{ 142 {{{#!python 143 143 s3mgr.configure(table, delete_next=url) 144 144 }}} … … 168 168 You can define extra form validation methods to be invoked after a create/update form has successfully passed the indivdual field validation, by using: 169 169 170 {{{ 170 {{{#!python 171 171 s3db.configure(tablename, create_onvalidation=callback) 172 172 }}} 173 {{{ 173 {{{#!python 174 174 s3db.configure(tablename, update_onvalidation=callback) 175 175 }}} … … 182 182 If either of {{{create_onvalidation}}} or {{{update_onvalidation}}} is not set, then the {{{onvalidation}}} setting is tried: 183 183 184 {{{ 184 {{{#!python 185 185 s3db.configure(tablename, onvalidation=callback) 186 186 }}} … … 191 191 192 192 Any validation errors are to be reported directly into the form as: 193 {{{ 193 {{{#!python 194 194 form.errors[fieldname] = error_msg 195 195 }}} … … 208 208 You can define methods to be invoked after a record has been created/updated, by using: 209 209 210 {{{ 210 {{{#!python 211 211 s3db.configure(tablename, create_onaccept=callback) 212 212 }}} 213 {{{ 213 {{{#!python 214 214 s3db.configure(tablename, update_onaccept=callback) 215 215 }}} … … 222 222 If either of {{{create_onaccept}}} or {{{update_onaccept}}} is not set, then the {{{onaccept}}} setting is tried: 223 223 224 {{{ 224 {{{#!python 225 225 s3db.configure(tablename, onaccept=callback) 226 226 }}} … … 234 234 You can specify callbacks to be invoked when a record is to be deleted: 235 235 236 {{{ 236 {{{#!python 237 237 s3db.configure(tablename, ondelete_cascade=callback) 238 238 }}} … … 251 251 You can also define callbacks to be invoked ''after'' a record has been deleted: 252 252 253 {{{ 253 {{{#!python 254 254 s3db.configure(tablename, ondelete=callback) 255 255 }}} … … 277 277 However, some tables may by their nature only contain one or few rows, and then server-side pagination is not needed (in fact, inefficient). In these cases, the respective controller can turn it off by: 278 278 279 {{{ 279 {{{#!python 280 280 response.s3.no_sspag=True 281 281 }}} … … 321 321 To choose a custom view, you can easily override the default setting ''after'' s3_rest_controller returns: 322 322 323 {{{ 323 {{{#!python 324 324 output = s3_rest_controller(prefix, resourcename) 325 325 … … 332 332 In interactive view formats, any additional named arguments in the {{{s3_rest_controller}}} argument list will be added to the view variables: 333 333 334 {{{ 334 {{{#!python 335 335 output = s3_rest_controller(prefix, resourcename, **attr) 336 336 }}} … … 345 345 A typical use-case is '''rheader''': 346 346 347 {{{ 347 {{{#!python 348 348 def my_rheader(r): 349 349 if r.interactive and r.component: … … 356 356 }}} 357 357 358 If {{{my_rheader(r)}}} gives something else than {{{ None}}}, then this value is added as {{{rheader}}} to the view variables.358 If {{{my_rheader(r)}}} gives something else than {{{#!python None}}}, then this value is added as {{{rheader}}} to the view variables. 359 359 360 360 == Advanced Options == … … 363 363 364 364 You can filter lists in the controller by setting {{{response.s3.filter}}} to a filter query: 365 {{{ 365 {{{#!python 366 366 # This filters for females: 367 367 response.s3.filter = (db.pr_person.gender == 2) … … 375 375 376 376 In {{{prep}}}, you can also add filter queries using the {{{add_filter}}} method: 377 {{{ 377 {{{#!python 378 378 def prep(r): 379 379 resource = r.resource … … 393 393 394 394 To have the primary resource unfiltered, and filter only records in a particular component, you can use {{{add_component_filter}}}: 395 {{{ 395 {{{#!python 396 396 def prep(r): 397 397 resource = r.resource … … 423 423 To '''pre-populate''' Create-forms '''from the controller''', you can specify the variable {{{populate}}} in the arguments of {{{s3_rest_controller}}}: 424 424 425 {{{ 425 {{{#!python 426 426 output = s3_rest_controller(prefix, resourcename, 427 427 populate=dict(fieldname1=value1, … … 432 432 Instead of a {{{dict}}}, you can also pass a callable object as {{{populate}}}. This will be executed with the current {{{S3Request}}} and the named arguments of {{{s3_rest_controller}}} in order to produce the field/value {{{dict}}}: 433 433 434 {{{ 434 {{{#!python 435 435 def populate(r, **attr): 436 436 """ … … 454 454 Note that {{{populate}}} will only be applied in {{{GET}}} requests and only if no record_id is specified. That means, if it uses a separate form to generate the data, you need to revert the request into {{{GET}}} in order to have the create-form pre-populated: 455 455 456 {{{ 456 {{{#!python 457 457 data = None 458 458 form = FORM(...some form...) … … 480 480 A prep hook would allow you to change a handler configuration in certain situations, e.g. testing a URL variable: 481 481 482 {{{ 482 {{{#!python 483 483 def myresource(): 484 484 … … 511 511 512 512 If you need to pass data between them, you can use this trick: 513 {{{ 513 {{{#!python 514 514 vars = {} # the surrounding dict 515 515 def prep(r, vars): … … 531 531 The s3_rest_controller has multiple hooks,Look at how s3_rest_controller is actually defined in models/00_utils.py: 532 532 533 {{{ 533 {{{#!python 534 534 def s3_rest_controller(prefix=None, resourcename=None, **attr): 535 535 … … 581 581 This could be your "warehouse" CRUD controller: 582 582 583 {{{ 583 {{{#!python 584 584 def warehouse(): 585 585 … … 591 591 At first you implement your report function (in the controller file). This function takes the argument r (=S3Request) and a dict of named arguments (just the same named arguments from the s3_rest_controller call above). This function returns the report. Then, in your controller, you plug in this function to your resource - together it would look like that: 592 592 593 {{{ 593 {{{#!python 594 594 def warehouse(): 595 595 … … 617 617 found in r: 618 618 619 {{{ 619 {{{#!python 620 620 def warehouse_report(r, **attr): 621 621 … … 647 647 To produce the XML report, it is probably sufficient to just export the requested warehouse information in S3-XML, and then use XSLT stylesheets to produce the finally desired XML formats. That's pretty easy: 648 648 649 {{{ 649 {{{#!python 650 650 def warehouse_report(r, **attr): 651 651 ... … … 657 657 Perhaps you want to add an RSS feed: 658 658 659 {{{ 659 {{{#!python 660 660 def warehouse_report(r, **attr): 661 661 ... … … 682 682 683 683 In case a specific record has been requested, you can access it as: 684 {{{ 684 {{{#!python 685 685 record = r.record 686 686 }}} 687 687 If r.record is None, then the request is targeting all warehouse records, so you'd take: 688 {{{ 688 {{{#!python 689 689 table = r.table 690 690 records = db().select(table.ALL)