| 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. |