Werkzeug基础--1(转载)

Origen Site

A Basic WSGI Introduction

A basic “Hello World” application in WSGI without the help of Werkzeug looks like this:

def application(environ, start_response):
   start_response('200 OK', [('Content-Type', 'text/plain')])
   return ['Hello World!']

# environ is a dict
# start_response function can be used to organize response.

With Werkzeug you don’t have to deal directly with either as request and response objects are provided to work with them.

from werkzeug.wrappers import Response

def application(environ, start_response):
   response = Response('Hello World!', mimetype='text/plain')
   return response(environ, start_response)
from werkzeug.wrappers import Request, Response

def application(environ, start_response):
   request = Request(environ)
   text = 'Hello %s!' % request.args.get('name', 'World')
   response = Response(text, mimetype='text/plain')
   return response(environ, start_response)

# application is a function of process, so it would contain other data construction, and communicate varibles from one object to others.

 

Step 1: Creating the Folders

/shortly
  /static
  /templates

The files inside the static folder are available to users of the application via HTTP. This is the place where CSS and JavaScript files go.

Inside the templates folder we will make Jinja2 look for templates.

 

Step 2: The Base Structure

Let’s create a file called shortly.py in the shortly folder.

import redis
import urlparse
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.middleware.shared_data import SharedDataMiddleware
from werkzeug.utils import redirect
from jinja2 import Environment, FileSystemLoader
class Shortly(object):

   def __init__(self, config):
       self.redis = redis.Redis(config['redis_host'], config['redis_port'])

   def dispatch_request(self, request):
       return Response('Hello World!')

   def wsgi_app(self, environ, start_response):
       request = Request(environ)
       response = self.dispatch_request(request)
       return response(environ, start_response)

   def __call__(self, environ, start_response):
       return self.wsgi_app(environ, start_response)


def create_app(redis_host='localhost', redis_port=6379, with_static=True):
   app = Shortly({
       'redis_host':       redis_host,
       'redis_port':       redis_port
  })
   if with_static:
       app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
           '/static':  os.path.join(os.path.dirname(__file__), 'static')
      })
   return app

SharedDataMiddleware: with a piece of WSGI middleware that exports all the files on the static folder on the web.

if __name__ == '__main__':
   from werkzeug.serving import run_simple
   app = create_app()
   run_simple('127.0.0.1', 5000, app, use_debugger=True, use_reloader=True)

Step 3: The Environment

def __init__(self, config):
   self.redis = redis.Redis(config['redis_host'], config['redis_port'])
   template_path = os.path.join(os.path.dirname(__file__), 'templates')
   self.jinja_env = Environment(loader=FileSystemLoader(template_path),
                                autoescape=True)

def render_template(self, template_name, **context):
   t = self.jinja_env.get_template(template_name)
   return Response(t.render(context), mimetype='text/html')

Step 4: The Routing

Routing is the process of matching and parsing the URL to something we can use. Werkzeug provides a flexible integrated routing system which we can use for that.

Usage:

  • create a Map instance

  • add a bunch of Rule objects

    • Each rule has a pattern it will try to match the URL against

    • The endpoint is typically a string and can be used to uniquely identify the URL

self.url_map = Map([
   Rule('/', endpoint='new_url'),
   Rule('/<short_id>', endpoint='follow_short_link'),
   Rule('/<short_id>+', endpoint='short_link_details')
])

By calling the method on_ + endpoint to find our way from endpoint to a function.

def dispatch_request(self, request):
   adapter = self.url_map.bind_to_environ(request.environ)
   try:
       endpoint, values = adapter.match()
       return getattr(self, 'on_' + endpoint)(request, **values)
   except HTTPException, e:
       return e

We bind the URL map to the current environment and get back a URLAdapter.The adapter can be used to match the request but also to reverse URLs.

The match method will return the endpoint and a dictionary of values in the URL.

# When we go to http://localhost:5000/foo we will get the following values back:
endpoint = 'follow_short_link'
values = {'short_id': u'foo'}

Step 5: The First View

