Gibt es komponentenbasierte Webrahmenwerke?
Verfasst: Freitag 4. Januar 2008, 10:31
Gibt es eigentlich Python-Web-Rahmenwerke, die komponentenbasiert sind wie z.B. Smalltalks Seaside oder Javas Wicket (oder Tapestry oder -gasp- JSF)?
Typischerweise muss man sich hier nicht selbst darum kümmern, wie man den Kontrollfluss innerhalb einer Webanwendung zerflückt, sondern arbeitet mit Callbacks oder Continuations. Letztes wird in Python nicht möglich sein, aber Wicket ist z.B. für Java-Verhältnisse schon nett.
Hier sind ein paar Beispiele.
Bei Seaside steht der Code, der eine Operation definiert, die durch einen Link (oder Button) ausgelöst werden soll, unmittelbar dort, wo auch der Link definiert wird. Das ist explizit und DRY, erspart es einem doch selbst URLs zu erfinden, sie explizit auf Controller (oder im Django-Fall auf Views) zu dispatchen und dann dort die Funktion zu implementieren. Dank Continuations wird der gesamte Zustand der Anwendung automatisch verwaltet.
Hier ist eine Komponente `Counter`, die eine Zahl anzeigt, die man In- und Dekrementieren kann.
In Python könnte das so aussehen. Python ist etwas geschwätziger und kennt keine Blöcke, daher muss ich weitere Methoden explizit definieren.
Mehrere Counter sind auch kein Problem. Komponenten lassen sich bei Seaside schachteln:
Würde `Counter` in Python genau wie bei Seaside funktionieren (was nicht geht, siehe unten), ginge das natürlich auch in Python:
Selbst modale Dialoge sind bei Seaside dank Continuations möglich. Die Methode #show: zeigt einen (gedachten - Namen und Konventionen sind ähnlich) modalen Dialog an, um eine neue Zahl einzugeben und der Kontrollfluss scheint in dieser Zeile stehen zu bleiben bis der Benutzer eine Eingabe gemacht hat.
Was Wicket kann, müsste Python auch können. Wicket kombiniert Komponenten mit Templates. Es ist jedoch extrem beim Einsatz von anonymen Klassen, ein Konzept, dass es bei Python nicht gibt und erneut den Code umständlicher macht. Hier meine Python-Adaption. Modelle landen automatisch in der Session, den Rest baut Wicket jedoch für jeden Request wieder auf und simuliert so Continuations für Arme ;)
Mehrere Counter gehen auch hier, das explizite Template wird aber lästig:
Allgemein gilt: Kontrollfluss wird über Callbacks implizit realisiert. Komponenten lassen sich zu größeren Komponenten kombinieren. Das Rahmenwerk kümmert sich selbst darum, seinen Zustand zwischen zwei Requests zu bewahren und schafft die Illusion, ich eine habe kontinuierlich laufende zustandsbehaftete Anwendung, keine Sammlung von Webseiten.
Gibt es hier etwas Vergleichbares im Python-Umfeld?
Stefan
Typischerweise muss man sich hier nicht selbst darum kümmern, wie man den Kontrollfluss innerhalb einer Webanwendung zerflückt, sondern arbeitet mit Callbacks oder Continuations. Letztes wird in Python nicht möglich sein, aber Wicket ist z.B. für Java-Verhältnisse schon nett.
Hier sind ein paar Beispiele.
Bei Seaside steht der Code, der eine Operation definiert, die durch einen Link (oder Button) ausgelöst werden soll, unmittelbar dort, wo auch der Link definiert wird. Das ist explizit und DRY, erspart es einem doch selbst URLs zu erfinden, sie explizit auf Controller (oder im Django-Fall auf Views) zu dispatchen und dann dort die Funktion zu implementieren. Dank Continuations wird der gesamte Zustand der Anwendung automatisch verwaltet.
Hier ist eine Komponente `Counter`, die eine Zahl anzeigt, die man In- und Dekrementieren kann.
Code: Alles auswählen
initialize
count := 0
renderContentOn: html
html
heading: count;
anchor: '++' callback: [count := count + 1];
space;
anchor: '--' callback: [count := count - 1]
Code: Alles auswählen
class Counter(Component):
def __init__(self):
self.count = 0
def renderContent(self, html):
html.heading(self.count)
html.div[
html.anchor(callback=self.increment)["++"],
" ",
html.anchor(callback=self.decrement)["--"],
]
def increment(self):
self.count += 1
def decrement(self):
self.count -= 1
Code: Alles auswählen
initialize
counters := (1 to: 6) collect: [:each | Counter new]
renderContentOn: html
counters
do: [:each | html render: each]
separatedBy: [html horizontalRule]
Code: Alles auswählen
class MultiCounter(Component):
def __init__(self):
self.counters = [Counter() for i in range(6)]
def renderContent(self, html):
first = True
for counter in counters:
if first:
first = False
else:
html.horizontalRule()
counter.renderContent(html)
Code: Alles auswählen
renderContentOn: html
...
html anchor: 'set' callback: [
d := Dialog prompt: 'enter new number'.
(self show: d) ifTrue: [count := d value asInteger]
]
Code: Alles auswählen
class Counter(WebPage):
def __init__(self, name):
WebPage.__init__(self, name)
class Count(Model):
def __init__(self): self.count = 0
def increment(self): self.count += 1
def decrement(self): self.count -= 1
def value(self): return str(self.count)
count = Count()
self.add(Link("incr", click=count.increment))
self.add(Link("decr", click=count.decrement))
self.add(Label("count", count))
Code: Alles auswählen
<h1><span wicket:id=count>0</span></h1>
<div>
<a wicket:id="incr">++</a>
<a wicket:id="decr">--</a>
</div>
Code: Alles auswählen
class MultiCounter(WebPage):
def __init__(self):
for i in range(6):
self.add(Counter("counter-%i" % i))
Code: Alles auswählen
<div wicket:id="counter-0"></div>
<hr/>
<div wicket:id="counter-1"></div>
<hr/>
<div wicket:id="counter-2"></div>
<hr/>
<div wicket:id="counter-3"></div>
<hr/>
<div wicket:id="counter-4"></div>
<hr/>
<div wicket:id="counter-5"></div>
Gibt es hier etwas Vergleichbares im Python-Umfeld?
Stefan