The Swiss-Army Knife for Python Web Developers Armin Ronacher - - PowerPoint PPT Presentation

the swiss army knife for python web developers
SMART_READER_LITE
LIVE PREVIEW

The Swiss-Army Knife for Python Web Developers Armin Ronacher - - PowerPoint PPT Presentation

The Swiss-Army Knife for Python Web Developers Armin Ronacher http://lucumr.pocoo.org/ About Me About Me Name: Armin Ronacher Werkzeug, Jinja, Pygments, ubuntuusers.de Python since 2005 WSGI warrior since the very beginning


slide-1
SLIDE 1

The Swiss-Army Knife for Python Web Developers

Armin Ronacher — http://lucumr.pocoo.org/

slide-2
SLIDE 2

About Me

slide-3
SLIDE 3

About Me

  • Name: Armin Ronacher
  • Werkzeug, Jinja, Pygments, ubuntuusers.de
  • Python since 2005
  • WSGI warrior since the very beginning (well, not quite)
slide-4
SLIDE 4

Why Python?

slide-5
SLIDE 5

Why Python?

  • agile
  • active community
  • countless modules
  • powerful introspection functionality
  • WSGI
slide-6
SLIDE 6

WSGI

slide-7
SLIDE 7

WSGI

  • Web Server Gateway Interface
  • lowlevel interface between application and

server

  • allows to reuse code between applications
  • CGI / FastCGI / SCGI / AJP / mod_python /

mod_wsgi / twisted / standalone

  • simple and fast
slide-8
SLIDE 8

Hello World

slide-9
SLIDE 9

Hello World

def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [ '<!DOCTYPE HTML>\n<title>Hello World</title>\n' '<h1>Hello World!</h1>' ]

slide-10
SLIDE 10

Hello World

def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [ '<!DOCTYPE HTML>\n<title>Hello World</title>\n' '<h1>Hello World!</h1>' ]

Request

slide-11
SLIDE 11

Hello World

def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [ '<!DOCTYPE HTML>\n<title>Hello World</title>\n' '<h1>Hello World!</h1>' ]

Request Response #1 Response #2

slide-12
SLIDE 12

Deployment

slide-13
SLIDE 13

Deployment

lighttpd Apache

slide-14
SLIDE 14

Deployment

lighttpd mod_fastcgi / mod_scgi Apache mod_wsgi

slide-15
SLIDE 15

Deployment

lighttpd mod_fastcgi / mod_scgi flup Apache mod_wsgi

slide-16
SLIDE 16

Deployment

lighttpd mod_fastcgi / mod_scgi flup WSGI Anwendung Apache mod_wsgi WSGI Anwendung

slide-17
SLIDE 17

Deployment

lighttpd mod_fastcgi / mod_scgi flup WSGI Anwendung Apache mod_wsgi WSGI Anwendung wsgiref WSGI Anwendung

slide-18
SLIDE 18

Middlewares

slide-19
SLIDE 19

Middlewares

  • middlewares work between server and

application

slide-20
SLIDE 20

Middlewares

  • middlewares work between server and

application

  • can manipulate incoming and outgoing data
slide-21
SLIDE 21

Middlewares

  • middlewares work between server and

application

  • can manipulate incoming and outgoing data
  • useful to …
  • … log errors
  • … fix broken server data
  • … combine multiple applications
slide-22
SLIDE 22

But....

slide-23
SLIDE 23

But....

...an application shouldn’t depend on an middleware

slide-24
SLIDE 24

But....

...an application shouldn’t depend on an middleware

http://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.html

slide-25
SLIDE 25

But....

...an application shouldn’t depend on an middleware

http://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.html

slide-26
SLIDE 26

Setup

slide-27
SLIDE 27

Setup

  • central „runner” file:
slide-28
SLIDE 28

Setup

  • central „runner” file:
  • application.fcgi … mod_fastcgi
slide-29
SLIDE 29

Setup

  • central „runner” file:
  • application.fcgi … mod_fastcgi
  • application.wsgi … mod_wsgi
slide-30
SLIDE 30

Setup

  • central „runner” file:
  • application.fcgi … mod_fastcgi
  • application.wsgi … mod_wsgi
  • run-application.py … standalone / wsgiref
