Search code examples
urlreversecherrypydispatcher

how to get url of an object in cherrypy?


I am new to CherryPy. I am using the default dispatcher, with a URL structure similar to this:

root = Root()
root.page1 = Page1()
root.page1.apple = Apple()
root.page2 = Page2()
root.page2.orange = Orange()

Orange renders a template, in which I need a link to Apple. I could just hardcode /page1/apple/. But how can I get the URL of Apple in a DRY manner?

Can this be done with the default dispatcher in CherryPy, or is it only possible with the Routes dispatcher?

(I am coming from the Django world, where one would use reverse() for this purpose.)


Solution

  • You can access to the mounted apps through

    cherrypy.tree.apps[mount_point].root
    

    root is always the mounted instance to the mount point. So a reverse function would look like:

    def reverse(cls):
        # get link to a class type
        for app_url in cherrypy.tree.apps.keys():
            if isinstance(cherrypy.tree.apps[app_url].root, cls):
                # NOTE: it will return with the first mount point of this class
                return app_url
    

    Please find a sample code below that uses your classes. http://localhost:8080/page4/orange/ prints out { Orange and the link to apple: : "/page3/apple" }

    import cherrypy
    
    link_to_apple_global = ''
    
    class Orange(object):
        def __init__(self):
            pass
        @cherrypy.expose
        @cherrypy.tools.json_out()
        def index(self):
            return {"Orange and the link to apple: ": link_to_apple_global}
    class Page2(object):
    
        def __init__(self):
            pass
        @cherrypy.expose
        def index(self):
            return "Page2"
    class Apple(object):
    
        def __init__(self):
            pass
        @cherrypy.expose
        def index(self):
            return "Apple"
    
    class Page1(object):
    
        def __init__(self):
            pass
        @cherrypy.expose
        def index(self):
            return "Page1"
    
    class Root(object):
    
        def __init__(self):
            pass
        @cherrypy.expose
        def index(self):
            return "Root"            
    
    def reverse(cls):
        #return cherrypy.tree.apps.keys()
        #return dir(cherrypy.tree.apps[''].root)
        #return dir(cherrypy.tree.apps['/page3/apple'].root)
        # get link to apple
        for app_url in cherrypy.tree.apps.keys():
            if isinstance(cherrypy.tree.apps[app_url].root, cls):
                # NOTE: it will return with the first instance
                return app_url
    
    root = Root()
    root.page1 = Page1()
    root.page1.apple = Apple()
    root.page2 = Page2()
    root.page2.orange = Orange()
    
    cherrypy.tree.mount(root, '/')
    # if you do not specify the mount points you can find the objects
    # in cherrypy.tree.apps[''].root...
    cherrypy.tree.mount(root.page1, '/page4')
    cherrypy.tree.mount(root.page2, '/page3')
    cherrypy.tree.mount(root.page2.orange, '/page4/orange')
    cherrypy.tree.mount(root.page1.apple, '/page3/apple')
    
    link_to_apple_global = reverse(Apple)
    
    cherrypy.engine.start()
    cherrypy.engine.block()