def on_new_url(self, request):
   error = None
   url = ''
   if request.method == 'POST':
       url = request.form['url']
       if not is_valid_url(url):
           error = 'Please enter a valid URL'
       else:
           short_id = self.insert_url(url)
           return redirect('/%s+' % short_id)
   return self.render_template('new_url.html', error=error, url=url)
def is_valid_url(url):
   parts = urlparse.urlparse(url)
   return parts.scheme in ('http', 'https')
def insert_url(self, url):
   short_id = self.redis.get('reverse-url:' + url)
   if short_id is not None:
       return short_id
   url_num = self.redis.incr('last-url-id')
   short_id = base36_encode(url_num)
   self.redis.set('url-target:' + short_id, url)
   self.redis.set('reverse-url:' + url, short_id)
   return short_id
def base36_encode(number):
   assert number >= 0, 'positive integer required'
   if number == 0:
       return '0'
   base36 = []
   while number != 0:
       number, i = divmod(number, 36)
       base36.append('0123456789abcdefghijklmnopqrstuvwxyz'[i])
   return ''.join(reversed(base36))

Step 6: Redirect View

def on_follow_short_link(self, request, short_id):
   link_target = self.redis.get('url-target:' + short_id)
   if link_target is None:
       raise NotFound()
   self.redis.incr('click-count:' + short_id)
   return redirect(link_target)

Step 7: Detail View

def on_short_link_details(self, request, short_id):
   link_target = self.redis.get('url-target:' + short_id)
   if link_target is None:
       raise NotFound()
   click_count = int(self.redis.get('click-count:' + short_id) or 0)
   return self.render_template('short_link_details.html',
       link_target=link_target,
       short_id=short_id,
       click_count=click_count
  )

Step 8: Templates

Jinja2 supports template inheritance, so the first thing we will do is create a layout template with blocks that act as placeholders.

<!doctype html>
<title>{% block title %}{% endblock %} | shortly</title>
<link rel=stylesheet href=/static/style.css type=text/css>
<div class=box>
 <h1><a href=/>shortly</a></h1>
 <p class=tagline>Shortly is a URL shortener written with Werkzeug
{% block body %}{% endblock %}
</div>

new_url.html:

{% extends "layout.html" %}
{% block title %}Create New Short URL{% endblock %}
{% block body %}
 <h2>Submit URL</h2>
 <form action="" method=post>
  {% if error %}
     <p class=error><strong>Error:</strong> {{ error }}
  {% endif %}
   <p>URL:
     <input type=text name=url value="{{ url }}" class=urlinput>
     <input type=submit value="Shorten">
 </form>
{% endblock %}

short_link_details.html:

{% extends "layout.html" %}
{% block title %}Details about /{{ short_id }}{% endblock %}
{% block body %}
 <h2><a href="/{{ short_id }}">/{{ short_id }}</a></h2>
 <dl>
   <dt>Full link
   <dd class=link><div>{{ link_target }}</div>
   <dt>Click count:
   <dd>{{ click_count }}
 </dl>
{% endblock %}

 

Step 9: The Style

static/style.css:

body        { background: #E8EFF0; margin: 0; padding: 0; }
body, input { font-family: 'Helvetica Neue', Arial,
             sans-serif; font-weight: 300; font-size: 18px; }
.box       { 500px; margin: 60px auto; padding: 20px;
             background: white; box-shadow: 0 1px 4px #BED1D4;
             border-radius: 2px; }
a           { color: #11557C; }
h1, h2     { margin: 0; color: #11557C; }
h1 a       { text-decoration: none; }
h2         { font-weight: normal; font-size: 24px; }
.tagline   { color: #888; font-style: italic; margin: 0 0 20px 0; }
.link div   { overflow: auto; font-size: 0.8em; white-space: pre;
             padding: 4px 10px; margin: 5px 0; background: #E5EAF1; }
dt         { font-weight: normal; }
.error     { background: #E8EFF0; padding: 3px 8px; color: #11557C;
             font-size: 0.9em; border-radius: 2px; }
.urlinput   { 300px; }

 

原文地址:https://www.cnblogs.com/draven123/p/12965888.html