slide-31
SLIDE 31

Setup

  • central „runner” file:
  • application.fcgi … mod_fastcgi
  • application.wsgi … mod_wsgi
  • run-application.py … standalone / wsgiref
  • imports application and middlewares
slide-32
SLIDE 32

Setup

  • central „runner” file:
  • application.fcgi … mod_fastcgi
  • application.wsgi … mod_wsgi
  • run-application.py … standalone / wsgiref
  • imports application and middlewares
  • combines it and creates and application object
  • r calls the gateway
slide-33
SLIDE 33

Setup

from yourapplication import Application from yourmiddleware import YourMiddleware from vendormiddleware import VendorMiddleware application = Application(configuration=here) application = YourMiddleware(application, configuration=here) application = VendorMiddleware(application)

  • central „runner” file:
  • application.fcgi … mod_fastcgi
  • application.wsgi … mod_wsgi
  • run-application.py … standalone / wsgiref
  • imports application and middlewares
  • combines it and creates and application object
  • r calls the gateway
slide-34
SLIDE 34

Summary

slide-35
SLIDE 35

Summary

  • application: callable object
slide-36
SLIDE 36

Summary

  • application: callable object
  • environ … incoming data
slide-37
SLIDE 37

Summary

  • application: callable object
  • environ … incoming data
  • start_response … starts the response
slide-38
SLIDE 38

Summary

  • application: callable object
  • environ … incoming data
  • start_response … starts the response
  • app_iter … an iterator, each iteration sends

data to the client

slide-39
SLIDE 39

Summary

  • application: callable object
  • environ … incoming data
  • start_response … starts the response
  • app_iter … an iterator, each iteration sends

data to the client

  • middleware: between application and gateway
slide-40
SLIDE 40

Summary

  • application: callable object
  • environ … incoming data
  • start_response … starts the response
  • app_iter … an iterator, each iteration sends

data to the client

  • middleware: between application and gateway
  • gateway: translates WSGI to CGI etc.
slide-41
SLIDE 41

Werkzeug

slide-42
SLIDE 42

Werkzeug

  • unicode handling
slide-43
SLIDE 43

Werkzeug

  • unicode handling
  • form data / file uploads / url parameter

parsing

slide-44
SLIDE 44

Werkzeug

  • unicode handling
  • form data / file uploads / url parameter

parsing

  • URL dispatching
slide-45
SLIDE 45

Werkzeug

  • unicode handling
  • form data / file uploads / url parameter

parsing

  • URL dispatching
  • HTTP parsing
slide-46
SLIDE 46

Werkzeug

  • unicode handling
  • form data / file uploads / url parameter

parsing

  • URL dispatching
  • HTTP parsing
  • development server
slide-47
SLIDE 47

Werkzeug

  • unicode handling
  • form data / file uploads / url parameter

parsing

  • URL dispatching
  • HTTP parsing
  • development server
  • autoreloader
slide-48
SLIDE 48

Werkzeug

  • unicode handling
  • form data / file uploads / url parameter

parsing

  • URL dispatching
  • HTTP parsing
  • development server
  • autoreloader
  • countless small helpers
slide-49
SLIDE 49

What is it not?

slide-50
SLIDE 50

What is it not?

  • ORM
slide-51
SLIDE 51

What is it not?

  • ORM
  • template engine
slide-52
SLIDE 52

What is it not?

  • ORM
  • template engine
  • form-validation
slide-53
SLIDE 53

What is it not?

  • ORM
  • template engine
  • form-validation
  • i18n / l10n
slide-54
SLIDE 54

What is it not?

  • ORM
  • template engine
  • form-validation
  • i18n / l10n
  • component architecture
slide-55
SLIDE 55

What is it not?

  • ORM
  • template engine
  • form-validation
  • i18n / l10n
  • component architecture
  • a framework
slide-56
SLIDE 56

Why not?

slide-57
SLIDE 57

Why not?

  • such things exist already
slide-58
SLIDE 58

Why not?

  • such things exist already
  • you can combine them
slide-59
SLIDE 59

Why not?

  • such things exist already
  • you can combine them
  • everybody wants something else
