| | 12 | |
| | 13 | The project is kept as simple as possible, while still showing many of Genshi features and how to best use them: |
| | 14 | * For persistence, we'll use native Python object serialization (via the `pickle` module), instead of an SQL database and an ORM. |
| | 15 | * There's no authentication of any kind. Anyone can submit links, anyone can comment. |
| | 16 | |
| | 17 | == Prerequisites == |
| | 18 | |
| | 19 | First, make sure you have !CherryPy 3.0.x installed, as well as recent versions of [http://formencode.org/ FormEncode], Genshi (obviously), and [http://pythonpaste.org/ Paste]. You can download and install those manually, or just use [http://peak.telecommunity.com/DevCenter/EasyInstall easy_install]: |
| | 20 | |
| | 21 | {{{ |
| | 22 | $ easy_install CherryPy |
| | 23 | $ easy_install FormEncode |
| | 24 | $ easy_install Genshi |
| | 25 | $ easy_install Paste |
| | 26 | }}} |
| | 27 | |
| | 28 | == Getting Started == |
| | 29 | |
| | 30 | Next, set up the basic !CherryPy application. Create a directory that should contain the application, and inside that directory create a Python package named `geddit` (basically a `geddit` directory containing an empty file called `__init__.py`. Inside that package, create a file called `controller.py` with the following content: |
| | 31 | |
| | 32 | {{{ |
| | 33 | #!python |
| | 34 | #!/usr/bin/env python |
| | 35 | |
| | 36 | import os |
| | 37 | import pickle |
| | 38 | import sys |
| | 39 | |
| | 40 | import cherrypy |
| | 41 | from paste.evalexception.middleware import EvalException |
| | 42 | |
| | 43 | |
| | 44 | class Root(object): |
| | 45 | |
| | 46 | def __init__(self, data): |
| | 47 | self.data = data |
| | 48 | |
| | 49 | @cherrypy.expose |
| | 50 | def index(self): |
| | 51 | return 'Geddit' |
| | 52 | |
| | 53 | |
| | 54 | def main(filename): |
| | 55 | # load data from the pickle file, or initialize it to an empty list |
| | 56 | if os.path.exists(filename): |
| | 57 | fileobj = open(filename, 'rb') |
| | 58 | try: |
| | 59 | data = pickle.load(fileobj) |
| | 60 | finally: |
| | 61 | fileobj.close() |
| | 62 | else: |
| | 63 | data = [] |
| | 64 | |
| | 65 | # save data back to the pickle file when the server is stopped |
| | 66 | def _save_data(): |
| | 67 | fileobj = open(filename, 'wb') |
| | 68 | try: |
| | 69 | pickle.dump(data, fileobj) |
| | 70 | finally: |
| | 71 | fileobj.close() |
| | 72 | cherrypy.engine.on_stop_engine_list.append(_save_data) |
| | 73 | |
| | 74 | # Some global configuration; note that this could be moved into a configuration file |
| | 75 | cherrypy.config.update({ |
| | 76 | 'request.throw_errors': True, |
| | 77 | 'tools.encode.on': True, |
| | 78 | 'tools.decode.on': True, |
| | 79 | 'tools.trailing_slash.on': True, |
| | 80 | 'tools.staticdir.root': os.path.abspath(os.path.dirname(__file__)), |
| | 81 | }) |
| | 82 | |
| | 83 | # Initialize the application, and add EvalException for more helpful error messages |
| | 84 | app = cherrypy.Application(Root(data)) |
| | 85 | app.wsgiapp.pipeline.append(('paste_exc', EvalException)) |
| | 86 | cherrypy.quickstart(app, '/', { |
| | 87 | '/media': { |
| | 88 | 'tools.staticdir.on': True, |
| | 89 | 'tools.staticdir.dir': 'static' |
| | 90 | } |
| | 91 | }) |
| | 92 | |
| | 93 | if __name__ == '__main__': |
| | 94 | main(sys.argv[1]) |
| | 95 | }}} |
| | 96 | |
| | 97 | Make that file executable, enter the tutorial directory in the terminal, and run: |
| | 98 | |
| | 99 | {{{ |
| | 100 | $ geddit/controller.py geddit.db |
| | 101 | }}} |
| | 102 | |
| | 103 | You should see a log message pointing you to the URL where the application is being served, which is usually http://localhost:8080/. Visiting that page will respond with just the string “Geddit”, as that's what the `index()` method of the `Root` object returns. |
| | 104 | |
| | 105 | Note that we've configured !CherryPy to serve static files from the `geddit/media` directory. !CherryPy will complain that that directory does not exist, so create it, but leave it empty for now. We'll add static resources later on in the tutorial. |
| | 106 | |
| | 107 | == Rendering from a Genshi Template == |
| | 108 | |
| | 109 | So far the code doesn't actually use Genshi, or even any kind of templating. Let's change that. |