Install Python 2.7 and then run:
easy_install flask sqlalchemy coffeescript alembic twilio
easy_install --index-url https://code.stripe.com --upgrade stripe
git clone https://github.com/trentm/python-markdown2.git
cd python-markdown2
sudo python setup.py install
Or, install pip and then run:
pip install -r requirements.txt
Scripts can be placed in the scripts/
directory. They can either be .js
or .coffee
. CoffeeScript source will be cached after compilation.
To reference from HTML, use scripts/foo.js
no matter whether it's Javascript or CoffeeScript.
Example file, handlers/echo.py
:
from handler import handler
@handler
def get_index(id, bar=None):
return 'foo %r %r' % (id, bar)
This will create a route for /echo/<id>
that takes an optional GET parameter called bar
. Hitting /echo/blah?bar=baz
will return: foo u'blah' u'baz'
. Note the unicode strings.
If you are modifying data, make sure you start your function name with post_
rather than get_
. This enforces the POST method and will require a CSRF token.
Routes are generated based on handler module name and method name. The code for this is really straightforward:
if module == 'index':
route = '/'
else:
route = '/%s/' % module
if name != 'index':
route += '%s/' % name
if len(args) and args[0] == 'id':
route += '<id>'
So that means that a handler module named index.py
is the very root of the web app. A method named index
(GET or POST -- you can have both if it makes sense!) is the root of a given handler. So the application's handler for /
is a method named get_index
in a handler module named index.py
. Got it? Good.
The id
argument must be the first to the function if you want to have it. This is handy for URLs like /user/55
. All non-id arguments are optional. Handle their non-existence or perish.
One additional way to use handlers is to automatically spit out JSON or put your data into a template.
@handler(json=True)
def get_foo():
return True
This will return true
as it's JSON-encoded.
@handler('login')
def get_login():
return dict(status='Login failed')
This will automatically output your login template (templates/login.html
) with the status variable assigned.
Handlers can also provide automatic RPC.
@handler
def rpc_foo(blah):
return dict(foo='bar', arg=blah)
This will automatically generate an RPC stub, which can be called from CoffeeScript:
$rpc.ourhandlermodule.foo 'baz', (data) ->
console.log data
This will print out a dict {foo: 'bar', arg: 'baz'}
. RPC methods cannot take id
(they're assumed to just be another parameter), always return JSON, and can't have a template applied to them, obviously.
Handlers can take care of high-level authorization.
@handler(admin=True)
def get_admin():
...
@handler(authed=True)
def get_user(id):
...
Make sure that you handle fine-grained authorization in your own handlers.
CSRF tokens are taken care of on RPC calls and are required for all POSTs. Inside your forms, place $CSRF$
at the beginning and it'll be dealt with.
We're using Alembic for migrations, and they live in migrations/
. Read this for more info.
Ensure you create a migration for anything that affects prod, but development should be done with SQLite and you should simply nuke your DB for each model change.