slide-60
SLIDE 60

Why not?

  • such things exist already
  • you can combine them
  • everybody wants something else
  • cherry picking!
slide-61
SLIDE 61

What does it look like?

slide-62
SLIDE 62

What does it look like?

>>> from werkzeug import Request, create_environ >>> environ = create_environ('/index.html?foo=bar&foo=baz&blah=42') >>> request = Request(environ) >>> request.args['foo'] u'bar' >>> request.args.getlist('foo') [u'bar', u'baz'] >>> request.args.get('blah', type=int) 42 >>> request.path u'/index.html' >>> request.method 'GET'

slide-63
SLIDE 63
slide-64
SLIDE 64

DumpIt!

a pastebin in 15 minutes

slide-65
SLIDE 65

What do we use?

slide-66
SLIDE 66

What do we use?

  • Werkzeug
slide-67
SLIDE 67

What do we use?

  • Werkzeug
  • Jinja
slide-68
SLIDE 68

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
slide-69
SLIDE 69

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
  • Pygments
slide-70
SLIDE 70

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
  • Pygments

WSGI

slide-71
SLIDE 71

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
  • Pygments

WSGI Templates

slide-72
SLIDE 72

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
  • Pygments

WSGI Templates Database

slide-73
SLIDE 73

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
  • Pygments

WSGI Templates Database Code Highlighting

slide-74
SLIDE 74

What do we use?

  • Werkzeug
  • Jinja
  • sqlite3
  • Pygments

WSGI Templates Database Code Highlighting

easy_install Werkzeug easy_install Jinja easy_install Pygments

slide-75
SLIDE 75

#0: Database

slide-76
SLIDE 76

#0: Database

CREATE TABLE pastes ( id INTEGER NOT NULL, code TEXT, lang VARCHAR(40), PRIMARY KEY (id) );

schema.sql

slide-77
SLIDE 77

#1: Imports

slide-78
SLIDE 78

#1: Imports

import sqlite3 from os import path from werkzeug import Request, Response, redirect from werkzeug.exceptions import HTTPException, NotFound from werkzeug.routing import Map, Rule from jinja import Environment, FileSystemLoader from pygments import highlight from pygments.lexers import get_lexer_by_name, TextLexer from pygments.formatters import HtmlFormatter

slide-79
SLIDE 79

#2: Configuration

slide-80
SLIDE 80

#2: Configuration

DATABASE = '/path/to/dumpit.db' PYGMENTS_STYLE = 'pastie' LANGUAGES = [ ('text', 'No Highlighting'), ('python', 'Python'), ('c', 'C') ] TEMPLATES = path.join(path.dirname(__file__), 'templates') jinja_env = Environment(loader=FileSystemLoader(TEMPLATES)) pygments_formatter = HtmlFormatter(style=PYGMENTS_STYLE) def render_template(template_name, **context): template = jinja_env.get_template(template_name) return template.render(context)

slide-81
SLIDE 81

#3: Dispatching

slide-82
SLIDE 82

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-83
SLIDE 83

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-84
SLIDE 84

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-85
SLIDE 85

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-86
SLIDE 86

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-87
SLIDE 87

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-88
SLIDE 88

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

http://localhost:5000/ http://localhost:5000/42 http://localhost:5000/42/raw http://localhost:5000/pygments.css

slide-89
SLIDE 89

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-90
SLIDE 90

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-91
SLIDE 91

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-92
SLIDE 92

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-93
SLIDE 93

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-94
SLIDE 94

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-95
SLIDE 95

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-96
SLIDE 96

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-97
SLIDE 97

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-98
SLIDE 98

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-99
SLIDE 99

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-100
SLIDE 100

#3: Dispatching

url_map = Map([ Rule('/', endpoint='new_paste'), Rule('/<int:id>', endpoint='show_paste'), Rule('/<int:id>/raw', endpoint='download_paste'), Rule('/pygments.css', endpoint='pygments_style') ]) def application(environ, start_response): request = Request(environ) request.db = sqlite3.connect(DATABASE) url_adapter = url_map.bind_to_environ(environ) try: endpoint, values = url_adapter.match() response = globals()[endpoint](request, **values) if isinstance(response, basestring): response = Response(response, mimetype='text/html') except HTTPException, error: response = error return response(environ, start_response)

