| 507 | If you have a resource "warehouse" and want to implement a function "report" that generates a report about the current status of the warehouse. |
| 508 | |
| 509 | Now you're gonna provide this report in a RESTful way, i.e. you want to provide it as a resource that can be addressed via URLs like: |
| 510 | |
| 511 | - '''!http://site.myserver.org/eden/wm/warehouse/report''' |
| 512 | |
| 513 | and is provided in several different data formats beyond HTML (the interactive view), let's say - XLS and XML: |
| 514 | |
| 515 | - '''!http://site.myserver.org/eden/wm/warehouse/report.xls''' |
| 516 | - '''!http://site.myserver.org/eden/wm/warehouse/report.xml''' |
| 517 | |
| 518 | you can use s3_rest_controller for this! |
| 519 | |
| 520 | This could be your "warehouse" CRUD controller: |
| 521 | |
| 522 | {{{ |
| 523 | def warehouse(): |
| 524 | |
| 525 | """ RESTful CRUD controller """ |
| 526 | |
| 527 | return s3_rest_controller(module, resource, ...) |
| 528 | }}} |
| 529 | |
| 530 | At first you implement your report function (in the controller file). This function takes the argument r (=S3RESTRequest) 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: |
| 531 | |
| 532 | {{{ |
| 533 | def warehouse(): |
| 534 | |
| 535 | """ RESTful CRUD+Reports controller """ |
| 536 | |
| 537 | # Plug warehouse_report into warehouse resource: |
| 538 | s3db.set_method(module, resource, method="report", action=warehouse_report) |
| 539 | |
| 540 | return shn_rest_controller(module, resource, ...) |
| 541 | |
| 542 | def warehouse_report(r, **attr): |
| 543 | |
| 544 | """ Warehouse report generator """ |
| 545 | |
| 546 | # Code to produce the report goes here |
| 547 | report = ... |
| 548 | |
| 549 | return report |
| 550 | }}} |
| 551 | |
| 552 | Note that if "report" is a dict, then the REST controller automatically adds the S3Request as "r" to that dict before returning it. Thus, "r" is |
| 553 | available to the view templates. That also means: do not use "r" as key in that dict. |
| 554 | |
| 555 | However, there may be other formats than HTML - to implement other formats, you might need to check for the representation of the request. This can be |
| 556 | found in r: |
| 557 | |
| 558 | {{{ |
| 559 | def warehouse_report(r, **attr): |
| 560 | |
| 561 | """ Warehouse report generator """ |
| 562 | |
| 563 | if r.representation in ("html", "popup"): |
| 564 | # Code to produce the report items: |
| 565 | title = T("Warehouse Report") |
| 566 | |
| 567 | # Assemble the report items in a dict: |
| 568 | report = dict(title=title, ...) |
| 569 | |
| 570 | elif r.representation == "xls": |
| 571 | # Code to produce the XLS report goes here |
| 572 | ... |
| 573 | |
| 574 | elif r.representation in s3_xml_export_formats: |
| 575 | # Code to produce the XML report goes here |
| 576 | ... |
| 577 | |
| 578 | else: |
| 579 | r.error(501, r.ERROR.BAD_FORMAT) |
| 580 | |
| 581 | return report |
| 582 | }}} |
| 583 | |
| 584 | See [wiki:S3XRC#RESTfulAPI#S3Request S3Request] to find out more about "r". |
| 585 | |
| 586 | 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: |
| 587 | |
| 588 | {{{ |
| 589 | def warehouse_report(r, **attr): |
| 590 | ... |
| 591 | elif r.representation in s3_xml_export_formats: |
| 592 | report = export_xml(xrequest) |
| 593 | ... |
| 594 | }}} |
| 595 | |
| 596 | Perhaps you want to add an RSS feed: |
| 597 | |
| 598 | {{{ |
| 599 | def warehouse_report(r, **attr): |
| 600 | ... |
| 601 | elif r.representation == "rss": |
| 602 | # Code to produce the RSS report goes here |
| 603 | report = ... |
| 604 | ... |
| 605 | }}} |
| 606 | |
| 607 | Getting the data from the warehouse_report. |
| 608 | |
| 609 | Your implementation already supports a variety of URLs: |
| 610 | |
| 611 | This URL addresses the report for all warehouses: |
| 612 | - '''!http://site.myserver.org/eden/wm/warehouse/report''' |
| 613 | |
| 614 | This URL addresses the report for the warehouse record with ID=1. |
| 615 | - '''!http://site.myserver.org/eden/wm/warehouse/1/report''' |
| 616 | |
| 617 | This URL addresses the report in XLS format for the warehouse record with the UUID=123654278 (assuming that you have UUID's in your warehouse table). |
| 618 | - '''!http://site.myserver.org/eden/wm/warehouse/report.xls?warehouse.uid=123654278''' |
| 619 | |
| 620 | The S3Request provides the resource information to your warehouse_report function. |
| 621 | |
| 622 | In case a specific record has been requested, you can access it as: |
| 623 | {{{ |
| 624 | record = r.record |
| 625 | }}} |
| 626 | If r.record is None, then the request is targeting all warehouse records, so you'd take: |
| 627 | {{{ |
| 628 | table = r.table |
| 629 | records = db().select(table.ALL) |
| 630 | for record in records: |
| 631 | ... |
| 632 | }}} |
| 633 | instead. |
| 634 | |
| 635 | NOTE: representation in r is always all lowercase, there is no differentiation between the ".XML" and ".xml" extension in the URL. |
| 636 | |
| 637 | And...not to forget: your warehouse_report is still a controller function, that means you can implement forms as usual (e.g. operated with form.accepts or web2py Crud). |
| 638 | |
| 639 | |