查看文章 |
In the previous post I've showed you how to create the development environment, and this time we'll create an editting page for our blog. This page can either create a new post or edit an existing post. Let's name it "compose". To make life easier, I will not focus on the styling of our blog, so I'll just use the default master template that quickstart has generated for us. First, go to templates folder, and open master.kid. Turbogrears uses a templating system called kid, which is very well designed and easy to use. The master.kid acts like a framework of all the pages(of course you can choose not to inherit from it too), which includes a common header and a common footer, etc. We'll keep the header, content and footer, and remove all the unnecessary parts in the body tag like this(you can skip this part if you are happy with them): <body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()"> Much better. The next step is to create a compose page of our own. In the templates directory, rename welcome.kid to compose.kid, then open it. First, delete the unnecessary parts like this: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> Notice 'py:extends="'master.kid'"' indicates this page inherits from the master.kid, which means the header and footer and other stuff will be carried on to our compose page. Then open controller.py, delete the unnecessary parts like this: import turbogears as tg class Root(controllers.RootController): then we are ready to write the server side code for our compose page, which is defined in a function called compose. This function will be called when we visit http://localhost:8080/compose. @expose(template="blog.templates.compose") @expose is a special kind of function in python called the decorator. In this decorator, we specified a parameter called templates, indicates the template we are going to use. compose takes 1 or no parameter. bid is the id of the post we'll edit, and if it is not provided, we are creating a new one. We have to assign a category to our post when editing, so we need all the categories too. Finally, we return this blog object and all the categories back to our template file - compose.kid. <body> Let's walk through this line by line. <h1 py:if="blog">Edit Post</h1> this indicates, if the blog is None, then the page title will be Compose, meaning that we are creating a new post; else page name will be edit post, meaning that we are editing an existing post. The whole tag will not be created if the expression in py:if is not true. <input py:if="blog" type="hidden" name="bid" value="${blog.id}"/> if we are editing a post, we need to carry the id of our post on or there's no way we'll should update the changes to an existing post instead of creating a new one when we save it. Subject: <input name="subject" value="${blog.subject if blog else None}"/> this indicates the subject textbox will show the blog's subject if we are editing it, or will show nothing if we are creating a new post. Notice that if None is the value in ${}, then the whole value attribute will not be created. This is a very neat design because it won't leave a 'value=""' or 'value=' in the html generated, which could cause some trouble if we are dealing with attributes like 'selected' and 'checked', because if something like 'selected=""' is generated, the browser will regard it as the selected item just like any other items with 'selected="selected"' in their attributes, and this is not what is desired. <select name="category"> notice the py:for in the option. This means the kid template will generate len(categories) option tags, each with its category's id assigned to the value attribute, and a display text of the category's name. The generated code may be something like this: <select name="category"> Look how simple it is to generate a dropdown list with the kid template. Be ware that the kid template is a xml document so we cannot offer to generate code like: <option selected>Funny</option>. And now we are ready to see what we've got here. Save the files and start the web server. Navigate to http://localhost:8080/compose, we should be able to see the compose page now:
Cool! Now we'll have to define a function that can save the post. Remember the action attribute of our form in the compose page? Yes, we are going to create a function called 'saveblog'. @expose() notice that we have a "tostr" function here(defined outside the Root class): def tostr(s): This function is designed to handle unicode characters. I've left a comment behind every line of saveblog, which I think is already very self-explanatory. The only thing I want to point out is that we did not pass any parameters to the expose decorator, because there's no page to show. What this function does is to save the blog and then guide you the page where you can read it. After adding these 2 functions to your controllers.py, and hit the submit button on the compose page, you'll probably get a 404 error. That is because we haven't got the viewpost funcion ready yet. We'll create this page later. |
