Classic URL Style

4 views
Skip to first unread message

Humberto Diógenes

unread,
Nov 6, 2007, 2:35:54 PM11/6/07
to pylons-discuss
Hi!

I'm trying to port an existing mod_python app to Pylons, but had
some trouble with Routes. I'd like to keep using URLs the same
"classic" URL style:
http://localhost/location/edit?location_id=123

And then have Pylons receive it as arguments for the controller
method:

<code>
class LocationController(BaseController):
def edit(self, location_id):
return 'Editing %s' % location_id
</code>

But I'm getting this exception:
TypeError: edit() takes exactly 2 arguments (1 given)

Do you have any directions on what do I need to do to make it work?

--
Humberto Diógenes

Alberto Valverde

unread,
Nov 6, 2007, 2:44:15 PM11/6/07
to pylons-...@googlegroups.com

Yes, pull location_id from the request GET parameters:

employment_id = request.GET.get('employment_id')

Alberto

Humberto Diógenes

unread,
Nov 6, 2007, 3:23:47 PM11/6/07
to pylons-discuss

On Nov 6, 4:44 pm, Alberto Valverde <albe...@toscat.net> wrote:
> Humberto Diógenes wrote:
>
> > http://localhost/location/edit?location_id=123

>
> > class LocationController(BaseController):
> > def edit(self, location_id):
> > return 'Editing %s' % location_id
>
> > TypeError: edit() takes exactly 2 arguments (1 given)
>
> Yes, pull location_id from the request GET parameters:
>
> employment_id = request.GET.get('employment_id')

Thanks, Alberto. But as I said, I'm trying to port an old application
-- that means I would have to add one request.GET line for every
parameter in every controller function (and then remove all parameters
from the function signature).

I could do that, but what I'd really like to know is this: does Pylons
support query string "parameter injection"? If not, how difficult
would it be to implement that?

--
Humberto Diógenes
http://humberto.digi.com.br

Jose Galvez

unread,
Nov 6, 2007, 3:40:04 PM11/6/07
to pylons-...@googlegroups.com
you could add
for k,v in request.params:
locals()[k] = v
to the top f your functions

this would inject the variable names into your functions do you could
use them directly. I don't know what security risks this will bring up
however
Jose

Jonathan LaCour

unread,
Nov 6, 2007, 3:56:34 PM11/6/07
to pylons-...@googlegroups.com
Humberto Diógenes wrote:

> Thanks, Alberto. But as I said, I'm trying to port an old application
> -- that means I would have to add one request.GET line for every
> parameter in every controller function (and then remove all parameters
> from the function signature).
>
> I could do that, but what I'd really like to know is this: does Pylons
> support query string "parameter injection"? If not, how difficult
> would it be to implement that?

This past weekend, I participated in a sprint on Pylons where
we implemented two new controllers: DecoratedController and
ObjectDispatchController. Both of these controllers perform "parameter
injection." Here is an example of a DecoratedController:

from pylons.controllers import DecoratedController
from pylons.decorators import expose

class TestController(DecoratedController):

@expose()
def testing(self, name):
return 'Hello, %s' % name

Navigating your browser to '/test/testing?name=Humberto' will render the
string "Hello, Humberto." You can also render templates from Buffet
compatible engines by passing specific information into the expose
decorator, like so:

@expose('myproject.templates.testing')
def testing(self, name):
return dict(name=name)

The dictionary you return in the controller method will be used as the
namespace for your template. You can also render JSON by simply doing
@expose('json'). The expose decorator can be stacked:

@expose('json', content_type='application/json')
@expose('myproject.templates.testing', content_type='text/html')
def testing(self, name):
return dict(name=name)

You then send the `Accept:` header to perform content negotiation to
determine which output will be rendered.

This is all very new, so it probably has some bugs, but please do give
it a try, and we'll do our best to fix any bugs you find!

--
Jonathan LaCour
http://cleverdevil.org

Mike Orr

unread,
Nov 6, 2007, 4:01:20 PM11/6/07
to pylons-...@googlegroups.com
On 11/6/07, Jonathan LaCour <jonatha...@cleverdevil.org> wrote:
> The dictionary you return in the controller method will be used as the
> namespace for your template.

Are 'c' and the other Pylons variables implicitly added?

--
Mike Orr <slugg...@gmail.com>

Jonathan LaCour

unread,
Nov 6, 2007, 4:07:57 PM11/6/07
to pylons-...@googlegroups.com
Mike Orr wrote:

>> The dictionary you return in the controller method will be used as
>> the
>> namespace for your template.
>
> Are 'c' and the other Pylons variables implicitly added?

As of right now, they are not. You will have to return them as part of
the dictionary that is sent to your template.

Mike Orr

