title: Python Pyramid traversal
body: <p>I've been trying out pyramid and this traversal thing is sending me nuts. I'm basically fiddling around to make a control panel for a shopping cart and this is the basic structure that I have in mind.</p>
  
  <p>The login page</p>
  
  <pre><code>localhost:6543/admin_login
  </code></pre>
  
  <p>Upon successful login</p>
  
  <pre><code>localhost:6543/admin/home 
  </code></pre>
  
  <p>To view all existing products</p>
  
  <pre><code>localhost:6543/admin/product
  </code></pre>
  
  <p>To edit product X</p>
  
  <pre><code>localhost:6543/admin/product/edit/1
  </code></pre>
  
  <p>So my folder structure is something like this ( Capitalize files are models )</p>
  
  <ul>
  <li>mycart
  <ul>
  <li>resources.py</li>
  <li>Admin.py</li>
  <li>Product.py</li>
  <li>static</li>
  <li>templates</li>
  <li>views
  <ul>
  <li>__init__.py</li>
  <li>admin.py</li>
  <li>root.py</li>
  </ul></li>
  </ul></li>
  </ul>
  
  <p>My resources.py</p>
  
  <pre><code>    from pyramid.security import Authenticated
      from pyramid.security import Allow
      from pyramid.response import Response
  
      class Root(object):
         __name__ = ''
         __parent__ = None
  
         def __init__(self, request):
            pass
  
         def __getitem__(self, key):
  
             if key == 'admin_login':
                return Admin()
  
             elif key == 'admin':
                return Admin()
  
             raise KeyError
  
      class Admin(object):
  
          __name__ = ''
          __parent__ = Root
          __acl__ = [(Allow, Authenticated, 'admin')]
  
          def __init__(self):
             pass
  </code></pre>
  
  <p>In <code>views/__init.py</code>, it's simply a blank file.
  As for <code>root.py</code>, it's simply a <code>httpexceptions.HTTPNOTFOUND</code>, 404 code</p>
  
  <p>For <code>views/admin.py</code></p>
  
  <pre><code>    from pyramid.view import view_config, render_view
      import mycart.resources
  
      from pyramid.httpexceptions import HTTPNotFound, HTTPFound
      from mycart.views.root import strip_tags
      from pyramid_mailer import get_mailer
      from pyramid_mailer.message import Message
  
      from pyramid.security import remember , forget , authenticated_userid
  
      from pyramid.events import subscriber , BeforeRender
  
      from mycart.Admin import Admin
      from mycart.Product import Product
  
  
      @view_config(context='mycart:resources.Admin',   request_method='POST', renderer='admin/login.jinja2')
      def login_post(context, request):
  
        if 'btnLogin' in request.params:
          token = request.session.get_csrf_token()
          login = request.params['txtLogin']
          password = request.params['txtPassword']
  
          admin = Admin(login, request)
  
          if admin.validate_user( password):
  
              record = admin.find_user_by_login( login )
  
              request.session['bs_admin_id'] = str(record['_id'])
              request.session['bs_admin_name'] = record['usr']['fname'] + ' ' + record['usr']['lname'];
              request.session['bs_admin_type'] = record['usr']['type']
              headers = remember(request, login )
              return HTTPFound('/admin/home',  headers=headers)
  
          message = 'Failed login'
  
        return {'message': message,  'url': '/admin_login', 'page_title': 'Failed Login'}
  
  
        @view_config(context='mycart:resources.Admin', name="home", renderer='admin/home.jinja2', permission='admin')
        def home(context, request):
            logged_in = authenticated_userid(request)
            url = request.path_info
  
            admin = Admin( logged_in, request )
            rec = admin.find_user_by_objectid( request.session['bs_admin_id'] ) ;
  
            return { 'firstname': rec['usr']['fname']  }
  
  
       @view_config(context='mycart:resources.Admin', name="product", renderer='admin/product_listing.jinja2', permission='admin')
            def product_list(context, request):
            print ('yes, showing product listing requested by ', request.session['bs_admin_id'] )
  </code></pre>
  
  <p>After logging in, I point the url to localhost:6543/admin/product, I notice that it still rendering the home page, instead of the product page.</p>
  
  <p>I know I missed out something but I can't seem to find out why. Looking through <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/traversal.html" rel="nofollow">http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/traversal.html</a>, I know that I on the right track as there might be arbitary segments. </p>
  
  <p>I've tried modifying resources.py to be the following</p>
  
  <pre><code>   .....
  
     class Admin(object):
  
         __name__ = ''
         __parent__ = Root
         __acl__ = [(Allow, Authenticated, 'admin')]
  
         def __init__(self):
             pass
  
         def __getitem__(self, key):
  
            if key == 'product':
               print ("WOOT! Listing products")
               ## this is the part where I don't know what should I return or set or how should I hook it up with view_config
  
            if key == 'home':
               print ("yes, I'm home!")
               ## this is the part where I don't know what should I return or set or how should I hook it up with view_config
  
            raise KeyError
  </code></pre>
  
  <p>For this part, I made some progress where it's definitely printing the respective message in the console. However , I have no inkling how should I hook it up with the view_configs and what should be parameters be for the view_configs if any changes need to be made.</p>
  
  <p>I do not know if version affects anything but anyway, I am using python 3.3</p>
  
  <p>Any help will be appreciated. Thanks!</p>
  
  <p>This is my first time coding in python after years of java. So there might be some terms / concepts that I'm not familiar with respect to pyramid / python. </p>
  
  <hr>
  
  <p>Ok, I think I kinda got my mind to wrap around this traversal thing. Reading through <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/narr/traversal.html" rel="nofollow">http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/narr/traversal.html</a>, 2 things caught my attention.</p>
  
  <p>For example, if the path info sequence is ['a', 'b', 'c']:</p>
  
  <pre><code>- Traversal starts by acquiring the root resource of the application by calling the root   factory. The root factory can be configured to return whatever object is appropriate as the traversal root of your application.
  
  - Next, the first element ('a') is popped from the path segment sequence and is used as a key to lookup the corresponding resource in the root. This invokes the root resource’s __getitem__ method using that value ('a') as an argument.
  
  - If the root resource “contains” a resource with key 'a', its __getitem__ method will return it. The context temporarily becomes the “A” resource.
  </code></pre>
  
  <p>So based on localhost:6543/admin/products, the settings for view_config is like the following: </p>
  
  <p>@view_config(context=Admin, name='products', .... )</p>
  
  <p>So after making changes to resources.py</p>
  
  <pre><code>    ## class Root(object):
         ....
  
  
      class ProductName(object):
          def __init__(self, _key):
              pass
  
      class Products(object):
          __name__ = ''
          __parent__ = Root
  
  
          def __init__(self):
              pass
  
          def __getitem__(self, key):
              print ('products: ', key)
              if key == 'add':
                  return ProductName(key)
  
              print ('Approaching KeyError')
              raise KeyError
  
  
       class Admin(object):
  
          __name__ = ''
          __parent__ = Root
          __acl__ = [(Allow, Authenticated, 'admin')]
  
          def __init__(self):
              pass
  
  
          def __getitem__(self, key):
  
              if key == 'products':
                 print ('admin: ', key)
                 return Products()
  
              raise KeyError
  </code></pre>
  
  <p>And in views/admin.py</p>
  
  <pre><code>    @view_config(context=Admin, name='products',  renderer='admin/products.jinja2', permission = 'admin')
      def product_add(context, request):
          print 'hey products_add'
          return { 'msg': ''}
  </code></pre>
  
  <p>Somehow or rather, it isn't rendering the product template, but the default 404.</p>