| 83 | | "schedule")</code>.</para> |
|---|
| | 83 | "schedule")</code>. Let's rewrite our user method to handle such requests:</para> |
|---|
| | 84 | <example> |
|---|
| | 85 | <title>A user method which handles positional parameters</title> |
|---|
| | 86 | <programlisting>class Admin: |
|---|
| | 87 | def user(self, *args): |
|---|
| | 88 | if not args: |
|---|
| | 89 | raise cherrypy.HTTPError(400, "A user id was expected but not supplied.") |
|---|
| | 90 | id = args.pop(0) |
|---|
| | 91 | if args and args[0] == 'schedule': |
|---|
| | 92 | return self.schedule(id) |
|---|
| | 93 | return "You asked for user '%s'" % id |
|---|
| | 94 | user.exposed = True</programlisting> |
|---|
| | 95 | </example> |
|---|
| | 96 | <para>Note that this is different behavior than CherryPy 2.1, which only allowed |
|---|
| | 97 | positional params for methods named "default".</para> |
|---|
| | 98 | </section> |
|---|
| | 99 | <section> |
|---|
| | 100 | <title>Default methods</title> |
|---|
| | 101 | <para>Are you ready for another special case? What handler is called in our example if |
|---|
| | 102 | you request the URI "/not/a/valid/path"? Given the behavior we have described up to this |
|---|
| | 103 | point, you might deduce that the <code>root.index</code> method will end up handling |
|---|
| | 104 | <emphasis>any</emphasis> path that can't be mapped elsewhere. This would mean, in effect, |
|---|
| | 105 | that CherryPy applications with a <code>root.index</code> could never return a "404 Not |
|---|
| | 106 | Found" response!</para> |
|---|
| | 107 | <para>To prevent this, CherryPy doesn't try to call index methods unless they are |
|---|
| | 108 | attached to the last node in the path; in our example, the only index method that might |
|---|
| | 109 | be called would be a <code>root.not.a.valid.path.index</code> method. If you truly want |
|---|
| | 110 | an intermediate index method to receive positional parameters, well, you can't do that. |
|---|
| | 111 | But what you can do is define a <code>default</code> method to do that for you, instead |
|---|
| | 112 | of an <code>index</code> method. If we wanted our <code>cherrypy.root</code> to handle |
|---|
| | 113 | any child path, and receive positional parameters, we could rewrite it like this:</para> |
|---|
| | 114 | <example> |
|---|
| | 115 | <title>A <code>default</code> method example</title> |
|---|
| | 116 | <programlisting>class Root: |
|---|
| | 117 | def index(self): |
|---|
| | 118 | return "Hello, world!" |
|---|
| | 119 | index.exposed = True |
|---|
| | 120 | |
|---|
| | 121 | def default(self, *args): |
|---|
| | 122 | return "Extra path info: %s" % repr(args) |
|---|
| | 123 | default.exposed = True</programlisting> |
|---|
| | 124 | </example> |
|---|
| | 125 | <para>This new Root class would handle the URI's "/" and "/index" via the |
|---|
| | 126 | <code>index</code> method, and would handle URI's like "/not/a/valid/path" and |
|---|
| | 127 | "/admin/unknown" via the <code>default</code> method.</para> |
|---|
| | 128 | </section> |
|---|
| | 129 | <section> |
|---|
| | 130 | <title>Traversal examples</title> |
|---|
| | 131 | <para>For those of you who need to see in exactly what order CherryPy will try various |
|---|
| | 132 | handlers, here are some examples, using the application above. We always start by trying |
|---|
| | 133 | to find the longest object path first, and then working backwards until an exposed, |
|---|
| | 134 | callable handler is found:</para> |
|---|
| | 135 | <example> |
|---|
| | 136 | <title>Traversal examples</title> |
|---|
| | 137 | <programlisting>"/admin/user/8192/schedule" |
|---|
| | 138 | Trying to reach cherrypy.root.admin.user.8192.schedule.index... |
|---|
| | 139 | cherrypy.root exists? Yes. |
|---|
| | 140 | .root.admin exists? Yes. |
|---|
| | 141 | .admin.user exists? Yes. |
|---|
| | 142 | .user.8192 exists? No. |
|---|
| | 143 | .user.default is callable and exposed? No. |
|---|
| | 144 | .admin.user is callable and exposed? Yes. Call it. |
|---|
| | 145 | |
|---|
| | 146 | "/admin/search/" |
|---|
| | 147 | Trying to reach cherrypy.root.admin.search.index... |
|---|
| | 148 | cherrypy.root exists? Yes. |
|---|
| | 149 | .root.admin exists? Yes. |
|---|
| | 150 | .admin.search exists? Yes. |
|---|
| | 151 | .search.index exists? Yes. Path exhausted. |
|---|
| | 152 | .search.index is callable and exposed? Yes. Call it. |
|---|
| | 153 | |
|---|
| | 154 | "/admin/unknown" |
|---|
| | 155 | Trying to reach cherrypy.root.admin.unknown.index... |
|---|
| | 156 | cherrypy.root exists? Yes. |
|---|
| | 157 | .root.admin exists? Yes. |
|---|
| | 158 | .admin.unknown exists? No. |
|---|
| | 159 | .admin.default is callable and exposed? No. |
|---|
| | 160 | .root.admin is callable and exposed? No. |
|---|
| | 161 | .root.default is callable and exposed? Yes. Call it.</programlisting> |
|---|
| | 162 | </example> |
|---|