Turbogears - Kurzanleitung
Was ist Web Framework?
Web Application Framework oder einfach Web Framework stellt eine Sammlung von Bibliotheken und Modulen dar, mit denen ein Webanwendungsentwickler Anwendungen schreiben kann, ohne sich um Details auf niedriger Ebene wie Protokolle, Thread-Verwaltung usw. kümmern zu müssen.
Was ist TurboGears?
TurboGears ist ein in Python geschriebenes Webanwendungsframework. Die neueste Version von TurboGears (Version 2.3.7) wurde 2005 von Kevin Dangoor entwickelt und wird von einer Gruppe von Entwicklern unter der Leitung von Mark Ramm und Florent Aide verwaltet.
TurboGears folgt dem Model-View-Controller-Paradigma wie die meisten modernen Web-Frameworks wie Rails, Django, Struts usw.
Model View Controller
MVC ist ein Software-Entwurfsmuster für die Entwicklung von Webanwendungen. Ein Model View Controller-Muster besteht aus drei Teilen:
Model - Die unterste Ebene des Musters ist für die Pflege der Daten verantwortlich.
View - Dies ist dafür verantwortlich, dem Benutzer alle oder einen Teil der Daten anzuzeigen.
Controller - Software-Code, der die Interaktionen zwischen Modell und Ansicht steuert.
MVC ist beliebt, da es die Anwendungslogik von der Benutzeroberflächenschicht isoliert und die Trennung von Bedenken unterstützt. Hier empfängt der Controller alle Anforderungen für die Anwendung und arbeitet dann mit dem Modell zusammen, um alle von der Ansicht benötigten Daten vorzubereiten. Die Ansicht verwendet dann die vom Controller vorbereiteten Daten, um eine endgültige vorzeigbare Antwort zu generieren. Die MVC-Abstraktion kann wie folgt grafisch dargestellt werden:
Das Model
Das Modell ist für die Verwaltung der Daten der Anwendung verantwortlich. Es reagiert auf die Anforderung aus der Ansicht und auf Anweisungen des Controllers, sich selbst zu aktualisieren.
Die Aussicht
Eine Präsentation von Daten in einem bestimmten Format, ausgelöst durch die Entscheidung eines Controllers, die Daten zu präsentieren. Es handelt sich um skriptbasierte Template-Systeme, die sich sehr einfach in die AJAX-Technologie integrieren lassen.
Der Controller
Die Steuerung ist dafür verantwortlich, auf Benutzereingaben zu reagieren und Interaktionen mit den Datenmodellobjekten durchzuführen. Der Controller empfängt die Eingabe, validiert die Eingabe und führt dann den Geschäftsvorgang aus, der den Status des Datenmodells ändert.
TurboGears basiert auf einer Reihe von Bibliotheken und Tools. Diese Tools haben sich zwischen verschiedenen Versionen von TurboGears geändert. Die Komponenten der aktuellen Version (Version 2.3.7) sind unten aufgeführt.
SQLAlchemy
Es ist ein Open-Source-SQL-Kit, das Object Relations Mapping (ORM) für Python-Code bereitstellt.
Genshi
Diese Template-Engine wird verwendet, um das Front-End von TG-Anwendungen zu erstellen. Ein Web-Template-System kombiniert eine Vorlage mit einer bestimmten Datenquelle, um dynamische Webseiten zu rendern.
ToscaWidgets
Es ist eine Widget-Bibliothek zum Generieren von HTML-Formularen mit serverseitigen Steuerelementen. Tosca fungiert auch als Middleware für die Verbindung mit JavaScript-Widgets und Toolkits.
Getriebe
Es enthält eine Reihe von Befehlen zum Verwalten von Projekten und Server-TurboGears-Anwendungen. TurboGears-Anwendungen können auf jedem WSGI-kompatiblen Webserver bereitgestellt werden.
Das Web Server Gateway Interface (WSGI) wurde als Standard für die Entwicklung von Python-Webanwendungen übernommen. WSGI ist eine Spezifikation für die universelle Schnittstelle zwischen Webserver und Webanwendungen. Das wsgiref-Paket ist eine Referenzimplementierung von WSGI. Es wird verwendet, um dem Web-TurboGears-Webframework WSGI-Unterstützung hinzuzufügen. Das simple_server-Modul in diesem Paket implementiert einen einfachen HTTP-Server, der WSGI-Anwendungen bedient. Wir werden es verwenden, um Anwendungen zu testen, die in diesem Tutorial entwickelt wurden.
Voraussetzung
Python 2.6 oder höher. Frühere Versionen von TurboGears waren nicht mit Python 3.X kompatibel. Die neueste Version soll unter Python 3.X gut funktionieren. Die offizielle Dokumentation von TurboGears basiert jedoch weiterhin auf der Python 2.7-Umgebung.
Der folgende Befehl installs virtualenv - -
pip install virtualenv
Dieser Befehl benötigt administratorPrivilegien. Hinzufügensudo before pipunter Linux / Mac OS. Wenn Sie unter Windows arbeiten, melden Sie sich als Administrator an. Unter Ubuntu kann virtualenv mit seinem Paketmanager installiert werden.
Sudo apt-get install virtualenv
Nach der Installation wird die neue virtuelle Umgebung in einem Ordner erstellt.
mkdir newproj
cd newproj
virtualenv venv
Um die entsprechende Umgebung zu aktivieren, aktivieren Sie Linux/OS X
venv/bin/activate
auf Windows
venv\scripts\activate
Wir sind jetzt bereit dazu install TurboGearsin dieser Umgebung. Eine minimale Installation von TurboGears erfolgt mit folgendem Befehl:
pip install TurboGears2
Der obige Befehl kann für die systemweite Installation direkt ohne virtuelle Umgebung ausgeführt werden.
Verwenden Sie den folgenden Befehl, um TurboGears zusammen mit den Entwicklungstools zu installieren:
pip install tg.devtools
TurboGears verfügt über einen Minimalmodus, mit dem einzelne Dateianwendungen schnell erstellt werden können. Einfache Beispiele und Dienste können schnell und mit minimalen Abhängigkeiten erstellt werden.
Die Anwendungsklasse in einer TG-Anwendung wird von geerbt TGControllerKlasse. Methoden in dieser Klasse stehen für den Zugriff durch zur Verfügung@expose Dekorateur aus tgModul. In unserer ersten Bewerbungindex()Die Methode wird als Root unserer Anwendung zugeordnet. Die TGController-Klasse muss ebenfalls aus importiert werdentg Modul.
from tg import expose, TGController
class MyController(TGController):
@expose()
def index(self):
return 'Hello World turbogears'
Legen Sie als Nächstes die Konfiguration der Anwendung fest und deklarieren Sie das Anwendungsobjekt. AppConfig Der Klassenkonstruktor verwendet hier zwei Parameter - das minimale Attribut, das auf true gesetzt ist, und die Controller-Klasse.
config = AppConfig(minimal = True, root_controller = RootController())
application = config.make_wsgi_app()
Das make_wsgi_app() Funktion hier konstruiert Anwendungsobjekt.
Um diese Anwendung zu bedienen, müssen wir jetzt den HTTP-Server starten. Wie bereits erwähnt, werden wir verwendensimple_server Modul in wsgirefPaket zum Einrichten und Starten. Dieses Modul hatmake_server() Methode, die Portnummer und Anwendungsobjekt als Argumente benötigt.
from wsgiref.simple_server import make_server
server = make_server('', 8080, application)
server.serve_forever()
Dies bedeutet, dass unsere Anwendung unter der Portnummer 8080 von localhost bereitgestellt wird.
Das Folgende ist der vollständige Code unserer ersten TurboGears-Anwendung -
app.py
from wsgiref.simple_server import make_server
from tg import expose, TGController, AppConfig
class MyController(TGController):
@expose()
def index(self):
return 'Hello World TurboGears'
config = AppConfig(minimal = True, root_controller = MyController())
application = config.make_wsgi_app()
print "Serving on port 8080..."
server = make_server('', 8080, application)
server.serve_forever()
Führen Sie das obige Skript über die Python-Shell aus.
Python app.py
Eingeben http://localhost:8080 in der Adressleiste des Browsers, um die Nachricht "Hello World TurboGears" anzuzeigen.
Das tg.devtoolsvon TurboGears enthält Getriebe. Es handelt sich um eine Reihe von Befehlen, die für die Verwaltung komplexerer TG-Projekte nützlich sind. Full-Stack-Projekte können schnell mit dem folgenden Gearbox-Befehl erstellt werden:
gearbox quickstart HelloWorld
Dadurch wird ein Projekt mit dem Namen erstellt HelloWorld.
Ein TurboGears-Projekt enthält die folgenden Verzeichnisse:
Config - Wo die Einrichtung und Konfiguration des Projekts abhängt
Controllers - Alle Projektcontroller, die Logik der Webanwendung
i018n - Übersetzungsdateien für die unterstützten Sprachen
Lib - Utility-Python-Funktionen und -Klassen
Model - Datenbankmodelle
Public Static Files - CSS, JavaScript und Bilder
Templates - Vorlagen, die von unseren Controllern verfügbar gemacht werden.
Tests - Die Anzahl der durchgeführten Tests.
Websetup - Funktionen, die beim Einrichten der Anwendung ausgeführt werden sollen.
So installieren Sie ein Projekt
Dieses Projekt muss jetzt installiert werden. EINsetup.pyist bereits im Basisverzeichnis des Projekts enthalten. Projektabhängigkeiten werden installiert, wenn dieses Skript ausgeführt wird.
Python setup.py develop
Standardmäßig werden zum Zeitpunkt der Projekteinrichtung folgende Abhängigkeiten installiert:
- Beaker
- Genshi
- zope.sqlalchemy
- sqlalchemy
- alembic
- repoze.who
- tw2.forms
- tgext.admin ≥ 0.6.1
- WebHelpers2
- babel
Starten Sie nach der Installation das Projekt auf dem Entwicklungsserver, indem Sie den folgenden Befehl in der Shell eingeben:
Gearbox serve –reload –debug
Befolgen Sie den oben genannten Befehl, um ein vorgefertigtes Beispielprojekt bereitzustellen. Öffnenhttp://localhost:8080im Browser. Diese vorgefertigte Beispielanwendung bietet eine kurze Einführung in das TurboGears-Framework.
In diesem Hello-Projekt wird der Standard-Controller im Controller-Verzeichnis als erstellt Hello/hello/controllers.root.py. Lasst unsmodify root.py mit folgendem Code -
from hello.lib.base import BaseController
from tg import expose, flash
class RootController(BaseController):
movie = MovieController()
@expose()
def index(self):
return "<h1>Hello World</h1>"
@expose()
def _default(self, *args, **kw):
return "This page is not ready"
Sobald eine grundlegende Arbeitsanwendung fertig ist, können der Controller-Klasse weitere Ansichten hinzugefügt werden. In demMycontroller Klasse oben, eine neue Methode sayHello()hinzugefügt. Das@expose() Dekorateur befestigt /sayHelloURL dazu. Diese Funktion akzeptiert einen Namen als Parameter aus der URL.
Nach dem Starten des Servers über den Befehl 'Getriebe bedienen' http://localhost:8080. Die Hello World-Nachricht wird im Browser angezeigt, auch wenn die folgenden URLs eingegeben wurden:
http://localhost:8080/
http://localhost:8080/index
Alle diese URLs sind zugeordnet RootController.index()Methode. Diese Klasse hat auch_default()Methode, die aufgerufen wird, wenn eine URL keiner bestimmten Funktion zugeordnet ist. Die Antwort auf die URL wird von @expose () decorator einer Funktion zugeordnet.
Es ist möglich, einen Parameter über die URL an eine exponierte Funktion zu senden. Die folgende Funktion liest den Parameter name aus der URL.
@expose()
def sayHello(self, name):
return '<h3>Hello %s</h3>' %name
Die folgende Ausgabe wird im Browser als Antwort auf die URL angezeigt: http://localhost:8080/?name=MVL
Hello MVL
TurboGears ordnet URL-Parameter automatisch Funktionsargumenten zu. Unsere RootController-Klasse wird von BaseController geerbt. Dies ist definiert alsbase.py in dem lib folder der Anwendung.
Sein Code lautet wie folgt:
from tg import TGController, tmpl_context
from tg import request
__all__ = ['BaseController']
def __call__(self, environ, context):
tmpl_context.identity = request.identity
return TGController.__call__(self, environ, context)
TGController.__call__ Versendet an die Controller-Methode, an die die Anforderung weitergeleitet wird.
Ein Ereignis Obwohl HTML-Inhalte an den Browser zurückgegeben werden können, wird für eine erweiterte Ausgabe immer die Verwendung der Vorlagen-Engine bevorzugt. In einem vom Getriebe "schnell gestarteten" Full-Stack-Projekt ist Genshi als Standardvorlagen-Renderer aktiviert. In einer minimalen Anwendung muss jedoch Genshi (oder eine andere Vorlagen-Engine wie z. B. jinja) installiert und aktiviert werden. Die Genshi Template Engine ermöglicht das Schreiben von Vorlagen in reinem HTML und validiert sie, um Probleme beim Kompilieren zu erkennen und das Bereitstellen fehlerhafter Seiten zu verhindern.
Auf Vorlagen wird mit einer gepunkteten Notation verwiesen. In unserem Hello-Projekt wird ein Vorlagenverzeichnis zum Speichern von Vorlagenwebseiten bereitgestellt. Dahersample.html wird als bezeichnet hello.templates.sample(Erweiterung nicht erwähnt). TurboGears rendert diese Vorlage über einen Expose-Dekorator, um die Controller-Methode mit ihr zu verknüpfentg.render_template() Funktion.
Die exponierte Controller-Funktion gibt ein Python-Wörterbuchobjekt zurück. Dieses Wörterbuchobjekt wird wiederum an die verknüpfte Vorlage weitergegeben. Platzhalter in der Vorlage werden mit Wörterbuchwerten gefüllt.
Lassen Sie uns zunächst eine Webseite mit einem einfachen HTML-Skript anzeigen. Der exponierte Controller gibt a zurücknull dictionary object da wir nicht beabsichtigen, Daten zu senden, die im HTML-Skript analysiert werden sollen.
So erstellen Sie ein Beispiel-HTML
Unsere sample.htmlist unten angegeben. Stellen Sie sicher, dass es im Vorlagenverzeichnis des Projekts gespeichert ist.
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
</body>
</html>
Hinzufügen sample() Funktion in root.py und legen Sie sample.html durch.
@expose("hello.templates.sample")
def sample(self):
return {}
Das folgende Ergebnis wird im Browser bei einer URL angezeigt http://localhost:8080/sample wird nach dem Start des Webservers eingegeben.
Wie oben erwähnt, wird ein Wörterbuchobjekt als Sammlung von Parametern an eine Genshi-Vorlage gesendet. Diese Vorlage enthält Platzhalter, die dynamisch mit vom Controller empfangenen Parametern gefüllt werden.
Lassen Sie uns das ändern sample() Funktion zum Senden eines Wörterbuchobjekts an die Beispielvorlage.
@expose("hello.templates.sample")
def sample(self,name):
mydata = {'person':name}
return mydata
Erstellen sample.html im Vorlagenordner (templates\sample.html)
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, my name is ${person}!.</h2>
</body>
</html>
Im obigen HTML-Code ${person}ist der Platzhalter. Eingebenhttp://localhost:8080/sample?name=MVLals URL im Browser. Diese URL ist zugeordnetsample()Methode in unserem Root-Controller. Es gibt ein Wörterbuchobjekt zurück. Dies wird von der verknüpften Vorlagenseite sample.html im Vorlagenverzeichnis ausgewählt. Das $ {person} wird dann auf der Webseite durch MVL ersetzt.
Es ist auch möglich, in einer Controller-Funktion auf die HTML-Formulardaten zuzugreifen. HTML-Formular wird zum Senden von Formulardaten verwendet.
Das HTTP-Protokoll ist die Grundlage der Datenkommunikation im World Wide Web. In diesem Protokoll werden verschiedene Methoden zum Abrufen von Daten von der angegebenen URL definiert. Die folgende Tabelle fasst verschiedene http-Methoden zusammen -
Sr.Nr. | HTTP-Methoden und Beschreibung |
---|---|
1 | GET Sendet Daten in unverschlüsselter Form an den Server. Häufigste Methode. |
2 | HEAD Wie GET, jedoch ohne Antwortkörper |
3 | POST Wird zum Senden von HTML-Formulardaten an den Server verwendet. Von der POST-Methode empfangene Daten werden vom Server nicht zwischengespeichert. |
4 | PUT Ersetzt alle aktuellen Darstellungen der Zielressource durch den hochgeladenen Inhalt. |
5 | DELETE Entfernt alle aktuellen Darstellungen der Zielressource, die durch eine URL angegeben werden |
Erstellen eines HTML-Formulars
Lassen Sie uns ein HTML-Formular erstellen und Formulardaten an eine URL senden. Speichern Sie das folgende Skript als login.html
<html>
<body>
<form action = "http://localhost:8080/login" method = "get">
<p>Enter Name:</p>
<p><input type = "text" name = "nm" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
Die in diesem Formular eingegebenen Daten sind zu übermitteln ‘/login’ URL. Erstellen Sie nun eine Controller-Funktionloginpage() und machen Sie die obige HTML-Seite dafür verfügbar.
@expose("hello.templates.login")
def loginpage(self):
return {}
Geben Sie a an, um die Formulardaten zu erhalten login()Controller, dessen Parameter Formularattribute sind. Hier‘nm’ Ist der Name des Texteingabefelds in Anmeldeform, wird dieser als Parameter der Funktion login () verwendet.
@expose("hello.templates.sample")
def login(self, nm):
name = nm
return {'person':name}
Wie zu sehen ist, werden die vom Anmeldeformular empfangenen Daten an die Vorlage sample.html (früher verwendet) gesendet. Es wird von a analysiertGenshi template engine um die folgende Ausgabe zu generieren -
POST-Methode
Wenn das HTML-Formular die POST-Methode verwendet, um Daten an die URL im Aktionsattribut zu senden, werden die Formulardaten in der URL nicht verfügbar gemacht. Die codierten Daten werden in a empfangendictArgument der Controller-Funktion. Das **kw Das folgende Argument ist das Wörterbuchobjekt, das Daten enthält.
Das HTML-Formular enthält zwei Eingabetextfelder.
<html>
<body>
<form action = "http://localhost:8080/marks" method = "post">
<p>Marks in Physics:</p>
<p><input type = "text" name = "phy" /></p>
<p>Marks in Maths:</p>
<p><input type = "text" name = "maths" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
Das marks() Der Controller empfängt Formulardaten und sendet sie an sample.htmlVorlage. Code fürroot.py ist wie folgt -
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose("hello.templates.marks")
def marksform(self):
return {}
@expose("hello.templates.sample")
def marks(self, **kw):
phy = kw['phy']
maths = kw['maths']
ttl = int(phy)+int(maths)
mydata = {'phy':phy, 'maths':maths, 'total':ttl}
return mydata
Schließlich lautet die sample.html-Vorlage wie folgt:
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
<h3>Marks in Physics: ${phy}.</h3>
<h3>Marks in Maths: ${maths}.</h3> <h3>Total Marks: ${total}</h3>
</body>
</html>
Starten Sie den Server (falls noch nicht ausgeführt)
Gearbox server –reload –debug
Eingeben http://localhost::8080/marksform im Browser
Das sample.html wird folgende Ausgabe rendern -
Genshi ist eine XML-basierte Vorlagensprache. Es ist ähnlich wieKid, die früher die Template-Engine für frühere Versionen von TurboGears war. Genshi und Kid lassen sich von anderen bekannten Vorlagensprachen wie inspirierenHSLT, TAL und PHP.
Eine Genshi-Vorlage besteht aus Verarbeitungsanweisungen. Diese Anweisungen sind Elemente und Attribute in einer Vorlage. Genshi-Direktiven werden in einem Namespace definierthttp://genshi.edgewall.org/. Daher muss dieser Namespace im Stammelement der Vorlage deklariert werden.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
...
</html>
Die obige Deklaration bedeutet, dass der Standard-Namespace auf XHTML festgelegt ist und Genshi-Direktiven das Präfix 'py' haben.
Genshi-Richtlinien
In Genshi sind eine Reihe von Richtlinien definiert. Die folgende Liste listet die Genshi-Richtlinien auf -
- py:if
- py:choose
- py:for
- py:def
- py:match
- py:with
- py:replace
- py:content
- py:attrs
- py:strip
Bedingte Abschnitte
Genshi bietet zwei Anweisungen zum bedingten Rendern von Inhalten - py: if und py: Choose.
py: wenn
Der Inhalt des Elements dieser Direktive wird nur gerendert, wenn der Ausdruck in if clausebewertet als wahr. Angenommen, die Daten im Vorlagenkontext sind{‘foo’:True, ‘bar’:’Hello’}, die folgende Richtlinie -
<div>
<b py:if = "foo">${bar}</b>
</div>
wird darin enden, dass
Hello
Diese Ausgabe würde jedoch nicht gerendert, wenn ‘foo’ is set to False.
Diese Direktive kann auch als Element verwendet werden. In diesem Fall<py:if> muss durch entsprechende geschlossen werden </py:if>
<div>
<py:if test = "foo">
<b>${bar}</b>
</py:if>
</div>
py: wähle
Die erweiterte bedingte Verarbeitung ist mit der Verwendung von möglich py:choose in Kombination mit py:when und py:otherwiseRichtlinien. Diese Funktion ähneltswitch – case konstruieren in C/C++.
Ausdruck in py:choose Die Direktive wird mit verschiedenen Werten überprüft, die mit gekennzeichnet sind py:whenAlternativen und entsprechende Inhalte werden gerendert. Eine Standardalternative kann in Form von bereitgestellt werdenpy:otherwise Richtlinie.
<div py:choose = "foo”>
<span py:when = "0">0</span>
<span py:when = "1">1</span>
<span py:otherwise = "">2</span>
</div>
Das folgende Beispiel zeigt die Verwendung von py:choose und py:whenRichtlinien. Das HTML-Formular sendet Daten an / markiert die URL. Dasmarks() Funktion leitet Markierungen um und führt in Form eines Wörterbuchobjekts zu total.htmlVorlage. Die bedingte Anzeige vonresult Pass/Fail wird durch die Verwendung erreicht py:choose und py:when Richtlinien.
HTML-Skript zur Eingabe von Marken (marks.html) ist wie folgt -
<html>
<body>
<form action = "http://localhost:8080/marks" method = "post">
<p>Marks in Physics:</p>
<p><input type = "text" name = "phy" /></p>
<p>Marks in Maths:</p>
<p><input type = "text" name = "maths" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
Der vollständige Code von root.pyist wie folgt. Dasmarks() Der Controller sendet Markierungen und Ergebnisse an total.html Vorlage -
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose("hello.templates.marks")
def marksform(self):
return {}
@expose("hello.templates.total")
def marks(self, **kw):
phy = kw['phy']
maths = kw['maths']
ttl = int(phy)+int(maths)
avg = ttl/2
if avg ≥ 50:
mydata = {'phy':phy, 'maths':maths, 'total':ttl, 'result':2}
else:
mydata = {'phy':phy, 'maths':maths, 'total':ttl,'result':1}
return mydata
Das total.html im Vorlagenordner empfängt Wörterbuchdaten und analysiert sie in der HTML-Ausgabe unter folgenden Bedingungen:
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
<h3>Marks in Physics: ${phy}.</h3> <h3>Marks in Maths: ${maths}.</h3>
<h3>Total Marks: ${total}</h3>
<div py:choose = "result">
<span py:when = "1"><h2>Result: Fail</h2></span>
<span py:when = "2"><h2>Result: Pass</h2></span>
</div>
</body>
</html>
Starten Sie den Server (falls noch nicht ausgeführt)
Gearbox server –reload –debug
Eingeben http://localhost::8080/marksform im Browser -
Das total.html wird folgende Ausgabe rendern -
py: für
Element in py: for-Direktive wird für jedes Element in einem iterierbaren Objekt, normalerweise einem Python-Listenobjekt, wiederholt. Wennitems = [1,2,3] in einem Vorlagenkontext vorhanden ist, kann es durch folgendes py iteriert werden: for directive -
<ul>
<li py:for = "item in items">${item}</li>
</ul>
Die folgende Ausgabe wird gerendert -
1
2
3
Das folgende Beispiel zeigt HTML-Formulardaten, die in der Vorlage total.html mit py gerendert wurden: for-Direktive kann auch wie folgt verwendet werden:
<py:for each = "item in items">
<li>${item}</li>
</py:for>
HTML-Formularskript
<html>
<body>
<form action = "http://localhost:8080/loop" method="post">
<p>Marks in Physics:</p>
<p><input type = "text" name = "phy" /></p>
<p>Marks in Chemistry:</p>
<p><input type = "text" name = "che" /></p>
<p>Marks in Maths:</p>
<p><input type = "text" name = "maths" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
Das loop() Der Controller liest Formulardaten und sendet sie in Form eines Listenobjekts an total.template.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose("hello.templates.marks")
def marksform(self):
return {}
@expose("hello.templates.temp")
def loop(self, **kw):
phy = kw['phy']
maths = kw['maths']
che = kw['che']
l1 = []
l1.append(phy)
l1.append(che)
l1.append(maths)
return ({'subjects':['physics', 'Chemistry', 'Mathematics'], 'marks':l1})
Die Vorlage temp.html verwendet die Schleife py: for, um den Inhalt des dict-Objekts in Form einer Tabelle zu rendern.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/" lang = "en">
<body>
<b>Marks Statement</b>
<table border = '1'>
<thead>
<py:for each = "key in subjects"><th>${key}</th></py:for>
</thead>
<tr>
<py:for each = "key in marks"><td>${key}</td></py:for>
</tr>
</table>
</body>
</html>
Starten Sie den Server (falls noch nicht ausgeführt)
gearbox server –reload –debug
Eingeben http://localhost::8080/marksform im Browser.
Die folgende Ausgabe wird im Browser angezeigt, wenn das obige Formular gesendet wird.
py: def
Diese Anweisung wird zum Erstellen eines Makros verwendet. Ein Makro ist ein wiederverwendbarer Ausschnitt aus Vorlagencode. Ähnlich wie eine Python-Funktion hat sie einen Namen und kann optional Parameter haben. Die Ausgabe dieses Makros kann an einer beliebigen Stelle in eine Vorlage eingefügt werden.
Die py: def-Direktive folgt der folgenden Syntax:
<p py:def = "greeting(name)">
Hello, ${name}!
</p>
Dieses Makro kann mit einem variablen Wert für den Parameter 'name' gerendert werden.
${greeting('world')} ${greeting('everybody)}
Diese Anweisung kann auch mit einer anderen Syntaxversion wie folgt verwendet werden:
<py:def function = "greeting(name)">
<p>Hello, ${name}! </p>
</py:def>
Im folgenden Beispiel: macro() Controller in root.py sendet a dict Objekt mit zwei Schlüsseln name1 und name2 zur Vorlage macro.html.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.macro')
def macro(self):
return {'name1':'TutorialPoint', 'name2':'TurboGears'}
Diese Vorlage macro.html enthält die Definition eines Makros namens Begrüßung. Es wird verwendet, um eine Begrüßungsnachricht für vom Controller empfangene Daten zu generieren.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<body>
<h2>py:def example</h2>
<div>
<div py:def = "greeting(name)">
Hello, Welcome to ${name}!
</div>
<b>
${greeting(name1)} ${greeting(name2)}
</b>
</div>
</body>
</html>
Starten Sie den Server mit dem Getriebe
gearbox serve –reload –debug
Rufen Sie macro () controller auf, indem Sie die folgende URL in den Browser eingeben -
http://localhost:8080/macro
Die folgende Ausgabe wird im Browser gerendert -
py: mit
Mit dieser Anweisung können Sie lokalen Variablen Ausdrücke zuweisen. Diese lokalen Variablen machen den Ausdruck innerhalb weniger ausführlich und effizienter.
Unter der Annahme, dass x = 50 in Kontextdaten für eine Vorlage angegeben ist, lautet das folgende py: mit Direktive -
<div>
<span py:with = "y = 50; z = x+y">$x $y $z</span>
</div>
Dies führt zu folgender Ausgabe:
50 50 100
Eine alternative Version für py: mit Direktive ist ebenfalls verfügbar -
<div>
<py:with = "y = 50; z = x+y">$x $y $z</py:with>
</div>
Im folgenden Beispiel gibt macro () controller ein dict-Objekt mit den Tasten name, phy und maths zurück.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.macro')
def macro(self):
return {'name':'XYZ', 'phy':60, 'maths':70}
Die Vorlage macro.html fügt Werte von phy- und maths-Schlüsseln mit py: with-Direktive hinzu.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<body>
<h2>py:with example</h2>
<h3>Marks Statement for : ${name}!</h3> <b>Phy: $phy Maths: $maths <span py:with = "ttl = phy+maths">Total: $ttl</span>
</b>
</body>
</html>
Der Browser rendert die folgende Ausgabe als Antwort auf die URL http://localhost:8080/macro
Richtlinien zur Strukturmanipulation
Das py:attrs Die Direktive fügt dem Element Attribute hinzu, ändert sie oder entfernt sie.
<ul>
<li py:attrs = "foo">Bar</li>
</ul>
Wenn foo = {‘class’:’collapse’} ist in einem Vorlagenkontext vorhanden, den das obige Snippet rendert.
<ul>
<li class = "collapse">Bar</li>
</ul>
Das py:content Direktive ersetzt verschachtelten Inhalt durch das Ergebnis der Auswertung des Ausdrucks -
<ul>
<li py:content = "bar">Hello</li>
</ul>
Wenn in den Kontextdaten bar = 'Bye' angegeben ist, würde dies erzeugen
<ul>
<li>Bye</li>
</ul>
Das py:replace Direktive ersetzt das Element selbst durch das Ergebnis der Auswertung des Ausdrucks -
<div>
<span py:replace = "bar">Hello</span>
</div>
Wenn in den Kontextdaten bar = 'Bye' angegeben wird, wird dies erzeugt
<div>
Bye
</div>
Der Inhalt eines anderen XML-Dokuments (insbesondere eines HTML-Dokuments) kann mithilfe von Einschluss-Tags in das aktuelle Dokument aufgenommen werden. Um eine solche Aufnahme zu ermöglichen, muss der XInclude-Namespace im Stammelement des HTML-Dokuments deklariert werden.
<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:xi = "http://www.w3.org/2001/XInclude >
Die obige Deklaration gibt an, dass die include-Direktive enthält ‘xi’Präfix. Verwenden Sie die xi: include-Direktive wie folgt, um den Inhalt einer anderen HTML-Seite im aktuellen Dokument hinzuzufügen:
<xi:include href = "somepage.html" />
Im folgenden Beispiel enthält root.py den include () -Controller, der include.html verfügbar macht.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.include')
def include(self):
return {}
Überschrift und Fußzeile HTML
In include.html wird der Include-Namespace deklariert und der Inhalt von Heading.html und Footer.html hinzugefügt. Hier ist das HTML-Skript von templates \ include.html -
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<xi:include href = "heading.html" />
<h2>main content </h2>
<xi:include href = "footer.html" />
</body>
</html>
Hier ist der Code templates \ Heading.html -
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h1>This is page Header</h1>
</body>
</html>
Das Folgende ist die Vorlage \ footer.html
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h3>This is page footer</h3>
</body>
</html>
Starten Sie die Entwicklung mit einem Getriebe und geben Sie ein http://localhost:8080/includeim Browser. Die gerenderte Ausgabe ist wie folgt:
Auf diese Weise kann der modulare Aufbau von Ansichten erreicht werden. Wenn die in xi: include genannte Ressource nicht verfügbar ist, wird ein Fehler ausgelöst. In einem solchen Fall kann eine alternative Ressource mithilfe von xi: fallback geladen werden.
<xi:include href = “main.html”>
<xi:fallback href = ”default.html”/>
</xi.include>
Die Aufnahme von Inhalten kann als href-Attribut, das Ausdrücke enthalten kann, dynamisch gestaltet werden.
Fügen Sie den folgenden Controller in root.py hinzu.
@expose('hello.templates.ref-include')
def refinclude(self):
return {'pages':['heading','main','footer']}
Speichern Sie den folgenden Code als ref-include.html im Vorlagenordner.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<xi:include href = "${name}.html" py:for = "name in pages" />
</body>
</html>
Stellen Sie vor dem Starten des Servers sicher, dass der Vorlagenordner die Überschriften.html, main.html und footer.html enthält. Eingebenhttp://localhost:8082/refinclude im Browser, um die folgende Ausgabe zu erhalten
Das @expose()Der Dekorator rendert standardmäßig HTML-Inhalte. Dies kann jedoch auf eingestellt werdenjson content type. TurboGears unterstützt das Durchspielen von JSONtg.jsonify.JSONEncoder (**kwargs)Klasse. Um JSON-Daten zu rendern, übergeben Sie einfach JSON als Inhaltstyp, um den Dekorateur verfügbar zu machen.
@expose('json')
def jsondata(self, **kwargs):
return dict(hello = 'World')
Wenn die URL '/ jsondata' im Browser eingegeben wird, wird Folgendes angezeigt:
{"hello": "World"}
jsonp Rendern
jsonp steht für json mit Polsterung. Es funktioniert ähnlich wie die JSON-Ausgabe, mit der Ausnahme, dass es eine Anwendungs- / Javascript-Antwort mit einem Aufruf einer Javascript-Funktion bereitstellt, die alle vom Controller als Funktionsargumente zurückgegebenen Werte bereitstellt.
Um das JSONP-Rendering zu aktivieren, müssen Sie es zuerst an die Liste der erforderlichen Engines in Ihrer Anwendung anhängen. config/app_cfg.py - -
base_config.renderers.append('jsonp')
Schreiben Sie Ihren Exposé-Dekorateur wie folgt:
@expose('json')
@expose('jsonp')
def jsonpdata (self, **kwargs):
return dict(hello = 'World')
Wenn Sie auf / jsonpdata? Callback = callme zugreifen, sollten Sie Folgendes sehen:
callme({"hello": "World"});
Manchmal erfordert eine Webanwendung eine URL-Struktur mit mehr als einer Ebene. TurboGears kann die Objekthierarchie durchlaufen, um eine geeignete Methode zu finden, die Ihre Anforderung verarbeiten kann.
Ein Projekt, das mit einem Getriebe schnell gestartet wurde, verfügt über eine BaseController-Klasse im lib-Ordner des Projekts. Es ist als 'Hallo / Hallo / lib / base.py' verfügbar. Es dient als Basisklasse für alle Subcontroller. Entwerfen Sie eine von BaseController abgeleitete Unterklasse namens BlogController, um der Anwendung eine URL-Unterebene hinzuzufügen.
Dieser BlogController verfügt über zwei Controller-Funktionen, index () und post (). Beide sind so konzipiert, dass jeweils eine Vorlage, blog.html und post.html, verfügbar gemacht wird.
Note - Diese Vorlagen werden in einem Unterordner abgelegt - Vorlagen / Blog
class BlogController(BaseController):
@expose('hello.templates.blog.blog')
def index(self):
return {}
@expose('hello.templates.blog.post')
def post(self):
from datetime import date
now = date.today().strftime("%d-%m-%y")
return {'date':now}
Deklarieren Sie nun ein Objekt dieser Klasse in der RootController-Klasse (in root.py) wie folgt:
class RootController(BaseController):
blog = BlogController()
Andere Controller-Funktionen für URLs der obersten Ebene sind in dieser Klasse wie zuvor vorhanden.
Wenn eine URL http://localhost:8080/blog/Wenn es eingegeben wird, wird es der index () - Controller-Funktion innerhalb der BlogController-Klasse zugeordnet. Ähnlich,http://localhost:8080/blog/post ruft die Funktion post () auf.
Der Code für blog.html und post.html lautet wie folgt:
Blog.html
<html>
<body>
<h2>My Blog</h2>
</body>
</html>
post.html
<html>
<body>
<h2>My new post dated $date</h2>
</body>
</html>
Wenn eine URL http://localhost:8080/blog/ eingegeben wird, wird die folgende Ausgabe erzeugt -
Wenn eine URL http://localhost:8080/blog/post eingegeben wird, wird die folgende Ausgabe erzeugt -
Einer der wichtigsten Aspekte einer Webanwendung ist die Darstellung der Benutzeroberfläche für einen Benutzer. HTML bietet ein <form> -Tag, mit dem eine Schnittstelle entworfen wird. Formelemente wie Texteingabe, Radio, Auswahl usw. können entsprechend verwendet werden. Vom Benutzer eingegebene Daten werden in Form einer HTTP-Anforderungsnachricht entweder per GET- oder POST-Methode an das serverseitige Skript gesendet.
Das serverseitige Skript muss die Formularelemente aus http-Anforderungsdaten neu erstellen. In diesem Fall müssen die Formularelemente zweimal definiert werden - einmal in HTML und erneut in serverseitigem Skript.
Ein weiterer Nachteil der Verwendung von HTML-Formularen besteht darin, dass es schwierig (wenn nicht unmöglich) ist, die Formularelemente dynamisch zu rendern. HTML selbst bietet keine Möglichkeit, Benutzereingaben zu überprüfen.
ToscaWidgets2
TurboGears basiert auf ToscaWidgets2, einer flexiblen Bibliothek zum Rendern und Validieren von Formularen. Mit ToscaWidgets können wir die Formularfelder in unserem Python-Skript definieren und mithilfe einer HTML-Vorlage rendern. Es ist auch möglich, die Validierung auf das Feld tw2 anzuwenden.
Die ToscaWidgets-Bibliothek ist eine Sammlung vieler Module. Einige wichtige Module sind unten aufgeführt -
tw2.core- Es bietet Kernfunktionalität. Widgets in diesem Modul sind nicht für Endbenutzer verfügbar.
tw2.forms- Dies ist eine grundlegende Formularbibliothek. Es enthält Widgets für Felder, Feldsätze und Formulare.
tw2.dynforms - Dies enthält Funktionen für dynamische Formulare.
tw2.sqla - Dies ist eine Schnittstelle für die SQLAlchemy-Datenbank.
tw2.forms
Es enthält eine Formularklasse, die als Basis für benutzerdefinierte Formulare dient. Es gibt eine TableForm-Klasse, die beim Rendern von Feldern in einer zweispaltigen Tabelle hilfreich ist. ListForm präsentiert seine Felder in einer ungeordneten Liste.
Sr.Nr. | Felder & Beschreibung |
---|---|
1 | TextField Ein einzeiliges Texteingabefeld |
2 | TextArea Mehrzeiliges Texteingabefeld |
3 | CheckBox Präsentiert ein überprüfbares rechteckiges Feld mit Beschriftung |
4 | CheckBoxList Mehrfach auswählbare Kontrollkästchen für Gruppen |
5 | RadioButton Eine Umschalttaste zum Auswählen / Abwählen |
6 | RadioButtonList Gruppe sich gegenseitig ausschließender Optionsfelder |
7 | PasswordField Ähnlich wie bei Textfield werden jedoch keine Eingabetasten angezeigt |
8 | CalendarDatePicker Ermöglicht dem Benutzer die Auswahl eines Datums |
9 | SubmitButton Schaltfläche zum Senden eines Formulars |
10 | ImageButton Klickbare Schaltfläche mit einem Bild oben |
11 | SingleSelectField Ermöglicht die Auswahl eines einzelnen Elements aus einer Liste |
12 | MultipleSelectField Ermöglicht die Auswahl mehrerer Elemente aus der Liste |
13 | FileField Feld zum Hochladen der Datei |
14 | EmailField Ein E-Mail-Eingabefeld |
15 | URLField Ein Eingabefeld zur Eingabe der URL |
16 | NumberField Eine Nummer Spinbox |
17 | RangeField Ein Zahlenregler |
Im folgenden Beispiel wird ein Formular mit einigen dieser Widgets erstellt. Während die meisten dieser Widgets in tw2.forms definiert sind, ist CalendarDateField im Modul tw2.Dynforms definiert. Daher werden diese beiden Module zusammen mit tw2.core am Anfang importiert -
import tw2.core as twc
import tw2.forms as twf
import tw2.dynforms as twd
Ein ToscaWidgets-Formular ist eine Klasse, von der abgeleitet wurde tw2.forms.formBasisklasse. Die erforderlichen Widgets werden in einem Layout-Objekt platziert. In diesem BeispielTableLayoutwird eingesetzt. Die Widgets werden in einer zweispaltigen Tabelle gerendert. Die erste Spalte zeigt die Beschriftung und die zweite Spalte zeigt das Eingabe- oder Auswahlfeld.
Ein TextField-Objekt wird mit dem folgenden Konstruktor erstellt:
twf.TextField(size, value = None)
Wenn nicht erwähnt, nimmt das TextField-Objekt eine Standardgröße an und ist anfangs leer. Beim Deklarieren des TextArea-Objekts kann die Anzahl der Zeilen und Spalten angegeben werden.
twf.TextArea("",rows = 5, cols = 30)
Das NumberField-Objekt ist ein TextField, das nur Ziffern akzeptieren kann. Aufwärts- und Abwärtspfeile werden am rechten Rand generiert, um die Anzahl darin zu erhöhen oder zu verringern. Der Anfangswert kann auch als Argument im Konstruktor angegeben werden.
twf.NumberField(value)
Rechts neben einem CalendarDatePicker-Feld wird eine Kalenderschaltfläche angezeigt. Wenn gedrückt, erscheint eine Datumsauswahl. Der Benutzer kann manuell ein Datum in das Feld eingeben oder aus der Datumsauswahl auswählen.
twd.CalendarDatePicker()
Das EmailField-Objekt zeigt ein TextField an, der darin enthaltene Text muss jedoch im E-Mail-Format vorliegen.
EmailID = twf.EmailField()
Das folgende Formular enthält auch eine RadioButtonList. Der Konstruktor dieser Klasse enthält ein List-Objekt als Wert des Optionsparameters. Für jede Option wird ein Optionsfeld gerendert. Die Standardauswahl wird mit dem Wertparameter festgelegt.
twf.RadioButtonList(options = ["option1","option2"],value = option1)
Die CheckBoxList rendert Kontrollkästchen für jede Option in der Liste.
twf.CheckBoxList(options = [option1, option2, option3])
Die Dropdown-Liste wird in dieser ToscaWidgets-Bibliothek als SingleSelectfield bezeichnet. Elemente in einem Listenobjekt, die dem Optionsparameter entsprechen, bilden die Dropdown-Liste. Die sichtbare Beschriftung wird als Wert des Parameters prompt_text festgelegt.
twf.SingleSelectField(prompt_text = 'text', options=['item1', 'item2', 'item3'])
Standardmäßig zeigt das Formular eine Schaltfläche "Senden" mit der Überschrift "Speichern" an. Um eine andere Beschriftung anzuzeigen, erstellen Sie ein SubmitButton-Objekt und geben Sie es als Wertparameter an.
twf.SubmitButton(value = 'Submit')
Das Formular wird an eine URL gesendet, die als Wert des Aktionsparameters des Formulars angegeben wird. Standardmäßig werden die Formulardaten über die http-POST-Methode gesendet.
action = 'URL'
Im folgenden Code wird ein Formular mit dem Namen AdmissionForm mithilfe der oben erläuterten Widgets erstellt. Fügen Sie diesen Code in root.py vor der RootController-Klasse hinzu.
class AdmissionForm(twf.Form):
class child(twf.TableLayout):
NameOfStudent = twf.TextField(size = 20)
AddressForCorrespondance = twf.TextArea("", rows = 5, cols = 30)
PINCODE = twf.NumberField(value = 431602)
DateOfBirth = twd.CalendarDatePicker()
EmailID = twf.EmailField()
Gender = twf.RadioButtonList(options = ["Male","Female"],value = 'Male')
Subjects = twf.CheckBoxList(options = ['TurboGears', 'Flask', 'Django', 'Pyramid'])
MediumOfInstruction = twf.SingleSelectField(prompt_text = 'choose',
options = ['English', 'Hindi', 'Marathi', 'Telugu'])
action = '/save_form'
submit = twf.SubmitButton(value ='Submit')
Speichern Sie nun diesen Code unten als twform.html im Vorlagenverzeichnis -
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>TurboGears Form Example</title>
</head>
<body>
<div id = "tw form">
${form.display(value = dict(title = 'default title'))}
</div>
</body>
</html>
Fügen Sie in der RootController-Klasse (in root.py) die folgende Controller-Funktion hinzu:
@expose('hello.templates.twform')
def twform(self, *args, **kw):
return dict(page = 'twform', form = MovieForm)
In der AdmissionForm-Klasse haben wir stipulated/save_formals Aktions-URL. Fügen Sie daher hinzusave_form() Funktion in RootController.
@expose()
def save_movie(self, **kw):
return str(kw)
Stellen Sie sicher, dass der Server läuft (mit Getriebeservice). Eingebenhttp://localhost:8080/twform im Browser.
Durch Drücken der Senden-Taste werden diese Daten an gesendet save_form() URL, die die Formulardaten in Form eines Wörterbuchobjekts anzeigt.
{
'EmailID': u'[email protected]',
'NameOfStudent': u'Malhar Lathkar',
'Gender': u'Male',
'PINCODE': u'431602',
'DateOfBirth': u'2015-12-29',
'Subjects': [u'TurboGears', u'Flask', u'Django'],
'MediumOfInstruction': u'',
'AddressForCorrespondance': u'Shivaji Nagar\r\nNanded\r\nMaharashtra'
}
Eine gute Forms-Widget-Bibliothek sollte über eine Funktion zur Eingabevalidierung verfügen. Beispielsweise sollte der Benutzer gezwungen sein, Daten in ein Pflichtfeld einzugeben oder zu überprüfen, ob ein E-Mail-Feld eine gültige E-Mail enthält, ohne zur Validierung auf andere programmatische Mittel (wie die JavaScript-Funktion) zurückzugreifen.
Frühere Versionen der ToscaWidgets Forms Library wurden verwendet, um das FormEncode-Modul für die Validierungsunterstützung zu verwenden. ToscaWidgets2 verfügt jetzt über eine integrierte Validierungsunterstützung, die im Modul tw2.core verfügbar ist. Es ist jedoch weiterhin möglich, FormEncode-Validierungstechniken zu verwenden.
Um ein ToscaWidgets-Formular einer Validierung zu unterziehen, wird @validate decorator verwendet.
@validate(form, error_handler, validators)
Das ’form’ ist das zu validierende ToscaWidgets-Formularobjekt.
Das ‘error-handler’ ist die Controller-Methode zur Behandlung von Formularfehlern.
Das ‘validators’ sind ein Wörterbuchobjekt, das FormEncode-Validatoren enthält.
Arten von Validatoren
Das Modul tw2.core enthält eine Validator-Klasse, von der andere Validatoren geerbt werden. Es ist auch möglich, einen benutzerdefinierten Validator basierend darauf zu entwerfen. Einige der wichtigen Validatoren werden nachfolgend beschrieben -
LengthValidator- Überprüfen Sie, ob ein Wert eine vorgeschriebene Länge hat. Minimal- und Maximalgrenzen werden mit Min- und Max-Parametern definiert. Benutzerdefinierte Nachrichten für Längen unter und über min und max können als tooshort- und toolong-Parameter angegeben werden.
tw2.core.LengthValidator(min = minval, max = maxval,
msgs = { 'tooshort': (‘message for short length’),
'toolong': (‘message for long length)})
RangeValidator- Wird normalerweise zusammen mit RangeField verwendet. Es ist nützlich, den Wert eines numerischen Feldes innerhalb der minimalen und maximalen Grenzen zu validieren. Meldungen für tooshort- und toolong-Parameter können angepasst werden.
tw2.core.RangeValidator(min = minval, max = maxval,
msgs = { 'tooshort': (‘message for short length’),
'toolong': (‘message for long length)})
IntValidator- Diese Klasse wird vom RangeValidator abgeleitet. Dies wird normalerweise verwendet, um zu überprüfen, ob die Eingabe in ein normales Textfeld ganzzahlige Daten enthält. Mindest- und Höchstgrenzen sowie Fehlermeldungen können eingestellt werden. Zusätzlich kann eine Fehlermeldung für eine nicht ganzzahlige Eingabe als 'notint'-Parameter angegeben werden.
tw2.core.IntValidator(msgs = {‘notint’:’Must be Integer’})
OneOfValidator - Dieser Validator zwingt den Benutzer, nur einen Wert aus den verfügbaren Optionen in der Liste auszuwählen.
tw2.core.OneOfValidator(values = [option1, option2,..],
msgs = {‘notinlist’:’Not in List’}}
DateValidator- Sehr nützlich, um sicherzustellen, dass Benutzereingaben ein gültiges Datum sind. Das Datumsformat (Standard ist YMD) und die Fehlermeldung können angepasst werden. Es können auch minimale und maximale Datumsgrenzen festgelegt werden. DateTimeValidator ist auch verfügbar, um das Objekt der DateTime-Klasse zu überprüfen.
tw2.core.DateValidator(msgs = {format = ’%Y-%m-%d’,
'baddatetime': ('baddate', ('Must follow date format $format_str'))}
EmailValidator- Überprüft Benutzereingaben anhand einer gültigen E-Mail-Adresse. Diese Klasse wird von einem allgemeineren RegexValidator geerbt.
tw2.core.EmailValidator(msgs = {'badregex': ('bademail',
('Must be a valid email address')) }
UrlValidator- Diese Klasse wird auch von RegexValidator geerbt. Es überprüft die Benutzereingabe für eine gültige URL.
tw2.core.UrlValidator(msgs = {'badregex': ('badurl', ('Must be a valid URL’)) }
MatchValidator- Bestätigt, ob der Wert eines Feldes mit dem anderen übereinstimmt. Dies ist besonders nützlich, wenn der Benutzer ein Kennwortfeld auswählen und bestätigen muss. Die typische Verwendung von MatchValidator ist unten dargestellt.
import tw2.core as twc
import tw2.forms as twf
class AdmissionForm(twf.Form):
class child(twf.TableLayout):
validator = twc.MatchValidator('pw', 'pwconfirm')
pw = twf.PasswordField()
pwconfirm = twf.PasswordField()
Es ist auch möglich, einen zusammengesetzten Validator zu erstellen, bei dem die Validierung erfolgreich sein soll, wenn eine der Prüfungen bestanden wird. In anderen Fällen möchten Sie möglicherweise, dass die Validierung nur dann erfolgreich ist, wenn die Eingabe alle Prüfungen bestanden hat. Zu diesem Zweck stellt tw2.core die Validatoren Any und All bereit, die Unterklassen des erweiterbaren CompoundValidator sind.
TurboGears bietet ein sehr praktisches Messaging-System, mit dem Benutzer Informationen auf unauffällige Weise benachrichtigt werden können. Die TGFlash-Klasse im tg-Modul unterstützt das Flashen von Nachrichten, die in einem einfachen Cookie gespeichert sind. Diese Klasse unterstützt das Abrufen von Flash-Nachrichten sowohl auf der Serverseite als auch auf der Clientseite über JavaScript.
Das render()Die Methode der TGFlash-Klasse kann, wenn sie von Python selbst verwendet wird, über die Vorlage aufgerufen werden, um eine Flash-Nachricht zu rendern. Bei Verwendung in JavaScript wird ein WebFlash-Objekt bereitgestellt. Es macht sichtbarpayload() und render() Methoden zum Abrufen der aktuellen Flash-Nachricht und zum Rendern aus JavaScript.
Wenn ein TurboGears-Projekt mit 'Schnellstart' erstellt wird, verfügt es über eine Master.html-Vorlage. Es enthält die Definition einer Variablen dieses Flash-Objekts. Der Inhalt dieser vom Controller empfangenen Flash-Nachricht ersetzt den markierten Platzhalter in dieser Vorlage.
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
Das tg.flash_obj ist das WebFlash-Objekt, das in jeder gerenderten Vorlage durch Einschließen verfügbar ist master.htmlVorlage. Mit diesem Objekt kann die aktuelle Flash-Nachricht abgerufen und angezeigt werden.
Die Flash-Nachrichten werden mithilfe von in einem Cookie (dessen Name standardmäßig Webflash ist) gespeichert tg.flash()Methode. Die Nachrichten- und Statusparameter werden dann an sie übergeben.
tg.flash('Message', 'status')
Wenn die als Flash bezeichnete Methode eine Umleitung durchführt, wird der Flash auf der umgeleiteten Seite angezeigt. Wenn die Methode eine Vorlage direkt verfügbar macht, ist der Flash in der Vorlage selbst sichtbar.
Das Erscheinungsbild der Flash-Nachricht kann durch Anwenden des CSS-Stils auf den Statuscode angepasst werden. Ein 'Schnellstart'-Projekt enthält Fehler-, Warn-, Info- und OK-Statuscodes, die von einem Stylesheet public / css / style.css angepasst wurden. Weitere Statuscodes mit Stilen können ebenfalls hinzugefügt werden.
#flash > .warning {
color: #c09853;
background-color: #fcf8e3;
border-color: #fbeed5;
}
#flash > .ok {
color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
}
#flash > .error {
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}
#flash > .info {
color: #3a87ad;
background-color: #d9edf7;
border-color: #bce8f1;
}
Dieses externe Stylesheet muss in der Vorlage enthalten sein -
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
Die Konfiguration einer beliebigen Flash-Nachrichtenunterstützung kann durch Festlegen von Parametern für die configure () -Methode des TGFlash-Objekts oder in app_cfg.py (im Konfigurationsordner) erreicht werden. Die konfigurierbaren Parameter sind -
Sr.Nr. | Parameter & Beschreibung |
---|---|
1 | flash.cookie_name Name des Cookies, in dem Flash-Nachrichten gespeichert werden. Standard istwebflash. |
2 | flash.default_status Standardnachrichtenstatus, falls nicht angegeben (standardmäßig in Ordnung) |
3 | flash.template Wird als verwendet flash template wenn gerendert. |
4 | flash.allow_html Wendet sich on/off escaping in flash messagesStandardmäßig ist HTML nicht zulässig. |
5 | flash.js_call JavaScript-Code, der ausgeführt wird, wenn der Flash von JavaScript angezeigt wird. Standard istwebflash.render() |
6 | flash.js_template string.Template Instanz, die verwendet wird, um die vollständige JavaScript-Unterstützung für Flash-Nachrichten zu ersetzen. |
pop_payload() - Funktion fetches current flash message, statusund verwandte Informationen. Wenn Sie die Flash-Nachricht erhalten, wird das Cookie gelöscht.
render(container_id, use_js=True) - Rendern Sie die Flash-Nachricht in der Vorlage oder bieten Sie Javascript-Unterstützung für sie.
container_id ist der DIV, in dem die Nachrichten angezeigt werden, während use_js zwischen dem Rendern des Flashs als HTML oder für die Verwendung von JavaScript wechselt.
status - Wenn Sie nur den aktuellen Flash-Status abrufen, wird der Cookie gelöscht, wenn Sie den Flash-Status erhalten.
message - Wenn Sie nur die aktuelle Flash-Nachricht abrufen, wird das Cookie gelöscht, wenn Sie die Flash-Nachricht erhalten.
Wie erstelle ich eine einfache Flash-Nachricht?
Im folgenden Beispiel wird eine flash () -Methode in der Root-Controller-Klasse bereitgestellt. Es ruft eine flash () - Nachricht auf, die in der exponierten Vorlage flash.html gerendert wird
from hello.lib.base import BaseController
from tg import expose, flash, redirect, request
class RootController(BaseController):
@expose('hello.templates.flash')
def flash(self, user = None):
if user:
flash(message = "Welcome "+user,status = "ok")
else:
flash(message = "Welcome Guest",status = "info")
return {}
Der Code zum Erstellen flash.html im Vorlagenordner ist wie folgt
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears 2.3: Flash messages>/title>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
</head>
<body>
<h2>Hello TurboGears</h2>
</body>
</html>
Starten Sie den Server und geben Sie ein http://localhost:8080/flash?user=MVL im Browser
Ändern Sie die URL in http://localhost:8080/flash und sehen Sie die Flash-Nachricht anders formatiert gemäß Definition in style.css
Es ist häufig erforderlich, einfache Browserdaten zu speichern, die an den Browser eines Benutzers angehängt sind. Sitzungen sind die am häufigsten verwendete Technik. Sitzung stellt Daten dar, die nicht in einer dauerhafteren Form wie Festplattendatei oder Datenbank gespeichert werden müssen.
Sitzungsdaten in TurboGears können jedoch durch Dateisystem-, Datenbank- oder Hash-Cookie-Werte gesichert werden. Eine kleine Menge von Sitzungsdaten wird im Allgemeinen in Cookies gespeichert, aber für das größere Volumen von Sitzungsdaten wird MemCache verwendet.
MemCache ist ein Daemon auf Systemebene. Es bietet schnellen Zugriff auf zwischengespeicherte Daten und ist extrem skalierbar. Es ist jedoch nur für die Verwendung auf sicheren Servern vorgesehen und muss daher von sysadmin gewartet und gesichert werden.
Becher in der Sitzungsverwaltung
TurboGears verwendet Beaker für das Sitzungsmanagement. Ein vom Getriebe schnell gestartetes Projekt ist standardmäßig so konfiguriert, dass Hash-Cookies zum Speichern von Sitzungsdaten verwendet werden.
Jedes Mal, wenn ein Client eine Verbindung herstellt, überprüft die Sitzungs-Middleware (Becher) das Cookie anhand des Cookie-Namens, der in der Konfigurationsdatei definiert wurde. Wird das Cookie nicht gefunden, wird es im Browser gesetzt. Bei allen nachfolgenden Besuchen findet die Middleware das Cookie und verwendet es.
Um die Sitzungsverwaltung zu aktivieren, sollte die Sitzungsklasse durch folgende Importanweisung in das Projekt aufgenommen werden:
from tg import session
So speichern Sie die Daten in einer Sitzungsvariablen:
session[‘key’] = value
session.save()
So rufen Sie die Sitzungsvariable ab:
return session[‘key’]
Beachten Sie, dass Sie die Sitzung explizit speichern müssen, damit Ihre Schlüssel in dieser Sitzung gespeichert werden.
Das delete() Methode des Sitzungsobjekts löscht alle Benutzersitzungen -
session.delete()
Obwohl es nicht üblich ist, alle Benutzersitzungen in einer bestimmten Produktionsumgebung zu löschen, werden Sie dies normalerweise zur Bereinigung tun, nachdem Usability- oder Funktionstests durchgeführt wurden.
Im Folgenden finden Sie ein einfaches Beispiel zur Demonstration von Sitzungen. Die RootController-Klasse hat einesetsession() Methode, die eine Sitzungsvariable festlegt.
from hello.lib.base import BaseController
from tg import expose, session
class RootController(BaseController):
@expose()
def setsession(self):
session['user'] = 'MVL'
session.save()
str = "<b>sessionVariable set to "+session['user']
str = str+"<br><a href = '/getsession'>click here to retrieve</a></b>"
return str
@expose()
def getsession(self):
return "<b>value of session variable retrieved " +session['user'] +"</b>"
Eingeben http://localhost:8080/setsession
Ein Link im Browser führt zu http://localhost:8080/getsession welches die Sitzungsvariable abruft und anzeigt -
Um die Leistung einer Webanwendung zu verbessern, insbesondere wenn sie an langwierigen Vorgängen beteiligt ist, werden Caching-Techniken verwendet. TurboGears bietet zwei Arten von Caching-Techniken:
Whole-page Caching
Es funktioniert auf HTTP-Protokollebene, um vollständige Anforderungen an den Server zu vermeiden, indem entweder der Browser des Benutzers oder ein Zwischenproxyserver (z. B. Squid) die Anforderung abfängt und eine zwischengespeicherte Kopie der Datei zurückgibt.
Application-level Caching
Dies funktioniert innerhalb des Anwendungsservers, um berechnete Werte, häufig die Ergebnisse komplexer Datenbankabfragen, zwischenzuspeichern, sodass zukünftige Anforderungen vermeiden können, dass die Werte neu berechnet werden müssen. Für Webanwendungen bietet das Caching auf Anwendungsebene eine flexible Möglichkeit, die Ergebnisse komplexer Abfragen zwischenzuspeichern, sodass die Gesamtlast einer bestimmten Controller-Methode auf einige benutzerspezifische oder fallspezifische Abfragen und der Rendering-Overhead einer Vorlage reduziert werden kann .
Caching auf Anwendungsebene
Wie bereits erwähnt, ist das 'Schnellstart'-TurboGears-Projekt so konfiguriert, dass das Beaker-Paket für die Caching-Unterstützung aktiviert wird. Beaker unterstützt die folgenden Backends, die für die Cache-Speicherung verwendet werden:
memory- Wird für die prozessbezogene Speicherung verwendet. Es ist extrem schnell.
filesystem - Speicherung pro Prozess sowie Multiprozess.
DBM database - pro Prozess, mehrere Prozesse, ziemlich schnell.
SQLAlchemy database- Speicher pro Datenbankserver. Langsamer im Vergleich zu den oben angegebenen Optionen.
Memcached - Speicherbasierter Cache für mehrere Server.
Controller-Caching
Für schnelles Controller-Caching a cached()Dekorateur ist vorhanden. Der gesamte Controller-Body wird abhängig von verschiedenen Anforderungsparametern zwischengespeichert. Die Definition vontg.decorators.cached() Dekorateur ist wie folgt
tg.decorators.cached(key, expire, type,
query-args, cache_headers, invalidate_on_startup, cache_response)
Die Beschreibung der Parameter lautet wie folgt:
Sr.Nr. | Parameter & Beschreibung |
---|---|
1 | key Gibt die Controller-Parameter an, die zum Generieren des Cache-Schlüssels verwendet werden. |
2 | expire Zeit in Sekunden, bevor der Cache abläuft. Der Standardwert ist "Nie". |
3 | Type DBM, Speicher, Datei, Memcached oder Keine. |
4 | cache_headers Ein Tupel von Headernamen, die Antwortheader angeben. |
5 | invalidate_on_startup Wenn True, wird der Cache bei jedem Start oder Neustart der Anwendung ungültig. |
6 | cache_response Die Antwort sollte zwischengespeichert werden oder nicht. Der Standardwert ist True. |
Es folgt ein Beispiel für das Zwischenspeichern von Controllern -
@cached(expire = 100, type = 'memory')
@expose()
def simple(self):
return "This is a cached controller!"
Caching auf Vorlagenebene
Die Genshi-Vorlagen-Engine ruft die Vorlage aus einem Cache ab, wenn sich ihr Inhalt nicht geändert hat. Die Standardgröße dieses Caches ist 25. Standardmäßig ist das automatische Neuladen von Vorlagen wahr. Um die Leistung zu verbessern, können die folgenden Einstellungen vorgenommen werdenapp_cfg.py - -
[app:main]
genshi.max_cache_size = 100
auto_reload_templates = false
Um eine Vorlage zwischenzuspeichern, müssen Sie nur die zurückgeben tg_cache Option vom Controller, der die zwischengespeicherte Vorlage rendert.
Der tg_cache ist ein Wörterbuch, das die folgenden Schlüssel akzeptiert:
key - Der Cache-Schlüssel. Default: Keiner.
expire - wie lange der Cache am Leben bleiben muss. Default: läuft nie ab
type - Speicher, DBM, zwischengespeichert. Default: dbm.
Das folgende Beispiel zeigt das Zwischenspeichern von Vorlagen -
@expose(hello.templates.user')
def user(self, username):
return dict(user = username, tg_cache = dict(key = user, expire = 900))
Obwohl es möglich ist, SQL in TurboGears-Anwendungen zu verwenden, um CRUD-Operationen für jede relationale Datenbank auszuführen, ist es ratsam, SQLAlchemy zu verwenden. Ein Python-Toolkit ist ein leistungsstarker Object Relation Mapper, der Anwendungsentwicklern die volle Leistung und Flexibilität von SQL bietet. Neben der Unterstützung von SQL-basierten Datenbanken über SQLAlchemy unterstützt TurboGears auch die MongoDB-Datenbank über Ming. In diesem Abschnitt wird die Funktionalität von SQLAlchemy erläutert.
Was ist ORM (Object Relational Mapping)?
Die meisten Programmiersprachenplattformen sind objektorientiert. Die Daten auf RDBMS-Servern werden dagegen als Tabellen gespeichert. Die Objektbeziehungszuordnung ist eine Technik zum Zuordnen von Objektparametern zur zugrunde liegenden RDBMS-Tabellenstruktur. Eine ORM-API bietet Methoden zum Ausführen von CRUD-Operationen, ohne dass SQL-Rohanweisungen geschrieben werden müssen.
Wenn ein TurboGears-Projekt mit dem Befehl 'Schnellstart' aus dem Getriebe-Toolkit erstellt wird, ist die SQLAlchemy-Unterstützung standardmäßig durch die folgenden Konfigurationseinstellungen aktiviert:
config['use_sqlalchemy'] = True
config['sqlalchemy.url'] = 'sqlite:///devdata.db'
Das 'Schnellstart'-Projekt erstellt auch ein Modellpaket darin. Zum Beispiel hat ein "Hallo" -Projekt "Hallo \ Hallo \ Modell". Die folgenden Dateien werden in diesem Paket erstellt -
__init__.py- Hier wird der Datenbankzugriff eingerichtet. Die Modellobjekte der Anwendung werden in dieses Modul importiert. Es hat auch eine DBSession - einen globalen Sitzungsmanager und eine DeclarativeBase, die eine Basisklasse für alle Modellklassen ist.
auth.py- Hier werden die vom Authentifizierungsstapel verwendeten Modelle definiert. Zusätzliche Datenbankmodelle werden in diesem Paket als separates Modul gespeichert und in der Datei __init__.py hinzugefügt.
Fügen wir ein Studentenmodell hinzu, das eine Studententabelle in unserem einrichtet sqlite Datenbank.
Hello\hello\model\student.py
from sqlalchemy import *
from sqlalchemy.orm import mapper, relation, relation, backref
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Integer, Unicode, DateTime
from hello.model import DeclarativeBase, metadata, DBSession
from datetime import datetime
class student(DeclarativeBase):
__tablename__ = 'student'
uid = Column(Integer, primary_key = True)
name = Column(Unicode(20), nullable = False, default = '')
city = Column(Unicode(20), nullable = False, default = '')
address = Column(Unicode(100), nullable = False, default = '')
pincode = Column(Unicode(10), nullable = False, default = '')
Fügen Sie nun dieses Modell hinzu init_model() Funktion im Inneren __init__.py.Diese Funktion enthält bereits das Auth-Modell. Fügen Sie unser Studentenmodell darunter hinzu.
# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student
Wenn Sie möchten, dass die Tabelle zum Zeitpunkt der Einrichtung der Modelle mit einigen Daten initialisiert wird, fügen Sie diese in der Datei bootstrap.py im Websetup-Paket hinzu. Fügen Sie die folgenden Anweisungen in diebootstrap() Funktion.
s1 = model.student()
s1.name = 'M.V.Lathkar'
s1.city = 'Nanded'
s1.address = 'Shivaji Nagar'
s1.pincode = '431602'
model.DBSession.add(s1)
model.DBSession.flush()
transaction.commit()
Die Modelle werden durch Ausführen des Befehls setup-app des Getriebes initialisiert -
gearbox setup-app
Das Sitzungsobjekt von SQLAlchemy verwaltet alle Persistenzoperationen des ORM-Objekts.
Die folgenden Sitzungsmethoden führen CRUD-Operationen aus:
DBSession.add(model object) - fügt einen Datensatz in die zugeordnete Tabelle ein.
DBSession.delete(model object) - löscht den Datensatz aus der Tabelle.
DBSession.query(model).all() - Ruft alle Datensätze aus der Tabelle ab (entsprechend einer SELECT-Abfrage).
Sie können einen Filter auf den abgerufenen Datensatz anwenden, indem Sie ein Filterattribut verwenden. Verwenden Sie beispielsweise die folgende Anweisung, um Datensätze mit city = 'Hyderabad' in der Schülertabelle abzurufen:
DBSession.query(model.student).filter_by(city = ’Hyderabad’).all()
Wir werden nun sehen, wie man mit den Modellen über Controller-URLs interagiert.
Lassen Sie uns zunächst ein ToscaWidgets-Formular für die Eingabe der Schülerdaten entwerfen
Hello\hello\controllers.studentform.py
import tw2.core as twc
import tw2.forms as twf
class StudentForm(twf.Form):
class child(twf.TableLayout):
name = twf.TextField(size = 20)
city = twf.TextField()
address = twf.TextArea("",rows = 5, cols = 30)
pincode = twf.NumberField()
action = '/save_record'
submit = twf.SubmitButton(value = 'Submit')
Fügen Sie im RootController (root.py der Hello-Anwendung) die folgende Funktionszuordnung hinzu: '/ add' URL -
from hello.controllers.studentform import StudentForm
class RootController(BaseController):
@expose('hello.templates.studentform')
def add(self, *args, **kw):
return dict(page='studentform', form = StudentForm)
Speichern Sie den folgenden HTML-Code als studentform.html im Vorlagenordner -
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>Student Registration Form</title>
</head>
<body>
<div id = "getting_started">
${form.display(value = dict(title = 'Enter data'))}
</div>
</body>
</html>
Eingeben http://localhost:8080/addim Browser nach dem Start des Servers. Das folgende Schülerinformationsformular wird im Browser geöffnet:
Das obige Formular soll an die ‘/save_record’URL. Daher asave_record() Funktion muss in der hinzugefügt werden root.pyum es zu entlarven. Die Daten aus dem Schülerformular werden von dieser Funktion als empfangendict()Objekt. Es wird verwendet, um der Schülertabelle, die dem Schülermodell zugrunde liegt, einen neuen Datensatz hinzuzufügen.
@expose()
#@validate(form = AdmissionForm, error_handler = index1)
def save_record(self, **kw):
newstudent = student(name = kw['name'],city = kw['city'],
address = kw['address'], pincode = kw['pincode'])
DBSession.add(newstudent)
flash(message = "new entry added successfully")
redirect("/listrec")
Bitte beachten Sie, dass nach dem erfolgreichen Hinzufügen der Browser zu weitergeleitet wird ‘/listrec’ URL. Diese URL wird von alistrec() function. Diese Funktion wählt alle Datensätze in der Schülertabelle aus und sendet sie in Form eines Diktierobjekts an die Vorlage studentlist.html. Dieselistrec() Funktion ist wie folgt -
@expose ("hello.templates.studentlist")
def listrec(self):
entries = DBSession.query(student).all()
return dict(entries = entries)
Die Vorlage studentlist.html durchläuft das Eintragswörterbuchobjekt mit der Anweisung py: for. Die Vorlage studentlist.html lautet wie folgt:
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/">
<head>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
<title>Welcome to TurboGears</title>
</head>
<body>
<h1>Welcome to TurboGears</h1>
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
<h2>Current Entries</h2>
<table border = '1'>
<thead>
<tr>
<th>Name</th>
<th>City</th>
<th>Address</th>
<th>Pincode</th>
</tr>
</thead>
<tbody>
<py:for each = "entry in entries">
<tr>
<td>${entry.name}</td> <td>${entry.city}</td>
<td>${entry.address}</td> <td>${entry.pincode}</td>
</tr>
</py:for>
</tbody>
</table>
</body>
</html>
Besuchen Sie jetzt die http://localhost:8080/addund geben Sie Daten in das Formular ein. Durch Klicken auf die Schaltfläche "Senden" wird der Browser zu studentlist.html weitergeleitet. Außerdem wird die Meldung "Neuer Datensatz erfolgreich hinzugefügt" angezeigt.
Das ToscaWidgets enthält ein DataGrid-Steuerelement, mit dem Daten schnell in Tabellenform dargestellt werden können. Das DataGrid-Objekt wird wie folgt deklariert:
from tw2.forms import DataGrid
student_grid = DataGrid(fields = [('Name', 'name'),('City', 'city'),
('Address','address'), ('PINCODE', 'pincode')])
Jetzt ruft die Funktion showgrid () alle Datensätze in der Schülertabelle ab und macht die Daten für die Vorlage grid.html verfügbar. Zuerst wird der Code für die Funktion showgrid () und dann der Code grid.html unten angegeben -
Raster anzeigen()
@expose('hello.templates.grid')
def showgrid(self):
data = DBSession.query(student).all()
return dict(page = 'grid', grid = student_grid, data = data)
grid.html
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
<head>
<title>Student Registration Form</title>
</head>
<body>
<div id = "getting_started">
<div>${grid.display(value = data)}</div>
</div>
</body>
</html>
Die folgenden tabellarischen Daten werden angezeigt, wenn http://localhost:8080/showlist URL wird im Browser eingegeben -
TurboGears bietet einen praktischen Dekorator namens paginate (), um die Ausgabe auf den Seiten zu teilen. Dieser Dekorator wird mit dem Dekorator expose () kombiniert. Der Dekorator @Paginate () verwendet das Wörterbuchobjekt des Abfrageergebnisses als Argument. Darüber hinaus wird die Anzahl der Datensätze pro Seite durch den Wert des Attributs items_per_page bestimmt. Stellen Sie sicher, dass Sie die Paginate-Funktion von tg.decorators in Ihren Code importieren.
Schreiben Sie die Funktion listrec () in root.py wie folgt um:
from tg.decorators import paginate
class RootController(BaseController):
@expose ("hello.templates.studentlist")
@paginate("entries", items_per_page = 3)
def listrec(self):
entries = DBSession.query(student).all()
return dict(entries = entries)
Die Elemente pro Seite sind auf drei festgelegt.
In der Vorlage studentlist.html wird die Seitennavigation durch Hinzufügen von tmpl_context.paginators.entries.pager () unter der Direktive py: for aktiviert. Der Code für diese Vorlage sollte wie folgt lauten:
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/">
<head>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
<title>Welcome to TurboGears</title>
</head>
<body>
<h1>Welcome to TurboGears</h1>
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
<h2>Current Entries</h2>
<table border = '1'>
<thead>
<tr>
<th>Name</th>
<th>City</th>
<th>Address</th>
<th>Pincode</th>
</tr>
</thead>
<tbody>
<py:for each = "entry in entries">
<tr>
<td>${entry.name}</td> <td>${entry.city}</td>
<td>${entry.address}</td> <td>${entry.pincode}</td>
</tr>
</py:for>
<div>${tmpl_context.paginators.entries.pager()}</div>
</tbody>
</table>
</body>
</html>
Eingeben http://localhost:8080/listrecim Browser. Die erste Seite der Datensätze in der Tabelle wird angezeigt. Oben in dieser Tabelle werden auch Links zu Seitenzahlen angezeigt.
So fügen Sie Datagrid Paginierungsunterstützung hinzu
Es ist auch möglich, Datagrid um Paginierungsunterstützung zu erweitern. Im folgenden Beispiel dient das paginierte Datagrid zur Anzeige der Aktionsschaltfläche. Um die Aktionsschaltfläche zu aktivieren, wird das Datagrid-Objekt mit folgendem Code erstellt:
student_grid = DataGrid(fields = [('Name', 'name'),('City', 'city'),
('Address','address'), ('PINCODE', 'pincode'),
('Action', lambda obj:genshi.Markup('<a
href = "%s">Edit</a>' % url('/edit',
params = dict(name = obj.name)))) ])
Hier ist die Aktionsschaltfläche mit dem Namensparameter jeder Zeile im Datenraster verknüpft.
Schreiben Sie die um showgrid() Funktion wie folgt -
@expose('hello.templates.grid')
@paginate("data", items_per_page = 3)
def showgrid(self):
data = DBSession.query(student).all()
return dict(page = 'grid', grid = student_grid, data = data)
Der Browser zeigt paginiertes Datagrid wie folgt an:
Durch Klicken auf die Schaltfläche Bearbeiten in der dritten Zeile wird zur folgenden URL umgeleitet http://localhost:8080/edit?name=Rajesh+Patil
TurboGears bietet die Erweiterung tgext.admin, die von tgext.crud und sprox unterstützt wird. Dieses Sprox ist ein Paket, das zum Erstellen von Web-Widgets direkt aus dem Datenbankschema verwendet wird. Dies kann zum automatischen Erstellen einfacher Verwaltungsseiten verwendet werden und ist das Toolkit, mit dem die Seite / admin in den neu gestarteten Anwendungen betrieben wird.
Standardmäßig bietet der Administrator einen automatisch generierten Zugriff auf alle in Ihre Projektmodelle / __ init__.py importierten Modelle.
How to Create TurboGears Admin
The default TurboGears admin is created as an object of AdminController class −
from tgext.admin.controller import AdminController
class RootController(BaseController):
admin = AdminController(model, DBSession, config_type = TGAdminConfig)
This creates an admin for all the models with the default TurboGears admin configuration.
Through the manager, a user has been created during the setup phase. Now, it is possible to get access to the TurboGears Admin at http://localhost:8080/admin The first time this page is accessed, it will ask for authentication. You can simply provide the username and password of the user that the setup-app command created for us −
Username: manager
Password: managepass
In order to login to the quickstarted project, add the following functions to the RootController class (controllers/root.py).
from hello.lib.base import BaseController
from tg import expose, flash, redirect, request,url, lurl
from tg import redirect, validate
from hello import model
from hello.model import DBSession
from tgext.admin.tgadminconfig import BootstrapTGAdminConfig as TGAdminConfig
from tgext.admin.controller import AdminController
from tg.exceptions import HTTPFound
class RootController(BaseController):
admin = AdminController(model, DBSession, config_type = TGAdminConfig)
@expose('hello.templates.index')
def index(self):
return dict(page = 'index')
@expose('hello.templates.login')
def login(self, came_from = lurl('/'), failure = None, login = ''):
if failure is not None:
if failure == 'user-not-found':
flash(_('User not found'), 'error')
elif failure == 'invalid-password':
flash(_('Invalid Password'), 'error')
login_counter = request.environ.get('repoze.who.logins', 0)
if failure is None and login_counter > 0:
flash(_('Wrong credentials'), 'warning')
return dict(page = 'login', login_counter = str(login_counter),
came_from = came_from, login = login)
@expose()
def post_login(self, came_from = lurl('/')):
if not request.identity:
login_counter = request.environ.get('repoze.who.logins', 0) + 1
redirect('/login', params = dict(came_from = came_from,
__logins = login_counter))
userid = request.identity['repoze.who.userid']
flash(('Welcome back, %s!') % userid)
return HTTPFound(location = came_from)
Login to the 'quickstarted' application after starting the server and by visiting http://localhost:8080/login and then enter the manager credentials as displayed above. The browser will display an admin page like the one shown below −
The page shows all the models created in this application. You can click any model to see the listing of entries in it −
The 'New' button on top of this datagrid allows the record to be added. Similarly, action buttons for editing and deleting a record are also provided in actions column of this datagrid. A search box is also displayed to select records conditionally.
A TurboGears application is created by quickstart and setup-app options of the gearbox toolkit, which has the authorization and authentication support enabled by default. The models declared in auth.py are set up and initialized as per values assigned in bootstrap.py.
The following models are declared in auth.py −
User Model
The User model contains the design of a tg_user table. This table is used by the repose.who package. This repose.who package is a powerful as well as an extensible authentication library for WSGI applications. The structure of a user model is as follows −
class User(DeclarativeBase):
"""
__tablename__ = 'tg_user'
user_id = Column(Integer, autoincrement = True, primary_key=True)
user_name = Column(Unicode(16), unique = True, nullable = False)
email_address = Column(Unicode(255), unique = True,nullable=False)
display_name = Column(Unicode(255))
_password = Column('password', Unicode(128))
created = Column(DateTime, default = datetime.now)
This group model contains the definition tg_group table. Its definition is given in auth.py as follows −
class Group(DeclarativeBase):
__tablename__ = 'tg_group'
group_id = Column(Integer, autoincrement = True,primary_key = True)
group_name = Column(Unicode(16),unique = True,nullable = False)
display_name = Column(Unicode(255))
created = Column(DateTime, default = datetime.now)
Another model permission is also set up, which contains permission definition.
class Permission(DeclarativeBase):
__tablename__ = 'tg_permission'
permission_id = Column(Integer,autoincrement = True,primary_key = True)
permission_name = Column(Unicode(63), unique = True, nullable = False)
description = Column(Unicode(255))
At the time of setting up models, the following data is added in these tables −
u = model.User()
u.user_name = 'manager'
u.display_name = 'Example manager'
u.email_address = '[email protected]'
u.password = 'managepass'
model.DBSession.add(u)
g = model.Group()
g.group_name = 'managers'
g.display_name = 'Managers Group'
g.users.append(u)
model.DBSession.add(g)
p = model.Permission()
p.permission_name = 'manage'
p.description = 'This permission gives an administrative right'
p.groups.append(g)
model.DBSession.add(p)
u1 = model.User()
u1.user_name = 'editor'
u1.display_name = 'Example editor'
u1.email_address = '[email protected]'
u1.password = 'editpass'
model.DBSession.add(u1)
Predicate Model
The predicates module in tg package contains definitions for predicate checkers. A predicate is a condition that must be met for the user to be able to access the requested source. Such a predicate, or condition, may be made up of more predicates – those are called compound predicates. Action controllers, or controllers, may have only one predicate, be it single or compound.
If a user is not logged in, or does not have the proper permissions, this predicate checker throws a 401 (HTTP Unauthorized), which is caught by the repoze.who middleware to display the login page allowing the user to login, and redirecting the user back to the proper page when they are done.
The different conditions or predicates defined in tg.predicates module are −
Sr.No. | tg.predicates module & Description |
---|---|
1 | All Check if all predicates specified are met |
2 | Any Check if at least one of specified predicates are met |
3 | is_user Check that the authenticated user's username is the specified one |
4 | in_group Check that the user belongs to the specific group. |
5 | in_all_groups Check that the user belongs to all of the specified groups. |
6 | in_any_group Check that the user belongs to at least one of the specified groups. |
7 | is_anonymous Check that the current user is anonymous. |
8 | has_permission Check that the current user has the specified permission. |
9 | has_all_permissions Check that the current user has been granted all of the specified permissions. |
10 | has_any_permission Check that the user has at least one of the specified permissions. |
For example, if you have a predicate, which is grant access user belonging to customers group, then you can use the following built-in predicate checker −
from tg.predicates import in_group
p in_group(‘customers’)
The following predicate checker will grant access to ‘root’ user or anybody with ‘manage’ permission −
from tg.predicates import Any, is_user, has_permission
p = Any(is_user('root'), has_permission('manage'),
sg = 'Only administrators can remove blog posts')
TurboGears also supports MongoDB document databases. It uses Ming, an Object Document Mapper API. Usage of Ming is very much similar to SQLAlchemy. Ming query language makes it possible to port SQLAlchemy based TurboGears project to Ming.
What is PyMongo
PyMongo is a Python distribution containing tools for working with MongoDB. Ming extends PyMongo providing −
- Declarative Models
- Schema Validation and Conversion
- Schema Evolution
- Pure InMemory MongoDB Implementation
- Unit of Work
- Identity Map
- One-To-Many, Many-To-One and Many-To-Many Relations
First of all, you need to download and install MongoDB. The latest distribution of MongoDB can be downloaded from https://www.mongodb.org/downloads
On Windows, start MongoDB server by providing -dbpath option −
C:\mongodb\bin>Mongod --dbpath d:\mongo
D:\mongo folder is designated to store MongoDB database. Server starts listening at http://localhost:27017. Now to start MongoDB shell use the following command −
C:\mongodb\bin>Mongo
Unsere MongoDB-Umgebung ist jetzt bereit.
Erstellen Sie nun ein TurboGears-Projekt mit der Option -ming -
gearbox quickstart --ming Hello
Dieses schnell gestartete Projekt bietet eine Authentifizierungs- und Autorisierungsschicht, wie sie für die SQLAlchemy-Version bereitgestellt wird. Diese Anwendung versucht nun, eine Verbindung zu einem Server an Port 27017 auf dem lokalen Computer herzustellen. Die Datei development.ini im Projektordner enthält die folgenden Einstellungen:
ming.url = mongodb://localhost:27017/
ming.db = hello
Richten Sie das Projekt mit dem folgenden Befehl ein:
Python setup.py develop
Der Projektordner enthält den Unterordner models mit den folgenden Dateien:
__init__.py - Hier ist die databaseZugang ist eingerichtet. Ihre Sammlungen sollten seinimported into this module. Zum Beispiel werden wir die Studentensammlung in dieses Paket aufnehmen.
session.py - Diese Datei definiert die session of your database connection. Sie müssen dies jedes Mal importieren, wenn Sie a deklarieren müssenMappedClass um die Sitzung anzugeben perform queries.
auth.py - Diese Datei wird erstellt, wenn Sie haben enabled authentication and authorizationim Schnellstart. Es definiert drei Sammlungenrepoze.who, auf das sich außerdem Folgendes stützt: Benutzer, Gruppe und Berechtigung.
Definieren Sie Ihre Sammlung
Standardmäßig konfiguriert TurboGears Ming in einem deklarativen Modus. Dies ähnelt der deklarativen Unterstützung von SQLAlchemy und erfordert, dass jedes Modell von der MappedClass-Klasse erbt.
Für die MappedClass muss eine Unterklasse __mongometa__ verfügbar sein, die die Details zum Namen der Sammlung, in der die Dokumente gespeichert sind, und zur Sitzung, in der die Dokumente gespeichert sind, enthält.
MappedClass enthält auch die Definition von Feldern im Dokument. Das Odm-Modul von Ming enthält Definitionen verschiedener Arten von Feldeigenschaften -
- FieldProperty
- ForeignIdProperty
- RelationProperty
Das ming.schema module definiert die folgenden Datentypen -
- ming.schema.Anything
- ming.schema.Array
- ming.schema.Binary
- ming.schema.Bool
- ming.schema.Float
- ming.schema.Int
- ming.schema.ObjectId
- ming.schema.Scalar
- ming.schema.String
Speichern Sie den folgenden Code als student.py im Ordner hello / models, um die Schülersammlung in diesem Modell hinzuzufügen.
Hallo \ models \ student.py
from ming import schema
from ming.odm import MappedClass
from ming.odm import FieldProperty, ForeignIdProperty
from hello.model import DBSession
Class student(MappedClass):
class __mongometa__:
session = DBSession
name = 'student'
_id = FieldProperty(schema.ObjectId)
name = FieldProperty(schema.String(required = True))
city = FieldProperty(schema.String(if_missing = ''))
address = FieldProperty(schema.String(if_missing = ''))
pincode = FieldProperty(schema.String(if_missing = ''))
Fügen Sie dieses Modell schließlich in hello \ models \ __ init__.py ein
# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student
Führen Sie zum Einrichten dieser Modelle den folgenden Getriebebefehl aus:
Gearbox setup-app
Starten Sie den Server mit dem folgenden Getriebebefehl:
Gearbox serve –reload –debug
Öffnen Sie die Homepage dieser Anwendung (http://localhost:8080/)und melden Sie sich mit Manager-Anmeldeinformationen an. Auf der Admin-Seite dieser Anwendung wird die Liste der eingerichteten Modelle angezeigt. (Login als Manager, Passwort-Managementpass)
Die Erstellung von Sammlungen kann auch in der MongoDB-Weboberfläche sowie in der MongoDB-Shell überprüft werden.
Die ODMSession wird verwendet, um mehrere Datenbankoperationen mit den folgenden Funktionen auszuführen:
- model.query.find()
- model.query.find_and_modify()
- model.remove()
- model.update()
- model.flush()
Entwerfen eines ToscoWidget-Formulars
Wir werden nun ein ToscoWidget-Formular entwerfen, um Schülerdaten einzugeben und in die Tabelle aufzunehmen, die dem Schülermodell zugrunde liegt.
Im Folgenden finden Sie den Code zum Erstellen einer studentform.py -
Hallo \ controller \ studentform.py
import tw2.core as twc
import tw2.forms as twf
class StudentForm(twf.Form):
class child(twf.TableLayout):
name = twf.TextField(size = 20)
city = twf.TextField()
address = twf.TextArea("",rows = 5, cols = 30)
pincode = twf.NumberField()
action = '/save_record'
submit = twf.SubmitButton(value = 'Submit')
In der Rootcontroller-URL '/ add' der Anwendung, die die Funktion add () aufruft, wird das oben gestaltete Formular im Browser geöffnet. Die Senden-Schaltfläche ruft dann die Funktion save_record () auf. Es ruft die Formulardaten ab, speichert sie in der Schülertabelle und leitet die Anwendung an die URL '/ listrec' weiter, wodurch die Vorlage für die Schülerliste verfügbar gemacht wird.
Die root.py für diese Aktivität lautet wie folgt:
Hallo / controller / root.py.
from hello.lib.base import BaseController
from tg import expose, flash, redirect, request,url, lurl
from tg import redirect, validate
from hello import model
from hello.model import DBSession
from hello.model.student import student
from hello.controllers.studentform import StudentForm
class RootController(BaseController):
@expose()
def index(self):
return "<h1>Hello World</h1>"
@expose ("hello.templates.studentlist")
def listrec(self):
entries = student.query.find()
return dict(entries = entries)
@expose('hello.templates.studentform')
def add(self, *args, **kw):
return dict(page = 'studentform', form = StudentForm)
@expose()
def save_record(self, **kw):
newstudent = student(name = kw['name'],city = kw['city'],
address = kw['address'], pincode = kw['pincode'])
DBSession.flush()
flash(message = "new entry added successfully")
redirect("/listrec")
Die folgenden Vorlagen werden im Vorlagenordner erstellt:
Hallo \ templates \ studentform.html
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/" lang = "en">
<head>
<title>Student Registration Form</title>
</head>
<body>
<div id = "getting_started">
${form.display(value = dict(title = 'Enter data'))}
</div>
</body>
</html>
Hallo \ templates \ studentlist.html
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/">
<head>
<link rel = "stylesheet" type = "text/css" media = "screen"
href = ${tg.url('/css/style.css')}" /> <title>Welcome to TurboGears</title> </head> <body> <h1>Welcome to TurboGears</h1> <py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)"> <div py:if = "flash" py:replace = "Markup(flash)" /> </py:with> <h2>Current Entries</h2> <table border = '1'> <thead> <tr> <th>Name</th> <th>City</th> <th>Address</th> <th>Pincode</th> </tr> </thead> <tbody> <py:for each = "entry in entries"> <tr> <td>${entry.name}</td>
<td>${entry.city}</td> <td>${entry.address}</td>
<td>${entry.pincode}</td>
</tr>
</py:for>
</tbody>
</table>
</body>
</html>
Starten Sie den Server neu und geben Sie ein http://localhost:8080/add im Browser -
Jedes Mal, wenn die Daten hinzugefügt und die Senden-Taste gedrückt wird, wird die Liste der aktuellen Einträge angezeigt.
Das Getriebe-Toolkit enthält einen Gerüstbefehl, der sehr nützlich ist, um schnell neue Komponenten der TurboGears-Anwendung zu erstellen. Eine durch den Schnellstartbefehl des Getriebes generierte Anwendung verfügt über eine Skelettvorlage im Modellordner (model.py.template), einen Vorlagenordner (template.html.template) und einen Steuerungsordner (controller.py.template). Diese '.template'-Dateien werden als Grundlage für die Erstellung neuer Gerüste für eine Anwendung verwendet
Um beispielsweise ein neues Modell mit dem Namen mymodel zu erstellen, führen Sie einfach den folgenden Befehl aus:
gearbox scaffold model mymodel
Dieser Befehl generiert model / mymodel.py mit der darin definierten newmodel-Klasse.
# -*- coding: utf-8 -*-
"""Mymodel model module."""
from sqlalchemy import *
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Integer, Unicode, DateTime, LargeBinary
from sqlalchemy.orm import relationship, backref
from hello.model import DeclarativeBase, metadata, DBSession
class Mymodel(DeclarativeBase):
__tablename__ = 'mymodels'
uid = Column(Integer, primary_key = True)
data = Column(Unicode(255), nullable = False)
user_id = Column(Integer, ForeignKey('tg_user.user_id'), index = True)
user = relationship('User', uselist = False,
backref = backref('mymodels',cascade = 'all, delete-orphan'))
__all__ = ['Mymodel']
Die Benutzer können nun Änderungen an der Tabellenstruktur gemäß ihren Anforderungen vornehmen und diese dann in die Tabelle importieren model/__init__.py um das Modell in der Anwendung verfügbar zu machen.
Um ein Modell, eine Controller-Klasse und eine Indexseite zu erstellen, können alle diese drei Komponenten gleichzeitig mit dem folgenden Befehl erstellt werden.
gearbox scaffold model controller template mymodel
Dieser Befehl führt zu controller \ mymodel.py, in dem die MymodelController-Klasse ordnungsgemäß definiert ist.
# -*- coding: utf-8 -*-
"""Mymodel controller module"""
from tg import expose, redirect, validate, flash, url
# from tg.i18n import ugettext as _
# from tg import predicates
from hello.lib.base import BaseController
# from hello.model import DBSession
class MymodelController(BaseController):
# Uncomment this line if your controller requires an authenticated user
# allow_only = predicates.not_anonymous()
@expose('hello.templates.mymodel')
def index(self, **kw):
return dict(page = 'mymodel-index')
Um diesen Controller zu verwenden, hängen Sie ihn in Ihre Anwendung RootController ein, um eine Instanz von MymodelController zu definieren. Fügen Sie diese Zeilen in die Datei controller \ root.py - ein
From hello.controller.mymodel import MymodelController
class RootController(BaseController): mymodel = MymodelController()
Im Vorlagenordner wird auch eine Vorlagengerüstvorlage \ mymodel.html erstellt. Es fungiert als Indexseite für die URL '/ mymodel'.
Das erzeugte mymodel.html file im Vorlagenordner wird wie folgt sein -
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<xi:include href = "master.html" />
<head>
<title>Mymodel</title>
</head>
<body>
<div class = "row">
<div class = "col-md-12">
<h2>Mymodel</h2>
<p>Template page for Mymodel</p>
</div>
</div>
</body>
</html>
In TurboGears gibt es drei Möglichkeiten, Verhaltensweisen in die vorhandenen Anwendungen einzufügen.
Hook - Es ist ein Mechanismus, mit dem es möglich ist, ein Ereignis zu definieren und registrierte Listener zu benachrichtigen, wenn die Ereignisse ausgegeben werden.
Controller Wrapper- Es befindet sich zwischen TurboGears und Controller, so dass es möglich ist, den Controller wie einen Dekorateur zu erweitern. Somit kann es an jede Controller-Anwendung eines Drittanbieters angehängt werden.
Application Wrapper - Es ähnelt jeder WSGI-Middleware, funktioniert jedoch nur im TurboGears-Kontext.
In diesem Kapitel wird erläutert, wie Hooks in einer vorhandenen Anwendung verwendet werden.
Haken
Hooks sind Ereignisse, die in der Konfigurationsdatei der Anwendung registriert sind app_cfg.py. Jeder Controller wird dann von Ereignisdekorateuren an diese Ereignisse angeschlossen.
Die folgenden Hooks sind in TurboGears definiert -
Sr.Nr. | Haken & Beschreibung |
---|---|
1 | Startup() Nur anwendungsweit, wird aufgerufen, wenn die Anwendung gestartet wird. |
2 | shutdown() Nur anwendungsweit, wird aufgerufen, wenn die Anwendung beendet wird. |
3 | configure_new_app Neue Anwendung wurde vom Anwendungskonfigurator erstellt. |
4 | before_config(app) Nur anwendungsweit, direkt nach dem Erstellen der Anwendung, jedoch vor dem Einrichten von Optionen und Middleware aufgerufen |
5 | after_config(app) Nur anwendungsweit, wird aufgerufen, nachdem alles eingerichtet wurde. |
6 | before_validate Wird vor der Validierung aufgerufen |
7 | before_call Wird nach der Validierung aufgerufen, bevor die eigentliche Controller-Methode aufgerufen wird. |
8 | before_render Wird vor dem Rendern einer Controller-Vorlage aufgerufen. Die Ausgabe ist der Controller-Rückgabewert. |
9 | after_render Wird aufgerufen, nachdem das Rendern einer Controller-Vorlage abgeschlossen ist. |
Registrieren Sie einen Haken
Damit register a Hook, Funktionen erstellen in app_cfg.py und registrieren Sie sie dann mit dem folgenden Code -
tg.hooks.register(hookane, function, controller)
Im folgenden Code werden die Hooks on_startup, on_shutdown und before_render in app_cfg.py registriert.
def on_startup():
print 'hello, startup world'
def on_shutdown():
print 'hello, shutdown world'
def before_render(remainder, params, output):
print 'system wide before render'
# ... (base_config init code)
tg.hooks.register('startup', on_startup)
tg.hooks.register('shutdown', on_shutdown)
tg.hooks.register('before_render', before_render)
Der before_render-Hook ist bei einer Controller-Funktion im Rootcontroller registriert. Fügen Sie den folgenden Code in controller \ root.py hinzu.
from tg.decorators import before_render
class RootController(BaseController):
@expose('hello.templates.index')
@before_render(before_render_cb)
def index(self, *args, **kw):
return dict(page = 'index')
Wenn die Anwendung bereitgestellt wird, wird in der Konsole eine Startmeldung angezeigt.
hello, startup world
Starting Standard HTTP server on http://127.0.0.1:8080
Wenn im Browser die URL '/' eingegeben wird, wird auf der Konsole eine Meldung angezeigt, die dem Hook before_render entspricht.
system wide before render
Going to render {'page': 'index'}
TurboGears-Erweiterungen sind gekennzeichnet durch tgext.* package. Ein Gearbox-Toolkit enthält den Befehl tgext zum Erstellen einer Beispielerweiterung. Zum Beispiel -
gearbox tgext -n myextension
Andere optionale Parameter für diesen Befehl sind -
--author - Name des Paketautors.
--email - E-Mail des Paketautors.
--licence- Lizenz für Paket verwendet. Standard ist MIT.
--description - Beschreibung des Pakets.
--keywords - Paketschlüsselwörter (Standard: turbogears2.extension).
Dadurch wird ein Verzeichnis tgext.myextension erstellt, in dem sich eine einfache Beispielerweiterung befindet.
Run the setup.py innerhalb des Verzeichnisses -
Python setup.py install
Das _init_.py Datei im Inneren tgext/myextension Ordner enthält -
Plugme function - Dies ist der Einstiegspunkt der Erweiterung.
SetupExtension class - Hier erfolgt die Erweiterungsinitialisierung.
On_startup function - Innerhalb der Klasse ist ein Hook für die Funktion __call__ innerhalb der Klasse registriert.
Kurzfassung des tgext\myextension\__init__.py.
from tg import config
from tg import hooks
from tg.configuration import milestones
import logging
log = logging.getLogger('tgext.myextension')
def plugme(configurator, options = None):
if options is None:
options = {}
log.info('Setting up tgext.myextension extension...')
milestones.config_ready.register(SetupExtension(configurator))
return dict(appid='tgext.myextension')
class SetupExtension(object):
def __init__(self, configurator):
self.configurator = configurator
def __call__(self):
log.info('>>> Public files path is %s' % config['paths']['static_files'])
hooks.register('startup', self.on_startup)
def echo_wrapper_factory(handler, config):
def echo_wrapper(controller, environ, context):
log.info('Serving: %s' % context.request.path)
return handler(controller, environ, context)
return echo_wrapper
self.configurator.register_wrapper(echo_wrapper_factory)
def on_startup(self):
log.info('+ Application Running!')
Sobald die Erweiterung installiert ist, aktivieren Sie sie, indem Sie die folgenden Ergänzungen in der Anwendung vornehmen app_cfg.py Konfigurationsdatei.
from tgext.myextension import plugme
plugme(base_config)
Wenn wir den Server mit einem Getriebeserverbefehl starten, kann die Benachrichtigung über eine neu registrierte Erweiterung auf der Konsole wie folgt angezeigt werden:
14:29:13,250 INFO [tgext.myextension] Setting up tgext.myextension extension...
14:29:13,453 INFO [tgext.myextension] >>> Public files path is c:\tghello\hello\hello\public
14:29:13,453 INFO [tgext.myextension] + Application Running!
Starting Standard HTTP server on http://127.0.0.1:8080
Wenn Ihre Erweiterung Modelle und Controller verfügbar machen muss, sollten Sie sich wahrscheinlich die ansehen Pluggable Applications, die wiederverwendbare Turbogears-Anwendungen erstellen sollen, die in andere Anwendungen integriert werden können, um deren Funktionen zu erweitern.
Verwenden Sie den folgenden Getriebebefehl, um eine steckbare Anwendung zu erstellen:
gearbox quickstart-pluggable plugtest
Diese steckbaren Anwendungen können ihre eigenen definieren -
Controllers - wird automatisch gemountet, wenn die Anwendung gelöscht wird.
Models - die innerhalb und außerhalb der angeschlossenen Anwendung verfügbar sein werden.
Helpers - die automatisch im 'H'-Objekt in einer Anwendungsvorlage verfügbar gemacht werden kann.
Bootstrap - wird ausgeführt, wenn die setup-app aufgerufen wird.
Statics - die auf ihrem eigenen privaten Weg verfügbar sein werden.
Installieren Sie diese Plugtest-Anwendung und mounten Sie sie, indem Sie die folgenden Änderungen in vornehmen app_cfg.py.
from tgext.pluggable import plug
plug(base_config, plugtest)
REST steht für REPräsentation State Tübertragen. REST ist eine auf Webstandards basierende Architektur und verwendet das HTTP-Protokoll für die Datenkommunikation. Es dreht sich um eine Ressource, bei der jede Komponente eine Ressource ist und auf eine Ressource über eine gemeinsame Schnittstelle mit HTTP-Standardmethoden zugegriffen wird. REST wurde zuerst von eingeführtRoy Fielding in 2000.
Was ist ein RestController?
RestController in TurboGears bietet einen Mechanismus für den Zugriff auf die Methode der Anforderung, nicht nur auf die URL. Die Standard-HTTP-Sprache umfasst: GET, POST, PUT und DELETE. Der RestController unterstützt diese und fügt einige Verknüpfungen für den URL-Versand hinzu, mit denen die Anzeige der Daten als Formulare und Listen für den Benutzer etwas einfacher wird.
Um zu erklären, wie RESTful mit TurboGears funktioniert, definieren wir einen einfachen Webservice, der eine Liste von Schülern anzeigt.
Der Code für das Studentenmodell ist unten angegeben -
model \ student.py
# -* - coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.orm import mapper, relation, relation, backref
from sqlalchemy import Table, ForeignKey, Column
from sqlalchemy.types import Integer, Unicode, DateTime
from hello.model import DeclarativeBase, metadata, DBSession
from datetime import datetime
class student(DeclarativeBase):
__tablename__ = 'student'
uid = Column(Integer, primary_key = True)
name = Column(Unicode(20), nullable = False, default = '')
city = Column(Unicode(20), nullable = False, default = '')
address = Column(Unicode(100), nullable = False, default = '')
pincode = Column(Unicode(10), nullable = False, default = '')
Erstellen Sie nun einen Controller, der auf RestController basiert, und stellen Sie eine Ansichtsfunktion bereit, um die Liste der Schüler im JSON-Format aufzulisten.
Controller \ student.py
from tg import RestController
from tg import expose
from hello import model
from hello.model import DBSession
from hello.model.student import student
from tg.decorators import with_trailing_slash
class StudentController(RestController):
@expose('json')
def get_all(self):
students = DBSession.query(student).all()
return dict(students=students)
Hängen Sie diesen StudentController in RootController der Anwendung ein, indem Sie die folgenden Zeilen in einfügen root.py - -
from hello.controllers.student import StudentController
class RootController(BaseController):
students = StudentController()
Geht zu http://localhost:8080/students Es wird die Liste unserer Schüler im JSON-Format enthalten.
Wir verwenden die Post-Methode, um zu definieren, wie wir unseren Schüler in der Datenbank speichern. Diese Methode wird immer dann aufgerufen, wenn die http://localhost:8080/student Auf die URL wird über eine POST-Anfrage zugegriffen -
@expose('json')
def post(self, name, city, address, pincode):
newstudent = student(name = name, city = city, address = address, pincode = pincode)
DBSession.add(newstudent)
DBSession.flush()
return dict(student = newstudent)
Verwendung der get_one() Methode können wir dem Benutzer ein Element aus der Datenbank anzeigen -
@expose('json')
def get_one(self, movie_id):
newstudent = DBSession.query(student).get(uid)
return dict(movie = movie)
PUT ist die Methode zum Aktualisieren eines vorhandenen Datensatzes mit REST -
@expose('json')
def put(self, name = name, city = city, address = address, pincode = pincode, **kw):
newstudent = DBSession.query(student).get(name)
newstudent.name = name
newstudent.city = city
newstudent.address = address
newstudent.pincode = pincode
return dict(student = newstudent)
Das Arbeitspferd von delete ist an die Methode post_delete angehängt. Hier entfernen wir den Datensatz tatsächlich aus der Datenbank und leiten ihn dann zurück zur Listenseite -
@expose('json')
def post_delete(self, uid, **kw):
newstudent = DBSession.query(student).get(uid)
DBSession.delete(newstudent)
return dict(movie = newstudent.uid)
Um von einer Entwicklungsumgebung zu einer vollwertigen Produktionsumgebung zu wechseln, muss die Anwendung auf einem echten Webserver bereitgestellt werden. Je nachdem, was Sie haben, stehen verschiedene Optionen zum Bereitstellen einer TurboGears-Webanwendung zur Verfügung.
Apache mit mod_wsgi
Das mod_wsgi ist ein Apache-Modul, das von Graham Dumpleton entwickelt wurde. Damit können WSGI-Programme über den Apache-Webserver bereitgestellt werden.
Installieren Sie zunächst Apache 2.X für Ihre Plattform, falls dies noch nicht geschehen ist. Sobald Sie Apache installiert haben, installieren Sie mod_wsgi. Erstellen und aktivieren Sie die virtuelle Python-Umgebung auf dem Server und installieren Sie TurboGears darin.
Installieren Sie Ihre Anwendung im Application Director und erstellen Sie ein Skript mit dem Namen app.wsgi.
Konfigurieren Sie die Apache-Installation wie folgt:
<VirtualHost *:80>
ServerName www.site1.com
WSGIProcessGroup www.site1.com
WSGIDaemonProcess www.site1.com user = <username>
group = www-data threads = 4 python-path = <pythonpath>
WSGIScriptAlias myapp/app.wsgi
#Serve static files directly without TurboGears
Alias /images
Alias /css
Alias /js
CustomLog
ErrorLog
</VirtualHost>
Starten Sie Apache neu
Art http://www.site1.com/ in einem Browser, um auf die Anwendung zuzugreifen.
TurboGears unter Circus und Chaussette
Circus ist ein Prozess- und Socket-Manager. Es kann zur Überwachung und Steuerung von Prozessen und Sockets verwendet werden. In Verbindung mit dem Chaussette WSGI-Server kann dies zu einem leistungsstarken Tool für die Bereitstellung Ihrer Anwendung und die Verwaltung aller zugehörigen Prozesse werden, die Ihre Anwendungen benötigen.
TurboGears - GoogleAppEngine
Installieren Sie das Google AppEngine SDK für Python unter der folgenden URL: https://cloud.google.coms
Installieren Sie die Google AppEngine auf Ihrem System. Öffnen Sie dann die Google Developer Console und melden Sie sich mit Ihrem Google-Konto an.https://console.developers.google.com/start
Erstellen Sie ein neues Projekt mit dem Namen mytgapp - -
Erstellen Sie mit Google AppEngine Launcher eine neue Anwendung mit dem Namen mytgapp.
Die folgenden Dateien werden im angegebenen Verzeichnis erstellt -
- app.yaml
- favicon.ico
- index.yaml
- main.py
Standardmäßig basiert die erstellte Anwendung auf dem Webapp2-Framework. Um diese Abhängigkeit zu entfernen, bearbeiten Sie die Datei app.yaml und löschen Sie den folgenden Teil:
libraries:
- name: webapp2
version: "2.5.2"
Erstellen Sie eine temporäre virtuelle Umgebung in einem Verzeichnis mit dem Namen mytgapp und installieren Sie TurboGears. Erstellen Sie darin eine TurboGears-Anwendung. Jetzt können wir mit der Bearbeitung fortfahrenmain.py Datei, die von AppEngine gestartet wird, um unsere Anwendung auszuführen und dort tatsächlich eine TurboGears-Anwendung zu schreiben.
Fügen Sie den folgenden Inhalt hinzu main.py - -
import os
import site
site.addsitedir(os.path.join(os.path.dirname(__file__), 'packages'))
from tg import expose, TGController, AppConfig
class RootController(TGController):
@expose()
def index(self):
return "<h1>Hello World</h1>"
config = AppConfig(minimal = True, root_controller = RootController())
app = config.make_wsgi_app()
Führen Sie nun die Anwendung über AppEngine Launcher aus und klicken Sie auf die Schaltfläche Durchsuchen, um festzustellen, ob die Anwendung auf dem lokalen Host ordnungsgemäß funktioniert.
Wir haben bereits ein Projekt namens mytgapp in der Entwicklerkonsole erstellt. Klicken Sie nun im Launcher auf die Schaltfläche Bereitstellen. Nachdem der Bereitstellungsprozess abgeschlossen ist,http://mytgapp.appspot.com/ Besuchen Sie, um unsere Bewerbung online zu sehen.