tutorial: - simon pami©s

Post on 12-Feb-2022

6 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Tutorial: repoze.bfg An introduction to Web-Development

About and Topics   Simon Pamiés

s.pamies@banality.de

  Background B. Sc. BioInformatics and Genome Research M.A. IT-Management (Business Analytics)

  Work banality design & communication Senior Application Engineer and Consultant Planning and Development of Web-Applications

  Technologies (excerpt) Zope, Plone, repoze.bfg, J2EE, GWT, jQuery, MongoDB, RabbitMQ

  Basics

  URL Mapping

  Views

  Templates

  Persistence

  Authentication

  Authorization

About this presentation

  Configuration scheme used here is mostly declarative

  Presentation refers to repoze.bfg version 1.2.x

  Examples imply having a nested package structure with at least   browser/   model/   tests/

  URL mapping is mostly done using dispatching

repoze.bfg – Introduction

  Framework to ease development of web applications

  Small code and memory footprint

  Uses WSGI protocol

  Very well documented

  Easy to start with

Goals

  Simplicity (parsimonious feature set)

  Speed (e.g. no regexps on url matching)

  Extensibility

  „Like Zope but less“

  „Like Pylons but more“

Blather

  repoze.bfg is built upon the WebOb library   ... that provides request and response base classes   ... that handles encoding and decoding of data (e.g. POST)

  repoze.bfg is built to play nicely with WSGI   ... protocol that connects a web server and application together   ... notion of a „pipeline“ where request goes through

  repoze.bfg is also known as BFG (Big Fine Gun, ...)

It doesn‘t do

  Persistence

  Session

  Indexing

  Restricted code execution

  Authentication

  ...

repoze.bfg vs.

  Zope 2+3 (ZTK, BlueBream, ...)   Big, Needs some amount of cognitive load to be understood

  Grok   Easy to start with, hard to continue (much magic)

  Django   Full-stacked (makes assumptions about the persistence layer)

  Pylons   Lacks features like object traversal

URL Mapping

  URLs are entry points to your web app

  Each URL (including parametrized ones) leads to one specific response of your application   e.g. /login, /dashboard, /member/profile, /member/preferences

  An URL is composed of different segments and parameters   e.g. /A/B/C or /A/B/SomeAction?param=value

Key-Question for every web application

How to map URLs to code?

Routing

  Routing takes the whole URL (including defined parametrized segments) and tries to find a matching rule (the most specific one)

  /logout   /member/12345/profile   /member/12345/profile/messages   /actions/some-ajax-query?param=value

Routing (Example)

<route path = „/member/:uid/logout“ name = „logout-handler“ view = „.user.logoutHandler“ />

def logoutHandler(context, request): useruid = request.matchdict.get(‚uid‘) return webob.Response(„User has been logged out“)

Traversal

  Traversal automagically maps each segment to objects

  Walks the object graph

  Context is set according to the last segment matching an object

  Useful in applications where you have dynamic object hierarchies (CMS)

Traversal (Example)

URL

OBJECT GRAPH

  B is the last object matching the route   Z is the view name   B is passed to the view as context

Traversal (Example)

<view name = „edit“ context = „.models.folder“ view = „.browser.folder.editHandler“ />

def editHandler(context, request): # context is a folder return webob.Response(„Some HTML to edit a folder“)

Views

  Methods or classes that act as URL targets

  Work on request object containing all relevant information

  Context provides object that links to model

  View always returns webob.Response

View (Method based)

def requestHandler(context, request): # do some fancy stuff return webob.Response(„body content here“)

  context is not required but if present holds model related data

  request is an object containing all relevant data

  request.params, request.GET, request.POST

  request[„HTTP_REFERER“]

View (Class based)

class UserRelatedActionsView(object):

def __init__(self, context, request): self.context = context self.request = request

def __call__(self): return webob.Response()

  Using a class you can group and reuse functionality

  Mainly used for templates to provide tool like interface

  If in doubt use methods

Templates

  Using Python to build HTML documents sucks

  Use a templating language (e.g. Chameleon ZPT)   Full ZPT implementation   Template compiler   In-place expression evaluation supported

<html> <b tal:condition=„context.hasTitle()“> ${context.Title()} </b>

</html>

Combining Views and Templates

class LoginView(object):

def isAuthenticated(self): return ‚repoze.who.userid‘ in self.request

def __call__(self): return {‚param‘ : True} # arbitrary parameters here

