Forums

web.py template problem with $code

im using templates, and am trying to read through a mysql data to create a table of records. the part of my code that im having trouble with is something like this...

$code:
    num = 7
    mytablerow = "<tr><td>" + num

but this gives me the error "cannot concatenate 'str' and 'int' objects", for obvious reasons. but when i try this...

$code:
    num = 7
    mytablerow = "<tr><td>" + str(num)

this gives me the error "global name 'str' is not defined", and i have no idea why it doesnt work in a template...because when i try it in my main .py file it works without a problem. so how do i get this to work in a $code: block in a template?? thanks

[edited by admin to fix code formatting]

oops i have no idea how to format my question above so the code is readable...if you could let me know how to do that, that would be good too. thanks

nevermind.... adding "str = str" when i render the template has made the str function available in my $code block.

Re: the template -- glad you got it working!

Re: formatting -- you need to put a blank line above and below code blocks so that they format properly -- I've edited your post to fix that and it looks OK now.

I've never used the web.py templating system, but according to this you can specify a globals parameter to the web.template.render which is a dictionary of extra global variables to make available to the template. It might be more convenient to build this dictionary once with all the additional builtins you need and just pass it into every render.

Still, if what you've got works then there's no need to change it - I just thought it might be worth mentioning in case it saves you making changes in lots of places in the future if you find there's another builtin you need.

thanks for your replies.

I had tried using the globals parameter, but when i do so i get the error:

__template__() got an unexpected keyword argument 'globals'

so this works for me:

return render.headers("templates",str = str)

but this doesnt:

return render.headers("templates",globals={'str': str})

any ideas why that might be?...because everything i read suggests to use the globals way...

Again, I'm definitely not an expert, but it sounds to me like you're passing globals when you want to actually render the string. From their tutorial it looks like they expect you to create a global instance of the renderer and pass globals at that point, so it's a fixed mapping for all template renders. Then you call the appropriate method on that instance to render each template - to this you don't need to pass the template directory each time, just the parameters for the template.

For example, I created this template as templates/hello.html:

$def with (name)

$code:
    value = 123
    title = "Easy as " + str(value)

<html>
  <head>
    <title>$title</title>
  </head>
  <body>
    <h1>$title</h1>
    <p>Hello, $name</p>
  </body>
</html>

And then I used the following Python session to create a renderer and use it, first without passing a globals (hence causing an exception due to a lack of str) and then with the appropriate globals:

>>> import web
>>> render = web.template.render("templates")
>>> print render.hello("world")
Traceback (most recent call last):
  [... traceback omitted for clarify ...]
NameError: global name 'str' is not defined
>>>
>>> render = web.template.render("templates", globals={"str": str})
>>> print render.hello("world")

<html>
  <head>
    <title>Easy as 123</title>
  </head>
  <body>
    <h1>Easy as 123</h1>
    <p>Hello, world</p>
  </body>
</html>

In your case, you'll presumably create the render instance globally, or in some other static storage, and pass both the templates directory and the globals to it on construction. The crucial point here is that you do this once when your web app is initialised, and not for every request. Then to generate your HTTP responses, you'll call the template methods on this static instance as I've done above with my hello.html template.

Does that help?

i see!...what i was doing wrong was trying to set globals for every request instead of when the render was initialized.

it all makes sense now and is working as expected.

thanks for the explanation. :-)

You're quite welcome and I'm glad to hear it's working out for you.