RoutesUrlMatching: tut11_routes.py
| Line | |
|---|---|
| 1 | """ |
| 2 | Tutorial - Routes |
| 3 | |
| 4 | In this tutorial, we will try to see what can be done with routes and what can't (at least with Routes 1.8). |
| 5 | We are going to create a very simple application customized for each user. |
| 6 | """ |
| 7 | |
| 8 | import cherrypy |
| 9 | |
| 10 | class Profile(object): |
| 11 | |
| 12 | def __init__(self): |
| 13 | self. users = { |
| 14 | 'marc' : {'id': 1, 'email': 'marc@test.com', 'interests': ['knitting', 'coding', 'beer drinking']}, |
| 15 | 'paul' : {'id': 2, 'email': 'paul@test.com', 'interests': ['kitty hunting', 'throwing rocks at children']} |
| 16 | } |
| 17 | |
| 18 | def interests(self, user, id=None): |
| 19 | user = user.lower() |
| 20 | if user in self.users.keys(): |
| 21 | if id is not None and 0 <= int(id) < len(self.users[user]['interests']): |
| 22 | return user + "'s interests: " + self.users[user]['interests'][int(id)] |
| 23 | if id is None: |
| 24 | return user + "'s interests: " + str(self.users[user]['interests']) |
| 25 | return user + " does not exist. Or the id specified is not valid." |
| 26 | |
| 27 | def home(self, user, field=None): |
| 28 | user = user.lower() |
| 29 | if field not in ['email', 'interests']: |
| 30 | field = None |
| 31 | if user in self.users.keys(): |
| 32 | if field is not None and field in self.users[user].keys(): |
| 33 | return user + "'s " + field + ": " + str(self.users[user][field]) |
| 34 | else: |
| 35 | res = "" |
| 36 | for field in self.users[user].keys(): |
| 37 | res += user+ "'s " + field + ": " + str(self.users[user][field]) + "<br/>" |
| 38 | return res |
| 39 | return user + " does not exist" |
| 40 | |
| 41 | |
| 42 | |
| 43 | # getting the Routes dispatcher |
| 44 | d = cherrypy.dispatch.RoutesDispatcher() |
| 45 | root = Profile() |
| 46 | |
| 47 | # here is the standard way of doing things with routes |
| 48 | # thanks to "URL Minimization", uri like |
| 49 | # /interests/marc |
| 50 | # /interests/marc/2 |
| 51 | # are both matched by the same route. |
| 52 | |
| 53 | #d.connect('second route', '/interests/:user/:id', controller=root, action='interests', id=0) |
| 54 | #d.connect('first route', '/home/:user/:field', controller=root, action='home', field=None) |
| 55 | |
| 56 | # but what happens when you want to do prettier uri ? |
| 57 | # let's assume that your app is user centered. |
| 58 | # Having all url starting with the user name is by far nicer |
| 59 | # /marc/interests is more attractive than /interests/marc |
| 60 | # moreover, it would be very nice to be able to access "home" through /marc and not /marc/home |
| 61 | # the intuitive way of doing so is the following: |
| 62 | # d.connect('interests', '/:user/interests/:id', controller=root, action='interests', id=0) |
| 63 | # d.connect('home', '/:user/:field', controller=root, action='home', field=None) |
| 64 | # Note that the order is very important here, as Routes stops at the first route matched. |
| 65 | # but as you can see, accessing /marc does not display marc's home but the page you would expect to get at /marc/interests/0 |
| 66 | |
| 67 | # Although it should not be this way, the url minimization in routes makes this possible |
| 68 | # For further detail, look at Routes' doc. It has to do with minization and implicit values of variables |
| 69 | # The only solution is forget minimization and only use explicit routes. |
| 70 | # To do so, 2 things must be done: |
| 71 | # first of all, not doing things like 'field=None' |
| 72 | # second of all, disabling implicit routes |
| 73 | # the default form for a route is /:controller/:action/:id |
| 74 | # you can just do d.connect('/:controller/:action/:id') and Routes will interpret it as using the 'action' method on the specified controller with id as parameter (id = None if not specified) |
| 75 | # As you can see, there is some implicit minimization here |
| 76 | # However, this is not possible with Routes 1.8 (the one provided with a standard cherrypy3 installation) |
| 77 | |
| 78 | # About classic minimization: |
| 79 | # If you want to be sure that no minimization is done, you must disable it (and of course use only explicit routes) |
| 80 | # You have to upgrade to at least Routes 1.9 to do this |
| 81 | # easy_install -U routes |
| 82 | # Moreover, with minimization disabled, you have to specify routes for each type of URL |
| 83 | # You can't do /:user/:field anymore with field default to None |
| 84 | # You have to specify /:user and /:user/:field |
| 85 | # This way everything is explicit and works fine |
| 86 | |
| 87 | m = d.mapper |
| 88 | m.explicit = True # no implicit values for routes |
| 89 | m.minimization = False # no minimization (Routes > 1.9 only !) |
| 90 | d.connect('interests-1', '/:user/interests', controller=root, action='interests') |
| 91 | d.connect('interests-2', '/:user/interests/:id', controller=root, action='interests') |
| 92 | d.connect('home-1', '/:user', controller=root, action='home') |
| 93 | d.connect('home-2', '/:user/:field', controller=root, action='home', field=None) |
| 94 | |
| 95 | |
| 96 | # setting the dispatcher into the CherryPy config |
| 97 | conf = {'/' : {'request.dispatch' : d}} |
| 98 | # note that since the dispatcher handles the matching url/method |
| 99 | # we do not need to specify the root of the application anymore |
| 100 | cherrypy.tree.mount(root=None, config=conf) |
| 101 | cherrypy.server.quickstart() |
| 102 | cherrypy.engine.start() |