<b tal:condition=„not view.isAuthenticated() and param“> Please login using the form below

</b>

<route name=„login-form“ view=„.login.LoginView“ renderer=„templates/login_form.pt“ />

Combining Views and Templates

class LoginView(object):

def __call__(self): from repoze.bfg.chameleon_zpt import render[...] return render_template_to_response( ‚templates/login_form.pt‘, view=self, request=self.request, param=True)

<b tal:condition=„not view.isAuthenticated() and param“> Please login using the form below

</b>

Renderer

  Built-in renderers available   String   JSON   Chameleon Templates

  Easy to write your own renderer

Lessons learned?

  repoze.bfg filling the gap between other frameworks

  Notion of URL mapping

  Traversal

  Routing

  Views (Method vs. Class)

  Templates

What next?

  Persisting data (model) – you‘re free to choose where   ZODB   RDBMS   „No-SQL“ (MongoDB, ...)

  Security   Authenticating users (repoze.who)   ACLs (repoze.bfg, repoze.what)

  Practical part   Installation (buildout, paster), examples

Persisting data

  Two easy steps   Write your model using plain python objects   Attach a persistent data handler

Your code should not know anything about the storage

  Model   Plain Python object using values from internal state (__dict__)

  Handler   At transaction boundaries (e.g. request) or upon app request

persists data from object to database or the way round

The Model

From your_db_handler import Persistent

class Person(Persistent):

def __init__(self, name): self.name = name

  The base class takes care of all operations related to the attached storage

  Your class just computes data based on values from known attributes (e.g. name)

The handler (just to get the idea)

class Persistent(object):

def save(self): if self.isNew(): self.connector.create(self.__dict__) else: self.connector.update(self.__dict__)

def delete(self): self.connector.delete(self.uid)

Batteries included (ZODB Handler)

  ZODB gives you   full fledged object oriented database   transaction awareness   transparent model handling   scalability

  ZODB can be included with just a few lines of code into your app – and it just works™

  Include ZODB into your model „from persistent import Persistent“

Security (Authentication)

  Application needs to   authenticate user

  persist authentication

  return state of authentication

  Authenticating: Basic Auth, Form, SSPI

  Persisting: Cookie, Session, URL token

  State: Variable in request

repoze.who

  Framework to handle authentication   Well thought architecture

  Easily extensible

  Rich set of predefined handlers

  „Who is coming in?“

repoze.who (cont.)

  Four stages where code can plug in   Classifier (What type of request do we have?)   Challenger (How to get auth data?)   Authenticator (How to check wheter data is valid?)   Persister (How to save valid data?)

  Simple configuration

  Many plugins available Cookie Auth, Basic Auth, Facebook Auth, OAuth

repoze.who configuration

[general] request classifier and challenge decider

[identifiers] extract data from request

[authenticators] authenticates user based on data from identifiers

[challengers] get user login data (basic auth, form based)

Security (Authorization)

  Authorization asks „User Bob has permission Edit?“

  User –(1:n)–> Group –(1:m)–> Permissions

  Protecting   Code (e.g. getTitle() method )   Views and URLs (e.g. /person/create-form)

  repoze.bfg has simple authorization handling included

  I recommend against using repoze.what (way to complicated)

Authorization using repoze.bfg

  Use authentication policy to define groups for users   e.g. repozewho1authenticationpolicy

  Implement or use authorization policy to check for rights   e.g. aclauthorizationpolicy

Practical Part: What?

  Simple „Hello World“ application   Wiring a view with a template   Handling form submission (POST)

  Another simple application (address book)   Creating a model (person)   User can create persons   Persons are listed and can be deleted

Practical Part: Installation

  Checking setuptools $ easy_install http://peak.telecommunity.com/dist/ez_setup.py

  Creating a virtualenv environment $ virtualenv –no-site-packages repozebfg

  Installing repoze.bfg $ bin/easy_install repoze.bfg==1.2.1

  Things to understand   Virtualenv   Setuptools

PP: Setting up a project

  Creating a simple project structure $ bin/paster create -t bfg_starter helloworld

  Things to understand   PasteScript   Python Packages and Eggs

PP: Starting up the application

  Fire up server $ bin/paster serve –reload helloworld.ini

  Things to understand   WSGI   Python WSGI reference implementation   PasteDeploy framework

PP: Next steps

  Understanding the structure   helloworld.ini   run.py   configure.zcml   views.py

  Writing some code   Creating a form   Validating form   Saving data

top related