slide-101
SLIDE 101

#4: „Views“

slide-102
SLIDE 102

#4: „Views“

def new_paste(request): if request.method == 'POST': code = request.form.get('code') lang = request.form.get('lang') if code and lang: paste = Paste(lang, code) paste.save(request.db) return redirect(str(paste.id)) return render_template('new_paste.html', languages=LANGUAGES)

slide-103
SLIDE 103

#4: „Views“

def new_paste(request): if request.method == 'POST': code = request.form.get('code') lang = request.form.get('lang') if code and lang: paste = Paste(lang, code) paste.save(request.db) return redirect(str(paste.id)) return render_template('new_paste.html', languages=LANGUAGES) def show_paste(request, id): paste = Paste.get(request.db, id) if paste is None: raise NotFound() return render_template('show_paste.html', paste=paste)

slide-104
SLIDE 104

#4: „Views“

def new_paste(request): if request.method == 'POST': code = request.form.get('code') lang = request.form.get('lang') if code and lang: paste = Paste(lang, code) paste.save(request.db) return redirect(str(paste.id)) return render_template('new_paste.html', languages=LANGUAGES) def show_paste(request, id): paste = Paste.get(request.db, id) if paste is None: raise NotFound() return render_template('show_paste.html', paste=paste) def download_paste(request, id): paste = Paste.get(request.db, id) if paste is None: raise NotFound() return Response(paste.code)

slide-105
SLIDE 105

#4: „Views“

def new_paste(request): if request.method == 'POST': code = request.form.get('code') lang = request.form.get('lang') if code and lang: paste = Paste(lang, code) paste.save(request.db) return redirect(str(paste.id)) return render_template('new_paste.html', languages=LANGUAGES) def show_paste(request, id): paste = Paste.get(request.db, id) if paste is None: raise NotFound() return render_template('show_paste.html', paste=paste) def download_paste(request, id): paste = Paste.get(request.db, id) if paste is None: raise NotFound() return Response(paste.code) def pygments_style(request): return Response(pygments_formatter.get_style_defs(), mimetype='text/css')

slide-106
SLIDE 106

#5: Model

slide-107
SLIDE 107

class Paste(object): def __init__(self, lang, code, id=None): self.lang = lang self.code = code self.id = id @property def highlighted_code(self): try: lexer = get_lexer_by_name(self.lang) except ValueError: lexer = TextLexer return highlight(self.code, lexer, pygments_formatter) @classmethod def get(cls, con, id): cur = con.cursor() cur.execute('select lang, code, id from pastes where id = ?', [id]) row = cur.fetchone() if row: return cls(*row)

#5: Model

slide-108
SLIDE 108

@property def highlighted_code(self): try: lexer = get_lexer_by_name(self.lang) except ValueError: lexer = TextLexer return highlight(self.code, lexer, pygments_formatter) @classmethod def get(cls, con, id): cur = con.cursor() cur.execute('select lang, code, id from pastes where id = ?', [id]) row = cur.fetchone() if row: return cls(*row) def save(self, con): cur = con.cursor() if self.id is None: cur.execute('insert into pastes (lang, code) values (?, ?)', [self.lang, self.code]) self.id = cur.lastrowid else: cur.execute('update pastes set lang = ?, code = ? where ' 'id = ?', [self.lang, self.code, self.id]) con.commit()

#5: Model

slide-109
SLIDE 109

#6: Templates

slide-110
SLIDE 110

#6: Templates

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Dump It!</title> <link rel="stylesheet" href="/static/style.css" type="text/css"> <link rel="stylesheet" href="/pygments.css" type="text/css"> </head> <body> <div id="header"> <h1>Dump It!</h1> </div> <div id="page"> {% block body %}{% endblock %} </div> </body> </html>

layout.html

slide-111
SLIDE 111