unread,
Nov 6, 2007, 4:11:27 PM11/6/07
to pylons-...@googlegroups.com
On 11/6/07, Jose Galvez <jj.g...@gmail.com> wrote:
>
> you could add
> for k,v in request.params:
> locals()[k] = v
> to the top f your functions
>
> this would inject the variable names into your functions do you could
> use them directly.

You can't modify local variables via locals(). Local variables are
implemented as an array with the names converted to subscripts at
compile time. The only exception is if the function contains an
'eval', which is slow and insecure (if the arg is untrusted).

===x1,py===
def test():
locals()["k"] = "v"
print k
if __name__ == "__main__": test()
===

$ python /tmp/x.py
Traceback (most recent call last):
File "/tmp/x.py", line 5, in <module>
if __name__ == "__main__": test()
File "/tmp/x.py", line 3, in test
print k
NameError: global name 'k' is not defined

If you put "k = 2" before the locals() call, it will print 2.


> I don't know what security risks this will bring up

A user might override one of your variables like 'filename_to_delete'.

--
Mike Orr <slugg...@gmail.com>

Jose Galvez

unread,
Nov 6, 2007, 4:29:09 PM11/6/07
to pylons-...@googlegroups.com
Thanks for the correction Mike
Jose

Humberto Diógenes

unread,
Nov 6, 2007, 5:37:22 PM11/6/07
to pylons-discuss

On Nov 6, 5:56 pm, Jonathan LaCour <jonathan-li...@cleverdevil.org>
wrote:


>
> This past weekend, I participated in a sprint on Pylons where
> we implemented two new controllers: DecoratedController and
> ObjectDispatchController. Both of these controllers perform "parameter
> injection." Here is an example of a DecoratedController:
>
> from pylons.controllers import DecoratedController
> from pylons.decorators import expose
>
> class TestController(DecoratedController):
>
> @expose()
> def testing(self, name):
> return 'Hello, %s' % name
>

> This is all very new, so it probably has some bugs, but please do give
> it a try, and we'll do our best to fix any bugs you find!
>


That's great! :)

I pulled the latest version from the repository but couldn't use it.


### Existing project:

URL: http://localhost:5000/location/index
File '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/
site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/error.py',
line 245 in respond
app_iter = self.application(environ, detect_start_response)
File '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/
site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/wsgiapp.py',
line 95 in __call__
controller = self.resolve(environ, start_response)
File '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/
site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/wsgiapp.py',
line 173 in resolve
match = environ['wsgiorg.routing_args'][1]
KeyError: 'wsgiorg.routing_args'

### New project:

$ paster create -t pylons PylonsTest2
[...]
OSError: [Errno 2] No such file or directory: '/Library/Frameworks/
Python.framework/Versions/2.4/lib/python2.4/site-packages/
Pylons-0.9.7dev_20071106-py2.4.egg/pylons/templates/default_project'

$ ls -l /Library/Frameworks/Python.framework/Versions/2.4/lib/
python2.4/site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/
templates/
-rwxr-xr-x 1 root admin 0 Nov 6 19:02 __init__.py
-rwxr-xr-x 1 root admin 221 Nov 6 19:02 __init__.pyc


I hope I'm not doing anything wrong. :P

Mike Orr

unread,
Nov 6, 2007, 6:22:15 PM11/6/07
to pylons-...@googlegroups.com
On 11/6/07, Humberto Diógenes <hdio...@gmail.com> wrote:
> I pulled the latest version from the repository but couldn't use it.
>
>
> ### Existing project:
>
> URL: http://localhost:5000/location/index
> File '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/
> site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/error.py',
> line 245 in respond
> app_iter = self.application(environ, detect_start_response)
> File '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/
> site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/wsgiapp.py',
> line 95 in __call__
> controller = self.resolve(environ, start_response)
> File '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/
> site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/wsgiapp.py',
> line 173 in resolve
> match = environ['wsgiorg.routing_args'][1]
> KeyError: 'wsgiorg.routing_args'

This is going to be a recurring problem with Pylons-dev. When
upgrading an app from Pylons 0.9.6 to 0.9.7, you have to add three
lines to middleware.py:


# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)

# Routing/Session/Cache Middleware
app = RoutesMiddleware(app, config['routes.map'])
app = SessionMiddleware(app, config)
app = CacheMiddleware(app, config)


Downgrading, you have to remove these lines, because Pylons 0.9.6
activates them implicitly.

> ### New project:
>
> $ paster create -t pylons PylonsTest2
> [...]
> OSError: [Errno 2] No such file or directory: '/Library/Frameworks/
> Python.framework/Versions/2.4/lib/python2.4/site-packages/
> Pylons-0.9.7dev_20071106-py2.4.egg/pylons/templates/default_project'
>
> $ ls -l /Library/Frameworks/Python.framework/Versions/2.4/lib/
> python2.4/site-packages/Pylons-0.9.7dev_20071106-py2.4.egg/pylons/
> templates/
> -rwxr-xr-x 1 root admin 0 Nov 6 19:02 __init__.py
> -rwxr-xr-x 1 root admin 221 Nov 6 19:02 __init__.pyc

