mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-20 16:03:59 +01:00
first full commit
This commit is contained in:
@@ -1,16 +0,0 @@
|
|||||||
CherryPy Tutorials
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
|
|
||||||
This is a series of tutorials explaining how to develop dynamic web
|
|
||||||
applications using CherryPy. A couple of notes:
|
|
||||||
|
|
||||||
- Each of these tutorials builds on the ones before it. If you're
|
|
||||||
new to CherryPy, we recommend you start with 01_helloworld.py and
|
|
||||||
work your way upwards. :)
|
|
||||||
|
|
||||||
- In most of these tutorials, you will notice that all output is done
|
|
||||||
by returning normal Python strings, often using simple Python
|
|
||||||
variable substitution. In most real-world applications, you will
|
|
||||||
probably want to use a separate template package (like Cheetah,
|
|
||||||
CherryTemplate or XML/XSL).
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
# This is used in test_config to test unrepr of "from A import B"
|
|
||||||
thing2 = object()
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
'''
|
|
||||||
Bonus Tutorial: Using SQLObject
|
|
||||||
|
|
||||||
This is a silly little contacts manager application intended to
|
|
||||||
demonstrate how to use SQLObject from within a CherryPy2 project. It
|
|
||||||
also shows how to use inline Cheetah templates.
|
|
||||||
|
|
||||||
SQLObject is an Object/Relational Mapper that allows you to access
|
|
||||||
data stored in an RDBMS in a pythonic fashion. You create data objects
|
|
||||||
as Python classes and let SQLObject take care of all the nasty details.
|
|
||||||
|
|
||||||
This code depends on the latest development version (0.6+) of SQLObject.
|
|
||||||
You can get it from the SQLObject Subversion server. You can find all
|
|
||||||
necessary information at <http://www.sqlobject.org>. This code will NOT
|
|
||||||
work with the 0.5.x version advertised on their website!
|
|
||||||
|
|
||||||
This code also depends on a recent version of Cheetah. You can find
|
|
||||||
Cheetah at <http://www.cheetahtemplate.org>.
|
|
||||||
|
|
||||||
After starting this application for the first time, you will need to
|
|
||||||
access the /reset URI in order to create the database table and some
|
|
||||||
sample data. Accessing /reset again will drop and re-create the table,
|
|
||||||
so you may want to be careful. :-)
|
|
||||||
|
|
||||||
This application isn't supposed to be fool-proof, it's not even supposed
|
|
||||||
to be very GOOD. Play around with it some, browse the source code, smile.
|
|
||||||
|
|
||||||
:)
|
|
||||||
|
|
||||||
-- Hendrik Mans <hendrik@mans.de>
|
|
||||||
'''
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
from Cheetah.Template import Template
|
|
||||||
from sqlobject import *
|
|
||||||
|
|
||||||
# configure your database connection here
|
|
||||||
__connection__ = 'mysql://root:@localhost/test'
|
|
||||||
|
|
||||||
# this is our (only) data class.
|
|
||||||
class Contact(SQLObject):
|
|
||||||
lastName = StringCol(length = 50, notNone = True)
|
|
||||||
firstName = StringCol(length = 50, notNone = True)
|
|
||||||
phone = StringCol(length = 30, notNone = True, default = '')
|
|
||||||
email = StringCol(length = 30, notNone = True, default = '')
|
|
||||||
url = StringCol(length = 100, notNone = True, default = '')
|
|
||||||
|
|
||||||
|
|
||||||
class ContactManager:
|
|
||||||
def index(self):
|
|
||||||
# Let's display a list of all stored contacts.
|
|
||||||
contacts = Contact.select()
|
|
||||||
|
|
||||||
template = Template('''
|
|
||||||
<h2>All Contacts</h2>
|
|
||||||
|
|
||||||
#for $contact in $contacts
|
|
||||||
<a href="mailto:$contact.email">$contact.lastName, $contact.firstName</a>
|
|
||||||
[<a href="./edit?id=$contact.id">Edit</a>]
|
|
||||||
[<a href="./delete?id=$contact.id">Delete</a>]
|
|
||||||
<br/>
|
|
||||||
#end for
|
|
||||||
|
|
||||||
<p>[<a href="./edit">Add new contact</a>]</p>
|
|
||||||
''', [locals(), globals()])
|
|
||||||
|
|
||||||
return template.respond()
|
|
||||||
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
def edit(self, id = 0):
|
|
||||||
# we really want id as an integer. Since GET/POST parameters
|
|
||||||
# are always passed as strings, let's convert it.
|
|
||||||
id = int(id)
|
|
||||||
|
|
||||||
if id > 0:
|
|
||||||
# if an id is specified, we're editing an existing contact.
|
|
||||||
contact = Contact.get(id)
|
|
||||||
title = "Edit Contact"
|
|
||||||
else:
|
|
||||||
# if no id is specified, we're entering a new contact.
|
|
||||||
contact = None
|
|
||||||
title = "New Contact"
|
|
||||||
|
|
||||||
|
|
||||||
# In the following template code, please note that we use
|
|
||||||
# Cheetah's $getVar() construct for the form values. We have
|
|
||||||
# to do this because contact may be set to None (see above).
|
|
||||||
template = Template('''
|
|
||||||
<h2>$title</h2>
|
|
||||||
|
|
||||||
<form action="./store" method="POST">
|
|
||||||
<input type="hidden" name="id" value="$id" />
|
|
||||||
Last Name: <input name="lastName" value="$getVar('contact.lastName', '')" /><br/>
|
|
||||||
First Name: <input name="firstName" value="$getVar('contact.firstName', '')" /><br/>
|
|
||||||
Phone: <input name="phone" value="$getVar('contact.phone', '')" /><br/>
|
|
||||||
Email: <input name="email" value="$getVar('contact.email', '')" /><br/>
|
|
||||||
URL: <input name="url" value="$getVar('contact.url', '')" /><br/>
|
|
||||||
<input type="submit" value="Store" />
|
|
||||||
</form>
|
|
||||||
''', [locals(), globals()])
|
|
||||||
|
|
||||||
return template.respond()
|
|
||||||
|
|
||||||
edit.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
def delete(self, id):
|
|
||||||
# Delete the specified contact
|
|
||||||
contact = Contact.get(int(id))
|
|
||||||
contact.destroySelf()
|
|
||||||
return 'Deleted. <a href="./">Return to Index</a>'
|
|
||||||
|
|
||||||
delete.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
def store(self, lastName, firstName, phone, email, url, id = None):
|
|
||||||
if id and int(id) > 0:
|
|
||||||
# If an id was specified, update an existing contact.
|
|
||||||
contact = Contact.get(int(id))
|
|
||||||
|
|
||||||
# We could set one field after another, but that would
|
|
||||||
# cause multiple UPDATE clauses. So we'll just do it all
|
|
||||||
# in a single pass through the set() method.
|
|
||||||
contact.set(
|
|
||||||
lastName = lastName,
|
|
||||||
firstName = firstName,
|
|
||||||
phone = phone,
|
|
||||||
email = email,
|
|
||||||
url = url)
|
|
||||||
else:
|
|
||||||
# Otherwise, add a new contact.
|
|
||||||
contact = Contact(
|
|
||||||
lastName = lastName,
|
|
||||||
firstName = firstName,
|
|
||||||
phone = phone,
|
|
||||||
email = email,
|
|
||||||
url = url)
|
|
||||||
|
|
||||||
return 'Stored. <a href="./">Return to Index</a>'
|
|
||||||
|
|
||||||
store.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
# Drop existing table
|
|
||||||
Contact.dropTable(True)
|
|
||||||
|
|
||||||
# Create new table
|
|
||||||
Contact.createTable()
|
|
||||||
|
|
||||||
# Create some sample data
|
|
||||||
Contact(
|
|
||||||
firstName = 'Hendrik',
|
|
||||||
lastName = 'Mans',
|
|
||||||
email = 'hendrik@mans.de',
|
|
||||||
phone = '++49 89 12345678',
|
|
||||||
url = 'http://www.mornography.de')
|
|
||||||
|
|
||||||
return "reset completed!"
|
|
||||||
|
|
||||||
reset.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
print("If you're running this application for the first time, please go to http://localhost:8080/reset once in order to create the database!")
|
|
||||||
|
|
||||||
cherrypy.quickstart(ContactManager())
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>403 Unauthorized</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h2>You can't do that!</h2>
|
|
||||||
<p>%(message)s</p>
|
|
||||||
<p>This is a custom error page that is read from a file.<p>
|
|
||||||
<pre>%(traceback)s</pre>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Binary file not shown.
@@ -1,35 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - Hello World
|
|
||||||
|
|
||||||
The most basic (working) CherryPy application possible.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Import CherryPy global namespace
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
class HelloWorld:
|
|
||||||
""" Sample request handler class. """
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# CherryPy will call this method for the root URI ("/") and send
|
|
||||||
# its return value to the client. Because this is tutorial
|
|
||||||
# lesson number 01, we'll just send something really simple.
|
|
||||||
# How about...
|
|
||||||
return "Hello world!"
|
|
||||||
|
|
||||||
# Expose the index method through the web. CherryPy will never
|
|
||||||
# publish methods that don't have the exposed attribute set to True.
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(HelloWorld(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(HelloWorld(), config=tutconf)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - Multiple methods
|
|
||||||
|
|
||||||
This tutorial shows you how to link to other methods of your request
|
|
||||||
handler.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
class HelloWorld:
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Let's link to another method here.
|
|
||||||
return 'We have an <a href="showMessage">important message</a> for you!'
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
def showMessage(self):
|
|
||||||
# Here's the important message!
|
|
||||||
return "Hello world!"
|
|
||||||
showMessage.exposed = True
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(HelloWorld(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(HelloWorld(), config=tutconf)
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - Passing variables
|
|
||||||
|
|
||||||
This tutorial shows you how to pass GET/POST variables to methods.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class WelcomePage:
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Ask for the user's name.
|
|
||||||
return '''
|
|
||||||
<form action="greetUser" method="GET">
|
|
||||||
What is your name?
|
|
||||||
<input type="text" name="name" />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>'''
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
def greetUser(self, name = None):
|
|
||||||
# CherryPy passes all GET and POST variables as method parameters.
|
|
||||||
# It doesn't make a difference where the variables come from, how
|
|
||||||
# large their contents are, and so on.
|
|
||||||
#
|
|
||||||
# You can define default parameter values as usual. In this
|
|
||||||
# example, the "name" parameter defaults to None so we can check
|
|
||||||
# if a name was actually specified.
|
|
||||||
|
|
||||||
if name:
|
|
||||||
# Greet the user!
|
|
||||||
return "Hey %s, what's up?" % name
|
|
||||||
else:
|
|
||||||
if name is None:
|
|
||||||
# No name was specified
|
|
||||||
return 'Please enter your name <a href="./">here</a>.'
|
|
||||||
else:
|
|
||||||
return 'No, really, enter your name <a href="./">here</a>.'
|
|
||||||
greetUser.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(WelcomePage(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(WelcomePage(), config=tutconf)
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - Multiple objects
|
|
||||||
|
|
||||||
This tutorial shows you how to create a site structure through multiple
|
|
||||||
possibly nested request handler objects.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class HomePage:
|
|
||||||
def index(self):
|
|
||||||
return '''
|
|
||||||
<p>Hi, this is the home page! Check out the other
|
|
||||||
fun stuff on this site:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="/joke/">A silly joke</a></li>
|
|
||||||
<li><a href="/links/">Useful links</a></li>
|
|
||||||
</ul>'''
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
class JokePage:
|
|
||||||
def index(self):
|
|
||||||
return '''
|
|
||||||
<p>"In Python, how do you create a string of random
|
|
||||||
characters?" -- "Read a Perl file!"</p>
|
|
||||||
<p>[<a href="../">Return</a>]</p>'''
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
class LinksPage:
|
|
||||||
def __init__(self):
|
|
||||||
# Request handler objects can create their own nested request
|
|
||||||
# handler objects. Simply create them inside their __init__
|
|
||||||
# methods!
|
|
||||||
self.extra = ExtraLinksPage()
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Note the way we link to the extra links page (and back).
|
|
||||||
# As you can see, this object doesn't really care about its
|
|
||||||
# absolute position in the site tree, since we use relative
|
|
||||||
# links exclusively.
|
|
||||||
return '''
|
|
||||||
<p>Here are some useful links:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="http://www.cherrypy.org">The CherryPy Homepage</a></li>
|
|
||||||
<li><a href="http://www.python.org">The Python Homepage</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>You can check out some extra useful
|
|
||||||
links <a href="./extra/">here</a>.</p>
|
|
||||||
|
|
||||||
<p>[<a href="../">Return</a>]</p>
|
|
||||||
'''
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
class ExtraLinksPage:
|
|
||||||
def index(self):
|
|
||||||
# Note the relative link back to the Links page!
|
|
||||||
return '''
|
|
||||||
<p>Here are some extra useful links:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="http://del.icio.us">del.icio.us</a></li>
|
|
||||||
<li><a href="http://www.mornography.de">Hendrik's weblog</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>[<a href="../">Return to links page</a>]</p>'''
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
# Of course we can also mount request handler objects right here!
|
|
||||||
root = HomePage()
|
|
||||||
root.joke = JokePage()
|
|
||||||
root.links = LinksPage()
|
|
||||||
|
|
||||||
# Remember, we don't need to mount ExtraLinksPage here, because
|
|
||||||
# LinksPage does that itself on initialization. In fact, there is
|
|
||||||
# no reason why you shouldn't let your root object take care of
|
|
||||||
# creating all contained request handler objects.
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(root, config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(root, config=tutconf)
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - Object inheritance
|
|
||||||
|
|
||||||
You are free to derive your request handler classes from any base
|
|
||||||
class you wish. In most real-world applications, you will probably
|
|
||||||
want to create a central base class used for all your pages, which takes
|
|
||||||
care of things like printing a common page header and footer.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class Page:
|
|
||||||
# Store the page title in a class attribute
|
|
||||||
title = 'Untitled Page'
|
|
||||||
|
|
||||||
def header(self):
|
|
||||||
return '''
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>%s</title>
|
|
||||||
<head>
|
|
||||||
<body>
|
|
||||||
<h2>%s</h2>
|
|
||||||
''' % (self.title, self.title)
|
|
||||||
|
|
||||||
def footer(self):
|
|
||||||
return '''
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Note that header and footer don't get their exposed attributes
|
|
||||||
# set to True. This isn't necessary since the user isn't supposed
|
|
||||||
# to call header or footer directly; instead, we'll call them from
|
|
||||||
# within the actually exposed handler methods defined in this
|
|
||||||
# class' subclasses.
|
|
||||||
|
|
||||||
|
|
||||||
class HomePage(Page):
|
|
||||||
# Different title for this page
|
|
||||||
title = 'Tutorial 5'
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
# create a subpage
|
|
||||||
self.another = AnotherPage()
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Note that we call the header and footer methods inherited
|
|
||||||
# from the Page class!
|
|
||||||
return self.header() + '''
|
|
||||||
<p>
|
|
||||||
Isn't this exciting? There's
|
|
||||||
<a href="./another/">another page</a>, too!
|
|
||||||
</p>
|
|
||||||
''' + self.footer()
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
class AnotherPage(Page):
|
|
||||||
title = 'Another Page'
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
return self.header() + '''
|
|
||||||
<p>
|
|
||||||
And this is the amazing second page!
|
|
||||||
</p>
|
|
||||||
''' + self.footer()
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(HomePage(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(HomePage(), config=tutconf)
|
|
||||||
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - The default method
|
|
||||||
|
|
||||||
Request handler objects can implement a method called "default" that
|
|
||||||
is called when no other suitable method/object could be found.
|
|
||||||
Essentially, if CherryPy2 can't find a matching request handler object
|
|
||||||
for the given request URI, it will use the default method of the object
|
|
||||||
located deepest on the URI path.
|
|
||||||
|
|
||||||
Using this mechanism you can easily simulate virtual URI structures
|
|
||||||
by parsing the extra URI string, which you can access through
|
|
||||||
cherrypy.request.virtualPath.
|
|
||||||
|
|
||||||
The application in this tutorial simulates an URI structure looking
|
|
||||||
like /users/<username>. Since the <username> bit will not be found (as
|
|
||||||
there are no matching methods), it is handled by the default method.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class UsersPage:
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Since this is just a stupid little example, we'll simply
|
|
||||||
# display a list of links to random, made-up users. In a real
|
|
||||||
# application, this could be generated from a database result set.
|
|
||||||
return '''
|
|
||||||
<a href="./remi">Remi Delon</a><br/>
|
|
||||||
<a href="./hendrik">Hendrik Mans</a><br/>
|
|
||||||
<a href="./lorenzo">Lorenzo Lamas</a><br/>
|
|
||||||
'''
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
def default(self, user):
|
|
||||||
# Here we react depending on the virtualPath -- the part of the
|
|
||||||
# path that could not be mapped to an object method. In a real
|
|
||||||
# application, we would probably do some database lookups here
|
|
||||||
# instead of the silly if/elif/else construct.
|
|
||||||
if user == 'remi':
|
|
||||||
out = "Remi Delon, CherryPy lead developer"
|
|
||||||
elif user == 'hendrik':
|
|
||||||
out = "Hendrik Mans, CherryPy co-developer & crazy German"
|
|
||||||
elif user == 'lorenzo':
|
|
||||||
out = "Lorenzo Lamas, famous actor and singer!"
|
|
||||||
else:
|
|
||||||
out = "Unknown user. :-("
|
|
||||||
|
|
||||||
return '%s (<a href="./">back</a>)' % out
|
|
||||||
default.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(UsersPage(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(UsersPage(), config=tutconf)
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
"""
|
|
||||||
Tutorial - Sessions
|
|
||||||
|
|
||||||
Storing session data in CherryPy applications is very easy: cherrypy
|
|
||||||
provides a dictionary called "session" that represents the session
|
|
||||||
data for the current user. If you use RAM based sessions, you can store
|
|
||||||
any kind of object into that dictionary; otherwise, you are limited to
|
|
||||||
objects that can be pickled.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class HitCounter:
|
|
||||||
|
|
||||||
_cp_config = {'tools.sessions.on': True}
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Increase the silly hit counter
|
|
||||||
count = cherrypy.session.get('count', 0) + 1
|
|
||||||
|
|
||||||
# Store the new value in the session dictionary
|
|
||||||
cherrypy.session['count'] = count
|
|
||||||
|
|
||||||
# And display a silly hit count message!
|
|
||||||
return '''
|
|
||||||
During your current session, you've viewed this
|
|
||||||
page %s times! Your life is a patio of fun!
|
|
||||||
''' % count
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(HitCounter(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(HitCounter(), config=tutconf)
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
"""
|
|
||||||
Bonus Tutorial: Using generators to return result bodies
|
|
||||||
|
|
||||||
Instead of returning a complete result string, you can use the yield
|
|
||||||
statement to return one result part after another. This may be convenient
|
|
||||||
in situations where using a template package like CherryPy or Cheetah
|
|
||||||
would be overkill, and messy string concatenation too uncool. ;-)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class GeneratorDemo:
|
|
||||||
|
|
||||||
def header(self):
|
|
||||||
return "<html><body><h2>Generators rule!</h2>"
|
|
||||||
|
|
||||||
def footer(self):
|
|
||||||
return "</body></html>"
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# Let's make up a list of users for presentation purposes
|
|
||||||
users = ['Remi', 'Carlos', 'Hendrik', 'Lorenzo Lamas']
|
|
||||||
|
|
||||||
# Every yield line adds one part to the total result body.
|
|
||||||
yield self.header()
|
|
||||||
yield "<h3>List of users:</h3>"
|
|
||||||
|
|
||||||
for user in users:
|
|
||||||
yield "%s<br/>" % user
|
|
||||||
|
|
||||||
yield self.footer()
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(GeneratorDemo(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(GeneratorDemo(), config=tutconf)
|
|
||||||
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
"""
|
|
||||||
|
|
||||||
Tutorial: File upload and download
|
|
||||||
|
|
||||||
Uploads
|
|
||||||
-------
|
|
||||||
|
|
||||||
When a client uploads a file to a CherryPy application, it's placed
|
|
||||||
on disk immediately. CherryPy will pass it to your exposed method
|
|
||||||
as an argument (see "myFile" below); that arg will have a "file"
|
|
||||||
attribute, which is a handle to the temporary uploaded file.
|
|
||||||
If you wish to permanently save the file, you need to read()
|
|
||||||
from myFile.file and write() somewhere else.
|
|
||||||
|
|
||||||
Note the use of 'enctype="multipart/form-data"' and 'input type="file"'
|
|
||||||
in the HTML which the client uses to upload the file.
|
|
||||||
|
|
||||||
|
|
||||||
Downloads
|
|
||||||
---------
|
|
||||||
|
|
||||||
If you wish to send a file to the client, you have two options:
|
|
||||||
First, you can simply return a file-like object from your page handler.
|
|
||||||
CherryPy will read the file and serve it as the content (HTTP body)
|
|
||||||
of the response. However, that doesn't tell the client that
|
|
||||||
the response is a file to be saved, rather than displayed.
|
|
||||||
Use cherrypy.lib.static.serve_file for that; it takes four
|
|
||||||
arguments:
|
|
||||||
|
|
||||||
serve_file(path, content_type=None, disposition=None, name=None)
|
|
||||||
|
|
||||||
Set "name" to the filename that you expect clients to use when they save
|
|
||||||
your file. Note that the "name" argument is ignored if you don't also
|
|
||||||
provide a "disposition" (usually "attachement"). You can manually set
|
|
||||||
"content_type", but be aware that if you also use the encoding tool, it
|
|
||||||
may choke if the file extension is not recognized as belonging to a known
|
|
||||||
Content-Type. Setting the content_type to "application/x-download" works
|
|
||||||
in most cases, and should prompt the user with an Open/Save dialog in
|
|
||||||
popular browsers.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
localDir = os.path.dirname(__file__)
|
|
||||||
absDir = os.path.join(os.getcwd(), localDir)
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
from cherrypy.lib import static
|
|
||||||
|
|
||||||
|
|
||||||
class FileDemo(object):
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
return """
|
|
||||||
<html><body>
|
|
||||||
<h2>Upload a file</h2>
|
|
||||||
<form action="upload" method="post" enctype="multipart/form-data">
|
|
||||||
filename: <input type="file" name="myFile" /><br />
|
|
||||||
<input type="submit" />
|
|
||||||
</form>
|
|
||||||
<h2>Download a file</h2>
|
|
||||||
<a href='download'>This one</a>
|
|
||||||
</body></html>
|
|
||||||
"""
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
def upload(self, myFile):
|
|
||||||
out = """<html>
|
|
||||||
<body>
|
|
||||||
myFile length: %s<br />
|
|
||||||
myFile filename: %s<br />
|
|
||||||
myFile mime-type: %s
|
|
||||||
</body>
|
|
||||||
</html>"""
|
|
||||||
|
|
||||||
# Although this just counts the file length, it demonstrates
|
|
||||||
# how to read large files in chunks instead of all at once.
|
|
||||||
# CherryPy reads the uploaded file into a temporary file;
|
|
||||||
# myFile.file.read reads from that.
|
|
||||||
size = 0
|
|
||||||
while True:
|
|
||||||
data = myFile.file.read(8192)
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
size += len(data)
|
|
||||||
|
|
||||||
return out % (size, myFile.filename, myFile.content_type)
|
|
||||||
upload.exposed = True
|
|
||||||
|
|
||||||
def download(self):
|
|
||||||
path = os.path.join(absDir, "pdf_file.pdf")
|
|
||||||
return static.serve_file(path, "application/x-download",
|
|
||||||
"attachment", os.path.basename(path))
|
|
||||||
download.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(FileDemo(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(FileDemo(), config=tutconf)
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
"""
|
|
||||||
|
|
||||||
Tutorial: HTTP errors
|
|
||||||
|
|
||||||
HTTPError is used to return an error response to the client.
|
|
||||||
CherryPy has lots of options regarding how such errors are
|
|
||||||
logged, displayed, and formatted.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
localDir = os.path.dirname(__file__)
|
|
||||||
curpath = os.path.normpath(os.path.join(os.getcwd(), localDir))
|
|
||||||
|
|
||||||
import cherrypy
|
|
||||||
|
|
||||||
|
|
||||||
class HTTPErrorDemo(object):
|
|
||||||
|
|
||||||
# Set a custom response for 403 errors.
|
|
||||||
_cp_config = {'error_page.403' : os.path.join(curpath, "custom_error.html")}
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
# display some links that will result in errors
|
|
||||||
tracebacks = cherrypy.request.show_tracebacks
|
|
||||||
if tracebacks:
|
|
||||||
trace = 'off'
|
|
||||||
else:
|
|
||||||
trace = 'on'
|
|
||||||
|
|
||||||
return """
|
|
||||||
<html><body>
|
|
||||||
<p>Toggle tracebacks <a href="toggleTracebacks">%s</a></p>
|
|
||||||
<p><a href="/doesNotExist">Click me; I'm a broken link!</a></p>
|
|
||||||
<p><a href="/error?code=403">Use a custom error page from a file.</a></p>
|
|
||||||
<p>These errors are explicitly raised by the application:</p>
|
|
||||||
<ul>
|
|
||||||
<li><a href="/error?code=400">400</a></li>
|
|
||||||
<li><a href="/error?code=401">401</a></li>
|
|
||||||
<li><a href="/error?code=402">402</a></li>
|
|
||||||
<li><a href="/error?code=500">500</a></li>
|
|
||||||
</ul>
|
|
||||||
<p><a href="/messageArg">You can also set the response body
|
|
||||||
when you raise an error.</a></p>
|
|
||||||
</body></html>
|
|
||||||
""" % trace
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
def toggleTracebacks(self):
|
|
||||||
# simple function to toggle tracebacks on and off
|
|
||||||
tracebacks = cherrypy.request.show_tracebacks
|
|
||||||
cherrypy.config.update({'request.show_tracebacks': not tracebacks})
|
|
||||||
|
|
||||||
# redirect back to the index
|
|
||||||
raise cherrypy.HTTPRedirect('/')
|
|
||||||
toggleTracebacks.exposed = True
|
|
||||||
|
|
||||||
def error(self, code):
|
|
||||||
# raise an error based on the get query
|
|
||||||
raise cherrypy.HTTPError(status = code)
|
|
||||||
error.exposed = True
|
|
||||||
|
|
||||||
def messageArg(self):
|
|
||||||
message = ("If you construct an HTTPError with a 'message' "
|
|
||||||
"argument, it wil be placed on the error page "
|
|
||||||
"(underneath the status line by default).")
|
|
||||||
raise cherrypy.HTTPError(500, message=message)
|
|
||||||
messageArg.exposed = True
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# CherryPy always starts with app.root when trying to map request URIs
|
|
||||||
# to objects, so we need to mount a request handler root. A request
|
|
||||||
# to '/' will be mapped to HelloWorld().index().
|
|
||||||
cherrypy.quickstart(HTTPErrorDemo(), config=tutconf)
|
|
||||||
else:
|
|
||||||
# This branch is for the test suite; you can ignore it.
|
|
||||||
cherrypy.tree.mount(HTTPErrorDemo(), config=tutconf)
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
[global]
|
|
||||||
server.socket_host = "127.0.0.1"
|
|
||||||
server.socket_port = 8181
|
|
||||||
server.thread_pool = 10
|
|
||||||
Reference in New Issue
Block a user