#6: Templates

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Dump It!</title> <link rel="stylesheet" href="/static/style.css" type="text/css"> <link rel="stylesheet" href="/pygments.css" type="text/css"> </head> <body> <div id="header"> <h1>Dump It!</h1> </div> <div id="page"> {% block body %}{% endblock %} </div> </body> </html> {% extends "layout.html" %} {% block body %} <h2>New Paste</h2> <form action="" method="post"> <p><textarea name="code" rows="8" cols="50"></textarea></p> <p><select name="lang"> {% for code, name in languages %} <option value="{{ code }}">{{ name }}</option> {% endfor %} </select><input type="submit" value="Paste"></p> </form> {% endblock %}

layout.html new_paste.html

slide-112
SLIDE 112

#6: Templates

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Dump It!</title> <link rel="stylesheet" href="/static/style.css" type="text/css"> <link rel="stylesheet" href="/pygments.css" type="text/css"> </head> <body> <div id="header"> <h1>Dump It!</h1> </div> <div id="page"> {% block body %}{% endblock %} </div> </body> </html> {% extends "layout.html" %} {% block body %} <h2>New Paste</h2> <form action="" method="post"> <p><textarea name="code" rows="8" cols="50"></textarea></p> <p><select name="lang"> {% for code, name in languages %} <option value="{{ code }}">{{ name }}</option> {% endfor %} </select><input type="submit" value="Paste"></p> </form> {% endblock %} {% extends "layout.html" %} {% block body %} <h2>Paste #{{ paste.id }}</h2> <div class="paste"> {{ paste.highlighted_code }} </div> {% endblock %}

layout.html new_paste.html show_paste.html

slide-113
SLIDE 113

Development Server

slide-114
SLIDE 114

Development Server

if __name__ == '__main__': from werkzeug import run_simple, SharedDataMiddleware application = SharedDataMiddleware(application, { '/static': path.join(path.dirname(__file__), 'static') }) run_simple('localhost', 4000, application)

slide-115
SLIDE 115

Development Server

mitsuhiko@nausicaa:~/DumpIt$ sqlite3 /path/to/dumpit.db < schema.sql mitsuhiko@nausicaa:~/DumpIt$ python dumpit.py runserver * Running on http://localhost:4000/ if __name__ == '__main__': from werkzeug import run_simple, SharedDataMiddleware application = SharedDataMiddleware(application, { '/static': path.join(path.dirname(__file__), 'static') }) run_simple('localhost', 4000, application)

slide-116
SLIDE 116

„Dump It!“ In Action

slide-117
SLIDE 117

„Dump It!“ In Action

slide-118
SLIDE 118

„Dump It!“ In Action

slide-119
SLIDE 119

More Than One Way

slide-120
SLIDE 120

More Than One Way

  • Templates: XML / Text-based / Sandbox
slide-121
SLIDE 121

More Than One Way

  • Templates: XML / Text-based / Sandbox
  • Daten: SQL / CouchDB / Filesystem
slide-122
SLIDE 122

More Than One Way

  • Templates: XML / Text-based / Sandbox
  • Daten: SQL / CouchDB / Filesystem
  • AJAX: JSON / XML / HTML Fragments
slide-123
SLIDE 123

More Than One Way

  • Templates: XML / Text-based / Sandbox
  • Daten: SQL / CouchDB / Filesystem
  • AJAX: JSON / XML / HTML Fragments
  • URLs: Regular Expressions / Werkzeug

Routing / Routes / Objekt-basierend / Query Parameters

slide-124
SLIDE 124

More Than One Way

  • Templates: XML / Text-based / Sandbox
  • Daten: SQL / CouchDB / Filesystem
  • AJAX: JSON / XML / HTML Fragments
  • URLs: Regular Expressions / Werkzeug

Routing / Routes / Objekt-basierend / Query Parameters

  • Dispatching: Controller / View-Functions
slide-125
SLIDE 125

More Than One Way

  • Templates: XML / Text-based / Sandbox
  • Daten: SQL / CouchDB / Filesystem
  • AJAX: JSON / XML / HTML Fragments
  • URLs: Regular Expressions / Werkzeug

Routing / Routes / Objekt-basierend / Query Parameters

  • Dispatching: Controller / View-Functions
  • Auth: Apache / LDAP / OpenID
slide-126
SLIDE 126

http://werkzeug.pocoo.org/

http://lucumr.pocoo.org/talks/ltgraz08/