It works for me, both with my existing dev snapshot (d3c5b6893348) and
after "hg pull -u" (a7756badfe81). Maybe you got an incomplete
update?

$ ls -l ~/mercurial/Pylons/pylons/templates
total 20
-rw-r--r-- 1 mso mso 281 2007-10-22 12:36 controller.py_tmpl
drwxr-xr-x 5 mso mso 4096 2007-10-22 12:36 default_project
-rw-r--r-- 1 mso mso 0 2007-10-22 12:36 __init__.py
drwxr-xr-x 4 mso mso 4096 2007-10-22 12:36 minimal_project
-rw-r--r-- 1 mso mso 2085 2007-10-22 12:36 restcontroller.py_tmpl
-rw-r--r-- 1 mso mso 200 2007-10-22 12:36 test_controller.py_tmpl

--
Mike Orr <slugg...@gmail.com>

Humberto Diógenes

unread,
Nov 6, 2007, 7:19:34 PM11/6/07
to pylons-discuss
On 06/11/2007, at 20:22, Mike Orr wrote:

>
> On 11/6/07, Humberto Diógenes <hdio...@gmail.com> wrote:
>> ### Existing project:
>> URL: http://localhost:5000/location/index

>> [...]


>> KeyError: 'wsgiorg.routing_args'
>
> This is going to be a recurring problem with Pylons-dev. When
> upgrading an app from Pylons 0.9.6 to 0.9.7, you have to add three
> lines to middleware.py:
>

> [...]


>
> Downgrading, you have to remove these lines, because Pylons 0.9.6
> activates them implicitly.
>

Thanks! It worked. Here goes the code with the right imports:


# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)

# Routing/Session/Cache Middleware (0.9.7 only, remove for 0.9.6)
from routes.middleware import RoutesMiddleware
from beaker.middleware import SessionMiddleware, CacheMiddleware

app = RoutesMiddleware(app, config['routes.map'])
app = SessionMiddleware(app, config)
app = CacheMiddleware(app, config)

>> ### New project:
>>
>> $ paster create -t pylons PylonsTest2
>> [...]
>> OSError: [Errno 2] No such file or directory: '/Library/Frameworks/
>> Python.framework/Versions/2.4/lib/python2.4/site-packages/
>> Pylons-0.9.7dev_20071106-py2.4.egg/pylons/templates/default_project'
>>
>

> It works for me (...) Maybe you got an incomplete update?

No, the update was OK, the files are in the checkout. I copied them
manually to Python site-packages and it worked.

I think there's something wrong with the install scripts. When I ran
"easy_install ." again, the templates were gone from site-packages.


Anyway, the new expose() decorator worked! Thanks!!! (although it
took a little to notice that BaseController was changed to
DecoratedController :-)

Mike Orr

unread,
Nov 6, 2007, 8:21:54 PM11/6/07
to pylons-...@googlegroups.com
On Nov 6, 2007 4:19 PM, Humberto Diógenes <hdio...@gmail.com> wrote:
> I think there's something wrong with the install scripts. When I ran
> "easy_install ." again, the templates were gone from site-packages.

is it possible to easy_install a development version in Mercurial?

I used "python setup.py develop"

--
Mike Orr <slugg...@gmail.com>

Mike Orr

unread,
Nov 7, 2007, 7:36:52 PM11/7/07
to pylons-...@googlegroups.com
I've added a comment to the "Development Version" wiki page re how to
make your middleware.py compatible with both Pylons 0.9.6 and dev.

http://wiki.pylonshq.com/display/pylonsdocs/Development+Version?focusedCommentId=11174468#comment-11174468

--
Mike Orr <slugg...@gmail.com>

Ben Bangert

unread,
Nov 8, 2007, 1:15:22 AM11/8/07
to pylons-...@googlegroups.com, Humberto Diógenes
Routes can handle this, though you'll need to 'post-process' the query arguments as a function condition:

In an app I'm working on right now, I have to handle some weird legacy URL's that work entirely based on query parameters, with the path portion being identical. No problem!

Try this in your routes...

from paste.wsgiwrappers import WSGIRequest

def fix_location(environ, result):
    req = WSGIRequest(environ)
    result['location'] = req.GET.get('location_id', '')
    return True

map.connect(':controller/:action', conditions=dict(function=fix_location))

Your function can now ask for 'location' as a function argument.

Note that since the same dict used for Routes that is passed into your controller, is also passed into your condition that verifies the route is valid (returning False causes it to not match), you can inject whatever you like from anything environ can see (remote ip, referer, etc.).

I'd highly recommend using this approach with Pylons 0.9.6.1, as pylons-dev is undergoing active development.

Cheers,
Ben
Reply all
Reply to author
Forward
0 new messages