Turbogears - Szybki przewodnik

Co to jest platforma internetowa?

Web Application Framework lub po prostu Web Framework reprezentuje zbiór bibliotek i modułów, który umożliwia programiście aplikacji internetowych pisanie aplikacji bez martwienia się o szczegóły niskiego poziomu, takie jak protokoły, zarządzanie wątkami itp.

Co to jest TurboGears?

TurboGears to framework aplikacji internetowych napisany w Pythonie. Pierwotnie stworzony przez Kevina Dangoora w 2005 roku, jego najnowsza wersja TurboGears (wersja 2.3.7) jest zarządzana przez grupę programistów kierowaną przez Marka Ramma i Florent Aide.

TurboGears podąża za paradygmatem Model-View-Controller, podobnie jak większość nowoczesnych platform internetowych, takich jak Rails, Django, Struts itp.

Kontroler widoku modelu

MVC to wzorzec projektowania oprogramowania do tworzenia aplikacji internetowych. Wzorzec kontrolera widoku modelu składa się z trzech części -

  • Model - Za utrzymanie danych odpowiada najniższy poziom wzorca.

  • View - Jest odpowiedzialny za wyświetlanie całości lub części danych użytkownikowi.

  • Controller - Kod oprogramowania, który kontroluje interakcje między modelem a widokiem.

MVC jest popularny, ponieważ izoluje logikę aplikacji od warstwy interfejsu użytkownika i wspiera rozdzielanie problemów. Tutaj Kontroler otrzymuje wszystkie zapytania dotyczące aplikacji, a następnie współpracuje z Modelką w celu przygotowania wszelkich danych wymaganych przez Widok. Widok następnie wykorzystuje dane przygotowane przez kontrolera do wygenerowania ostatecznej, możliwej do zaprezentowania odpowiedzi. Abstrakcję MVC można przedstawić graficznie w następujący sposób -

Model

Model jest odpowiedzialny za zarządzanie danymi aplikacji. Odpowiada na żądanie z widoku, a także odpowiada na instrukcje administratora, aby się zaktualizować.

Widok

Prezentacja danych w określonym formacie, wywołana decyzją administratora o przedstawieniu danych. Są to systemy szablonów oparte na skryptach, bardzo łatwe do zintegrowania z technologią AJAX.

Administrator

Kontroler jest odpowiedzialny za reagowanie na dane wejściowe użytkownika i wykonywanie interakcji na obiektach modelu danych. Kontroler odbiera dane wejściowe, weryfikuje je, a następnie wykonuje operację biznesową, która modyfikuje stan modelu danych.

TurboGears jest zbudowany na podstawie wielu bibliotek i narzędzi. Te narzędzia zmieniły się w różnych wersjach TurboGears. Poniżej wymieniono składniki aktualnej wersji (wersja 2.3.7).

SQLAlchemy

Jest to zestaw SQL typu open source, który zapewnia mapowanie relacji obiektów (ORM) dla kodu Pythona.

Genshi

Ten silnik szablonów służy do konstruowania front-endu aplikacji TG. System szablonów internetowych łączy szablon z pewnym źródłem danych w celu renderowania dynamicznych stron internetowych.

ToscaWidgets

Jest to biblioteka widżetów do generowania formularzy HTML z kontrolkami po stronie serwera. Tosca działa również jako oprogramowanie pośredniczące do łączenia się z widżetami JavaScript i zestawami narzędzi.

Skrzynia biegów

Zawiera zestaw poleceń do zarządzania projektami i aplikacjami serwera TurboGears. Aplikacje TurboGears można wdrażać na dowolnym serwerze WWW zgodnym ze standardem WSGI.

Interfejs bramy serwera sieci Web (WSGI) został przyjęty jako standard do tworzenia aplikacji internetowych w języku Python. WSGI to specyfikacja uniwersalnego interfejsu pomiędzy serwerem WWW a aplikacjami WWW. Pakiet wsgiref jest referencyjną implementacją WSGI. Służy do dodawania obsługi WSGI do frameworka WWW TurboGears. Moduł simple_server w tym pakiecie implementuje prosty serwer HTTP, który obsługuje aplikacje WSGI. Będziemy go używać do testowania aplikacji opracowanych podczas tego samouczka.

Warunek wstępny

Python 2.6 lub nowszy. Wcześniejsze wersje TurboGears nie były zgodne z Python 3.X. Najnowsza wersja twierdzi, że działa dobrze na Pythonie 3.X. Jednak oficjalna dokumentacja TurboGears jest nadal oparta na środowisku Python 2.7.

Następujące polecenie installs virtualenv -

pip install virtualenv

To polecenie potrzebuje administratorprzywileje. Dodajsudo before pipw systemie Linux / Mac OS. Jeśli korzystasz z systemu Windows, zaloguj się jako administrator. W systemie Ubuntu virtualenv można zainstalować za pomocą swojego menedżera pakietów.

Sudo apt-get install virtualenv

Po zainstalowaniu nowe środowisko wirtualne jest tworzone w folderze.

mkdir newproj
cd newproj
virtualenv venv

Aby aktywować odpowiednie środowisko, włącz Linux/OS X

venv/bin/activate

na Windows

venv\scripts\activate

Jesteśmy teraz gotowi install TurboGearsw tym środowisku. Minimalna instalacja TurboGears odbywa się za pomocą następującego polecenia -

pip install TurboGears2

Powyższe polecenie można uruchomić bezpośrednio bez środowiska wirtualnego w przypadku instalacji w całym systemie.

Aby zainstalować TurboGears wraz z narzędziami programistycznymi, użyj następującego polecenia -

pip install tg.devtools

TurboGears ma tryb minimalny, który umożliwia szybkie tworzenie aplikacji jednoplikowych. Proste przykłady i usługi można szybko zbudować przy minimalnym zestawie zależności.

Klasa aplikacji w aplikacji TG jest dziedziczona z TGControllerklasa. Metody w tej klasie są dostępne dla@expose dekorator z tgmoduł. W naszej pierwszej aplikacjiindex()metoda jest mapowana jako katalog główny naszej aplikacji. Klasa TGController również musi zostać zaimportowana ztg moduł.

from tg import expose, TGController
class MyController(TGController):
   @expose()
   def index(self):
      return 'Hello World turbogears'

Następnie ustaw konfigurację aplikacji i zadeklaruj obiekt aplikacji. AppConfig konstruktor klasy przyjmuje tutaj dwa parametry - minimalny atrybut ustawiony na wartość true i klasę kontrolera.

config = AppConfig(minimal = True, root_controller = RootController())
application = config.make_wsgi_app()

Plik make_wsgi_app() funkcja konstruuje tutaj obiekt aplikacji.

Aby obsłużyć tę aplikację, musimy teraz uruchomić serwer HTTP. Jak wspomniano wcześniej, użyjemysimple_server moduł w wsgirefpakiet, aby go skonfigurować i uruchomić. Ten moduł mamake_server() metoda, która wymaga numeru portu i obiektu aplikacji jako argumentów.

from wsgiref.simple_server import make_server
server = make_server('', 8080, application)
server.serve_forever()

Oznacza to, że nasza aplikacja będzie obsługiwana na porcie numer 8080 hosta lokalnego.

Poniżej znajduje się pełny kod naszej pierwszej aplikacji TurboGears -

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()

Uruchom powyższy skrypt z powłoki Pythona.

Python app.py

Wchodzić http://localhost:8080 w pasku adresu przeglądarki, aby wyświetlić wiadomość „Hello World TurboGears”.

Plik tg.devtoolsTurboGears zawiera skrzynię biegów. Jest to zestaw poleceń przydatnych przy zarządzaniu bardziej złożonymi projektami TG. Projekty pełnego stosu można szybko utworzyć za pomocą następującego polecenia Gearbox -

gearbox quickstart HelloWorld

Spowoduje to utworzenie projektu o nazwie HelloWorld.

Projekt TurboGears zawiera następujące katalogi -

  • Config - Gdzie zależy konfiguracja i konfiguracja projektu

  • Controllers - Wszyscy kontrolerzy projektu, logika aplikacji internetowej

  • i018n - Pliki tłumaczeń dla obsługiwanych języków

  • Lib - Funkcje i klasy narzędzi w języku Python

  • Model - Modele baz danych

  • Public Static Files - CSS, JavaScript i obrazy

  • Templates - Szablony ujawnione przez naszych kontrolerów.

  • Tests - Zestaw wykonanych testów.

  • Websetup - Funkcje do wykonania podczas konfiguracji aplikacji.

Jak zainstalować projekt

Ten projekt musi teraz zostać zainstalowany. ZAsetup.pyjest już udostępniony w katalogu podstawowym projektu. Zależności projektu są instalowane po wykonaniu tego skryptu.

Python setup.py develop

Domyślnie podczas konfigurowania projektu są instalowane następujące zależności -

  • Beaker
  • Genshi
  • zope.sqlalchemy
  • sqlalchemy
  • alembic
  • repoze.who
  • tw2.forms
  • tgext.admin ≥ 0.6.1
  • WebHelpers2
  • babel

Po instalacji rozpocznij udostępnianie projektu na serwerze deweloperskim, wydając następujące polecenie w powłoce -

Gearbox serve –reload –debug

Postępuj zgodnie z powyższym poleceniem, aby wyświetlić gotowy przykładowy projekt. otwartyhttp://localhost:8080w wyszukiwarce. Ta gotowa przykładowa aplikacja zawiera krótkie wprowadzenie do samego frameworka TurboGears.

W tym projekcie Hello, domyślny kontroler jest tworzony w katalogu controllers jako Hello/hello/controllers.root.py. Pozwól nammodify root.py z następującym kodem -

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"

Gdy podstawowa aplikacja działająca jest gotowa, można dodać więcej widoków do klasy kontrolera. wMycontroller klasa powyżej, nowa metoda sayHello()jest dodany. Plik@expose() dekorator załącza /sayHelloURL do niego. Ta funkcja została zaprojektowana tak, aby akceptować nazwę jako parametr z adresu URL.

Po uruchomieniu serwera za pomocą komendy `` serwis skrzyni biegów '', http://localhost:8080. Wiadomość Hello World zostanie wyświetlona w przeglądarce, nawet jeśli zostaną wprowadzone następujące adresy URL -

http://localhost:8080/

http://localhost:8080/index

Wszystkie te adresy URL są mapowane RootController.index()metoda. Ta klasa również ma_default()metoda, która zostanie wywołana za każdym razem, gdy adres URL nie jest odwzorowany na żadną określoną funkcję. Odpowiedź na adres URL jest odwzorowywana na funkcję przez dekorator @expose ().

Możliwe jest przesłanie parametru do udostępnionej funkcji z adresu URL. Poniższa funkcja odczytuje parametr name z adresu URL.

@expose()
def sayHello(self, name):
   return '<h3>Hello %s</h3>' %name

Następujące dane wyjściowe będą widoczne w przeglądarce jako odpowiedź na adres URL - http://localhost:8080/?name=MVL

Hello MVL

TurboGears automatycznie mapuje parametry adresu URL na argumenty funkcji. Nasza klasa RootController jest dziedziczona z BaseController. Jest to zdefiniowane jakobase.py w lib folder podaniowy.

Jego kod jest następujący -

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__ wysyła do metody kontrolera, do której kierowane jest żądanie.

Zdarzenie, chociaż treść HTML może zostać zwrócona do przeglądarki, w celu uzyskania bardziej zaawansowanych wyników zawsze preferowane jest użycie silnika szablonów. W projekcie z pełnym stosem „szybkiego uruchomienia” przez gearbox, Genshi jest włączony jako domyślny renderer szablonów. Jednak w minimalnej aplikacji Genshi (lub jakikolwiek inny silnik szablonów, taki jak jinja) musi być zainstalowany i włączony. Silnik szablonów Genshi pozwala na pisanie szablonów w czystym xhtml i weryfikuje je, aby wykrywać problemy w czasie kompilacji i zapobiegać wyświetlaniu uszkodzonych stron.

Szablony są określane za pomocą notacji z kropkami. W naszym projekcie Hello udostępniono katalog szablonów do przechowywania szablonów stron internetowych. W związku z tymsample.html będzie określany jako hello.templates.sample(rozszerzenie nie wymienione). TurboGears renderuje ten szablon za pomocą dekoratora expose, aby połączyć z nim metodę kontroleratg.render_template() funkcjonować.

Udostępniona funkcja kontrolera zwraca obiekt słownika języka Python. Ten obiekt słownika jest z kolei przekazywany do połączonego szablonu. Symbole zastępcze w szablonie są wypełnione wartościami słownikowymi.

Na początek wyświetlmy stronę internetową ze zwykłym skryptem html. Udostępniony kontroler zwraca pliknull dictionary object ponieważ nie zamierzamy wysyłać żadnych danych do przeanalizowania wewnątrz skryptu HTML.

Jak stworzyć przykładowy kod HTML

Nasz sample.htmlpodano poniżej. Upewnij się, że jest on przechowywany w katalogu szablonów projektu.

<html>
   <head>
      <title>TurboGears Templating Example</title>
   </head>
	
   <body>
      <h2>Hello, Welcome to TurboGears!.</h2>
   </body>
</html>

Dodaj sample() funkcja w root.py i ujawnij za jego pośrednictwem plik sample.html.

@expose("hello.templates.sample")
   def sample(self):
      return {}

Poniższy wynik zostanie wyświetlony w przeglądarce, gdy adres URL http://localhost:8080/sample jest wprowadzany po uruchomieniu serwera WWW.

Jak wspomniano powyżej, obiekt słownika jest wysyłany jako zbiór parametrów do szablonu Genshi. Ten szablon zawiera „place holders”, które są dynamicznie wypełniane parametrami otrzymywanymi z kontrolera.

Zmieńmy sample() funkcji, aby wysłać obiekt słownika do przykładowego szablonu.

@expose("hello.templates.sample")
   def sample(self,name):
      mydata = {'person':name}
      return mydata

Stwórz sample.html w folderze szablonów (templates\sample.html)

<html>
   <head>
      <title>TurboGears Templating Example</title>
   </head>
	
   <body>
      <h2>Hello, my name is ${person}!.</h2>
   </body>
</html>

W powyższym kodzie HTML, ${person}jest symbolem zastępczym. Wchodzićhttp://localhost:8080/sample?name=MVLjako adres URL w przeglądarce. Ten adres URL jest zamapowany nasample()metoda w naszym kontrolerze głównym. Zwraca obiekt słownika. Jest to wybierane przez połączoną stronę szablonu sample.html w katalogu szablonów. $ {Person} jest następnie zastępowane przez MVL na stronie internetowej.

Możliwy jest również dostęp do danych formularza HTML w funkcji kontrolera. Formularz HTML służy do wysyłania danych formularza.

Protokół Http jest podstawą komunikacji danych w sieci WWW. W tym protokole zdefiniowano różne metody pobierania danych z określonego adresu URL. Poniższa tabela zawiera podsumowanie różnych metod HTTP -

Sr.No. Metody i opis HTTP
1

GET

Wysyła dane w niezaszyfrowanej formie na serwer. Najpopularniejsza metoda.

2

HEAD

To samo co GET, ale bez treści odpowiedzi

3

POST

Służy do wysyłania danych formularza HTML na serwer. Dane otrzymane metodą POST nie są buforowane przez serwer.

4

PUT

Zastępuje wszystkie bieżące reprezentacje zasobu docelowego przesłaną treścią.

5

DELETE

Usuwa wszystkie bieżące reprezentacje zasobu docelowego podane przez adres URL

Tworzenie formularza HTML

Stwórzmy formularz HTML i wyślij dane formularza na adres URL. Zapisz następujący skrypt jako 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>

Dane wpisane w formularzu należy przesłać do ‘/login’ URL. Teraz utwórz funkcję kontroleraloginpage() i ujawnij mu powyższą stronę html.

@expose("hello.templates.login")
   def loginpage(self):
      return {}

Aby otrzymać dane formularza, podaj a login()kontroler, który ma atrybuty formularza jako parametry. Tutaj‘nm’ to nazwa pola wprowadzania tekstu w formularzu logowania, to samo jest używane jako parametr funkcji login ().

@expose("hello.templates.sample")
   def login(self, nm):
      name = nm
      return {'person':name}

Jak widać, dane otrzymane z formularza logowania są przesyłane do szablonu sample.html (używanego wcześniej). Jest analizowany przez plikGenshi template engine wygenerować następujący wynik -

Metoda POST

Gdy formularz HTML używa metody POST do wysyłania danych do adresu URL w atrybucie akcji, dane formularza nie są ujawniane w adresie URL. Zakodowane dane są odbierane w formaciedictargument przez funkcję kontrolera. **kw Argument poniżej to obiekt słownika przechowujący dane.

Formularz HTML zawiera dwa wejściowe pola tekstowe.

<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>

Plik marks() Administrator otrzymuje dane formularza i przesyła je do sample.htmlszablon. Kod dlaroot.py wygląda następująco -

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

Na koniec szablon sample.html wygląda następująco -

<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>

Uruchom serwer (jeśli jeszcze nie działa)

Gearbox server –reload –debug

Wchodzić http://localhost::8080/marksform w wyszukiwarce

Plik sample.html wyrenderuje następujące wyjście -

Genshi to język szablonów oparty na XML. To jest podobne doKid, który był kiedyś silnikiem szablonów dla wcześniejszych wersji TurboGears. Genshi i Kid są inspirowane innymi znanymi językami szablonów, takimi jakHSLT, TAL i PHP.

Szablon Genshi składa się z dyrektyw przetwarzania. Te dyrektywy są elementami i atrybutami w szablonie. Dyrektywy Genshi są zdefiniowane w przestrzeni nazwhttp://genshi.edgewall.org/. Dlatego ta przestrzeń nazw musi być zadeklarowana w głównym elemencie szablonu.

<html xmlns = "http://www.w3.org/1999/xhtml"
   xmlns:py = "http://genshi.edgewall.org/"
   lang = "en">
...
</html>

Powyższa deklaracja oznacza, że ​​domyślna przestrzeń nazw jest ustawiona na XHTML, a dyrektywy Genshi mają przedrostek „py”.

Dyrektywy Genshi

W Genshi zdefiniowano szereg dyrektyw. Poniższa lista wylicza dyrektywy Genshi -

  • py:if
  • py:choose
  • py:for
  • py:def
  • py:match
  • py:with
  • py:replace
  • py:content
  • py:attrs
  • py:strip

Sekcje warunkowe

Genshi dostarcza dwie dyrektywy warunkowego renderowania treści - py: if i py: choose.

py: jeśli

Zawartość elementu tej dyrektywy będzie renderowana tylko wtedy, gdy wyrażenie w if clausezwraca wartość true. Zakładając, że dane w kontekście szablonu to{‘foo’:True, ‘bar’:’Hello’}, następująca dyrektywa -

<div>
   <b py:if = "foo">${bar}</b>
</div>

spowoduje

Hello

Te dane wyjściowe nie byłyby jednak renderowane, gdyby ‘foo’ is set to False.

Ta dyrektywa może być również używana jako element. W tym przypadku<py:if> musi zostać zamknięty przez odpowiednie </py:if>

<div>
   <py:if test = "foo">
      <b>${bar}</b>
   </py:if>
</div>

py: wybierz

Zaawansowane przetwarzanie warunkowe jest możliwe dzięki wykorzystaniu py:choose w połączeniu z py:when i py:otherwisedyrektyw. Ta funkcja jest podobna doswitch – case skonstruuj w C/C++.

Wyrażenie w py:choose Dyrektywa jest sprawdzana z różnymi wartościami oznaczonymi py:whenzostaną renderowane alternatywy i odpowiadające im treści. Domyślną alternatywę można dostarczyć w postacipy:otherwise dyrektywa.

<div py:choose = "foo”>
   <span py:when = "0">0</span>
   <span py:when = "1">1</span>
   <span py:otherwise = "">2</span>
</div>

Poniższy przykład ilustruje użycie py:choose i py:whendyrektyw. Formularz HTML wysyła dane do / zaznacza adres URL. Plikmarks() funkcja przekierowuje znaki i wyniki w postaci obiektu słownika do total.htmlszablon. Warunkowe wyświetlanieresult Pass/Fail osiąga się za pomocą py:choose i py:when dyrektyw.

Skrypt HTML do wprowadzania znaków (marks.html) wygląda następująco -

<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>

Pełny kod root.pynastępująco. Plikmarks() kontroler wysyła oceny i wyniki do total.html szablon -

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

Plik total.html w folderze szablonów otrzymuje dane ze słownika i warunkowo analizuje je w danych wyjściowych html w następujący sposób -

<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>

Uruchom serwer (jeśli jeszcze nie działa)

Gearbox server –reload –debug

Wchodzić http://localhost::8080/marksform w przeglądarce -

Plik total.html wyrenderuje następujące wyjście -

py: dla

Element w dyrektywie py: for jest powtarzany dla każdego elementu w iterowalnym obiekcie, zwykle w obiekcie Python List. Gdybyitems = [1,2,3] jest obecny w kontekście szablonu, można go iterować, wykonując następujące polecenie py: dla dyrektywy -

<ul>
   <li py:for = "item in items">${item}</li>
</ul>

Zostanie wyrenderowany następujący wynik -

1
2
3

Poniższy przykład pokazuje dane formularza HTML renderowane w szablonie total.html przy użyciu dyrektywy py: for, które mogą być również użyte w następujący sposób -

<py:for each = "item in items">
   <li>${item}</li>
</py:for>

Skrypt formularza HTML

<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>

Plik loop() kontroler odczytuje dane z formularza i przesyła je do total.template w postaci obiektu listy.

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})

Szablon temp.html używa pętli py: for do renderowania zawartości obiektu dict w postaci tabeli.

<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>

Uruchom serwer (jeśli jeszcze nie działa)

gearbox server –reload –debug

Wchodzić http://localhost::8080/marksform w przeglądarce.

Poniższe dane wyjściowe zostaną wyświetlone w przeglądarce po przesłaniu powyższego formularza.

py: pok

Ta dyrektywa służy do tworzenia makra. Makro to fragment kodu szablonu wielokrotnego użytku. Podobnie jak funkcja Pythona ma nazwę i opcjonalnie może mieć parametry. Wyjście tego makra można wstawić w dowolnym miejscu szablonu.

Dyrektywa py: def ma następującą składnię -

<p py:def = "greeting(name)">
   Hello, ${name}!
</p>

To makro może być renderowane z wartością zmiennej do parametru „nazwa”.

${greeting('world')} ${greeting('everybody)}

Tej dyrektywy można również używać z inną wersją składni w następujący sposób -

<py:def function = "greeting(name)">
   <p>Hello, ${name}! </p>
</py:def>

W poniższym przykładzie macro() kontroler w root.py wysyła dict obiekt z dwoma kluczami nazwa1 i nazwa2 do szablonu 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'}

Ten szablon macro.html zawiera definicję makra o nazwie powitanie. Służy do generowania powitania dla danych odebranych z kontrolera.

<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>

Uruchom serwer za pomocą gearboxa

gearbox serve –reload –debug

Wywołaj kontroler makra (), wprowadzając następujący adres URL w przeglądarce -

http://localhost:8080/macro

Następujące dane wyjściowe zostaną wyrenderowane w przeglądarce -

py: z

Ta dyrektywa umożliwia przypisywanie wyrażeń do zmiennych lokalnych. Te zmienne lokalne sprawiają, że wyrażenie wewnątrz jest mniej szczegółowe i wydajniejsze.

Zakładając, że x = 50 jest dane kontekstowe dla szablonu, poniżej będzie py: z dyrektywą -

<div>
   <span py:with = "y = 50; z = x+y">$x $y $z</span>
</div>

Spowoduje to następujący wynik -

50 50 100

Dostępna jest również wersja alternatywna dla py: with z dyrektywą -

<div>
   <py:with = "y = 50; z = x+y">$x $y $z</py:with>
</div>

W poniższym przykładzie kontroler macro () zwraca obiekt dict z kluczami nazwy, phy i matematyki.

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}

Szablon macro.html dodaje wartości kluczy phy i matematycznych za pomocą dyrektywy py: with.

<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>

Przeglądarka wyrenderuje następujące dane wyjściowe w odpowiedzi na adres URL http://localhost:8080/macro

Dyrektywy dotyczące manipulacji strukturą

Plik py:attrs Dyrektywa dodaje, modyfikuje lub usuwa atrybuty z elementu.

<ul>
   <li py:attrs = "foo">Bar</li>
</ul>

Gdyby foo = {‘class’:’collapse’} jest obecny w kontekście szablonu, który zostanie wyrenderowany przez powyższy fragment.

<ul>
   <li class = "collapse">Bar</li>
</ul>

Plik py:content dyrektywa zastępuje zagnieżdżoną zawartość wynikiem oceny wyrażenia -

<ul>
   <li py:content = "bar">Hello</li>
</ul>

Biorąc pod uwagę słupek = „Bye” w danych kontekstowych, dałoby to

<ul>
   <li>Bye</li>
</ul>

Plik py:replace Dyrektywa zastępuje sam element wynikiem oceny wyrażenia -

<div>
   <span py:replace = "bar">Hello</span>
</div>

Biorąc pod uwagę słupek = „Do widzenia” w danych kontekstowych, wygeneruje

<div>
   Bye
</div>

Zawartość innego dokumentu XML (zwłaszcza dokumentu HTML) można dołączyć za pomocą znaczników włączenia w bieżącym dokumencie. Aby umożliwić takie włączenie, przestrzeń nazw XInclude musi być zadeklarowana w elemencie głównym dokumentu HTML.

<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:xi = "http://www.w3.org/2001/XInclude >

Powyższa deklaracja określa, że ​​dyrektywa include zawiera ‘xi’prefiks. Aby dodać zawartość innej strony html do bieżącego dokumentu, użyj dyrektywy xi: include w następujący sposób -

<xi:include href = "somepage.html" />

W poniższym przykładzie root.py zawiera kontroler include (), który ujawnia include.html.

from hello.lib.base import BaseController
from tg import expose, request

class RootController(BaseController):
   @expose('hello.templates.include')
   def include(self):
      return {}

Nagłówek i stopka HTML

W pliku include.html zadeklarowano przestrzeń nazw include i dodano zawartość nagłówków.html i stopka.html. Oto skrypt HTML szablonów \ 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>

Oto kod szablonów \ header.html -

<html>
   <head>
      <title>TurboGears Templating Example</title>
   </head>
	
   <body>
      <h1>This is page Header</h1>
   </body>
</html>

Poniżej znajduje się plik templates \ footer.html

<html>
   <head>
      <title>TurboGears Templating Example</title>
   </head>
	
   <body>
      <h3>This is page footer</h3>
   </body>
</html>

Rozpocznij rozwój za pomocą skrzyni biegów i wejdź http://localhost:8080/includew przeglądarce. Wyrenderowane dane wyjściowe będą wyglądać tak, jak pokazano poniżej -

W ten sposób można uzyskać modułową konstrukcję widoków. Jeśli zasób wymieniony w dyrektywie xi: include nie jest dostępny, zostanie zgłoszony błąd. W takim przypadku alternatywny zasób może zostać załadowany przy użyciu xi: fallback.

<xi:include href = “main.html”>
   <xi:fallback href = ”default.html”/>
</xi.include>

Włączanie treści może być dynamiczne jako atrybut href, który może zawierać wyrażenia.

Dodaj następujący kontroler w root.py.

@expose('hello.templates.ref-include')
   def refinclude(self):
      return {'pages':['heading','main','footer']}

Zapisz poniższy kod jako ref-include.html w folderze szablonów.

<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>

Przed uruchomieniem serwera upewnij się, że folder szablonów ma pliki header.html, main.html i footer.html. Wchodzićhttp://localhost:8082/refinclude w przeglądarce, aby uzyskać następujące dane wyjściowe

Plik @expose()dekorator domyślnie renderuje zawartość html. Można to jednak ustawić najson content type. TurboGears obsługuje renderowanie json przeztg.jsonify.JSONEncoder (**kwargs)klasa. Aby renderować dane json, po prostu przekaż json jako typ zawartości, aby udostępnić dekorator.

@expose('json')
def jsondata(self, **kwargs):
   return dict(hello = 'World')

Jeśli adres URL „/ jsondata” zostanie wprowadzony w przeglądarce, odpowie, wyświetlając -

{"hello": "World"}

jsonp Rendering

jsonp oznacza json z dopełnieniem. Działa podobnie do danych wyjściowych json, z wyjątkiem faktu, że zapewnia odpowiedź aplikacji / javascript z wywołaniem funkcji javascript, podając wszystkie wartości zwrócone przez kontroler jako argumenty funkcji.

Aby włączyć renderowanie jsonp, musisz najpierw dołączyć go do listy wymaganych silników w aplikacji - config/app_cfg.py -

base_config.renderers.append('jsonp')

Napisz swój dekorator ekspozycji w następujący sposób -

@expose('json')
@expose('jsonp')
def jsonpdata (self, **kwargs): 
   return dict(hello = 'World')

Podczas uzyskiwania dostępu do / jsonpdata? Callback = callme, powinieneś zobaczyć -

callme({"hello": "World"});

Czasami aplikacja internetowa może wymagać struktury adresu URL, która ma więcej niż jeden poziom. TurboGears może przeszukiwać hierarchię obiektów, aby znaleźć odpowiednią metodę, która może obsłużyć Twoje żądanie.

Projekt „Szybki start” ze skrzynią biegów ma klasę BaseController w folderze lib projektu. Jest dostępny jako „Hello / hello / lib / base.py”. Służy jako klasa bazowa dla wszystkich kontrolerów podrzędnych. Aby dodać podrzędny poziom adresu URL w aplikacji, zaprojektuj podklasę o nazwie BlogController pochodzącą z BaseController.

Ten BlogController ma dwie funkcje kontrolera, index () i post (). Obydwa mają na celu udostępnienie po jednym szablonie, blog.html i post.html.

Note - Te szablony są umieszczane w podfolderze - templates / 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}

Teraz zadeklaruj obiekt tej klasy w klasie RootController (w root.py) w następujący sposób -

class RootController(BaseController):
   blog = BlogController()

Inne funkcje kontrolera dla adresów URL najwyższego poziomu będą dostępne w tej klasie, jak wcześniej.

Kiedy URL http://localhost:8080/blog/zostanie wpisana, zostanie odwzorowana na funkcję kontrolera index () w klasie BlogController. Podobnie,http://localhost:8080/blog/post wywoła funkcję post ().

Kod dla blog.html i post.html jest następujący -

Blog.html

<html>
   <body>
      <h2>My Blog</h2>
   </body>
</html>

post.html

<html>
   <body>
      <h2>My new post dated $date</h2>
   </body>
</html>

Kiedy URL http://localhost:8080/blog/ zostanie wpisane, wygeneruje następujący wynik -

Kiedy URL http://localhost:8080/blog/post zostanie wpisane, wygeneruje następujący wynik -

Jednym z najważniejszych aspektów każdej aplikacji internetowej jest przedstawienie użytkownikowi interfejsu użytkownika. HTML udostępnia tag <form>, który jest używany do projektowania interfejsu. Elementy formularza, takie jak wprowadzanie tekstu, radio, wybór itp., Mogą być odpowiednio używane. Dane wprowadzone przez użytkownika są przesyłane w postaci komunikatu żądania HTTP do skryptu po stronie serwera metodą GET lub POST.

Skrypt po stronie serwera musi odtworzyć elementy formularza z danych żądania http. W tym celu elementy formularza muszą zostać zdefiniowane dwukrotnie - raz w HTML i ponownie w skrypcie po stronie serwera.

Inną wadą korzystania z formularza HTML jest to, że jest trudne (jeśli nie niemożliwe) dynamiczne renderowanie elementów formularza. Sam HTML nie zapewnia możliwości sprawdzenia poprawności danych wejściowych użytkownika.

ToscaWidgets2

TurboGears opiera się na ToscaWidgets2, elastycznej bibliotece do renderowania formularzy i weryfikacji. Korzystając z ToscaWidgets, możemy zdefiniować pola formularza w naszym skrypcie Python i renderować je za pomocą szablonu HTML. Możliwe jest również zastosowanie walidacji do pola tw2.

Biblioteka ToscaWidgets to zbiór wielu modułów. Poniżej wymieniono niektóre ważne moduły -

  • tw2.core- Zapewnia podstawową funkcjonalność. Widżety w tym module nie mają być dostępne dla użytkownika końcowego.

  • tw2.forms- To jest podstawowa biblioteka formularzy. Zawiera widżety dla pól, zestawów pól i formularzy.

  • tw2.dynforms - Zawiera funkcjonalność formularzy dynamicznych.

  • tw2.sqla - To jest interfejs dla bazy danych SQLAlchemy.

tw2.forms

Zawiera klasę Form, która działa jako baza dla niestandardowych formularzy. Istnieje klasa TableForm, która jest przydatna do renderowania pól w tabeli z dwiema kolumnami. ListForm przedstawia swoje pola na nieuporządkowanej liście.

Sr.No. Pola i opis
1

TextField

Jednowierszowe pole wprowadzania tekstu

2

TextArea

Wielowierszowe pole wprowadzania tekstu

3

CheckBox

Prezentuje prostokątne pudełko z etykietą, które można zaznaczyć

4

CheckBoxList

Pola wyboru grupy pf z możliwością wielokrotnego wyboru

5

RadioButton

Przycisk przełączania do zaznaczania / odznaczania

6

RadioButtonList

Grupa wzajemnie wykluczających się przycisków radiowych

7

PasswordField

Podobny do Textfield, ale klucze wprowadzania nie są widoczne

8

CalendarDatePicker

Pozwala użytkownikowi wybrać datę

9

SubmitButton

Przycisk do przesłania formularza

10

ImageButton

Klikalny przycisk z obrazem na górze

11

SingleSelectField

Umożliwia wybór pojedynczego elementu z listy

12

MultipleSelectField

Umożliwia wybór wielu pozycji z listy

13

FileField

Pole do przesłania pliku

14

EmailField

Pole do wprowadzania adresu e-mail

15

URLField

Pole do wpisania adresu URL

16

NumberField

Liczba spinbox

17

RangeField

Suwak liczbowy

W poniższym przykładzie utworzono formularz korzystający z niektórych z tych widżetów. Chociaż większość tych widżetów jest zdefiniowana w tw2.forms, CalendarDateField jest zdefiniowana w module tw2.Dynforms. Stąd oba te moduły wraz z tw2.core są importowane na początku -

import tw2.core as twc
import tw2.forms as twf
import tw2.dynforms as twd

Formularz ToscaWidgets jest klasą pochodną tw2.forms.formklasa bazowa. Wymagane widgety są umieszczane w obiekcie układu. W tym przykładzieTableLayoutjest używany. Widżety są renderowane w tabeli z dwiema kolumnami. Pierwsza kolumna zawiera podpis, a druga kolumna - pole wejściowe lub pole wyboru.

Obiekt TextField jest tworzony przy użyciu następującego konstruktora -

twf.TextField(size, value = None)

Jeśli nie wspomniano, obiekt TextField przyjmuje rozmiar domyślny i jest początkowo pusty. Deklarując obiekt TextArea, można wspomnieć o liczbie wierszy i kolumn.

twf.TextArea("",rows = 5, cols = 30)

Obiekt NumberField jest obiektem TextField, który akceptuje tylko cyfry. Strzałki w górę iw dół są generowane na prawej krawędzi, aby zwiększyć lub zmniejszyć liczbę w środku. Wartość początkową można również określić jako argument w konstruktorze.

twf.NumberField(value)

Po prawej stronie pola CalendarDatePicker jest wyświetlany przycisk kalendarza. Po naciśnięciu pojawia się selektor daty. Użytkownik może ręcznie wpisać datę w polu lub wybrać z selektora daty.

twd.CalendarDatePicker()

EmailField przedstawia TextField, ale tekst w nim musi być w formacie e-mail.

EmailID = twf.EmailField()

Poniższy formularz ma również RadioButtonList. Konstruktor tej klasy zawiera obiekt List jako wartość parametru options. Zostanie wyświetlony przycisk radiowy dla każdej opcji. Wybór domyślny jest określany za pomocą parametru wartości.

twf.RadioButtonList(options = ["option1","option2"],value = option1)

CheckBoxList renderuje pola wyboru dla każdej opcji na liście.

twf.CheckBoxList(options = [option1, option2, option3])

Lista rozwijana nosi nazwę SingleSelectfield w tej bibliotece ToscaWidgets. Elementy w obiekcie List odpowiadające parametrom options z listy rozwijanej. Widoczny napis jest ustawiany jako wartość parametru prompt_text.

twf.SingleSelectField(prompt_text = 'text', options=['item1', 'item2', 'item3'])

Formularz domyślnie wyświetla przycisk Prześlij z podpisem „Zapisz”. Aby wyświetlić inny podpis, utwórz obiekt SubmitButton i określ go jako parametr wartości.

twf.SubmitButton(value = 'Submit')

Formularz jest przesyłany do adresu URL, który jest określony jako wartość parametru akcji formularza. Domyślnie dane formularza są przesyłane metodą http POST.

action = 'URL'

W poniższym kodzie formularz o nazwie AdmissionForm został zaprojektowany przy użyciu wyżej wyjaśnionych widżetów. Dodaj ten kod w root.py przed klasą RootController.

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')

Teraz zapisz poniższy kod jako twform.html w katalogu szablonów -

<!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>

W klasie RootController (w root.py) dodaj następującą funkcję kontrolera -

@expose('hello.templates.twform')
def twform(self, *args, **kw):
   return dict(page = 'twform', form = MovieForm)

W klasie AdmissionForm mamy stipulated/save_formjako adres URL akcji. Dlatego dodajsave_form() funkcja w RootController.

@expose()
def save_movie(self, **kw):
   return str(kw)

Upewnij się, że serwer jest uruchomiony (przy użyciu usługi Gearbox). Wchodzićhttp://localhost:8080/twform w przeglądarce.

Naciśnięcie przycisku przesyłania spowoduje wysłanie tych danych do save_form() URL, który wyświetli dane formularza w postaci obiektu słownikowego.

{
   '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'
}

Dobra biblioteka widżetów Formularzy powinna mieć funkcję sprawdzania poprawności danych wejściowych. Na przykład użytkownik powinien zostać zmuszony do wprowadzenia danych w obowiązkowym polu lub sprawdzenia, czy pole wiadomości e-mail zawiera prawidłowy adres e-mail, bez uciekania się do innych środków programistycznych (takich jak funkcja JavaScript) w celu weryfikacji.

Wczesne wersje ToscaWidgets Forms Library korzystały z modułu FormEncode do obsługi walidacji. ToscaWidgets2 ma teraz wbudowaną obsługę walidacji dostępną w module tw2.core. Jednak nadal można używać technik walidacji FormEncode.

Aby poddać formularz ToscaWidgets do walidacji, używany jest dekorator @validate.

@validate(form, error_handler, validators)
  • Plik ’form’ jest obiektem formularza ToscaWidgets do sprawdzenia.

  • Plik ‘error-handler’ jest metodą kontrolera używaną do obsługi błędów formularza.

  • Plik ‘validators’ są obiektami słownika zawierającymi walidatory FormEncode.

Typy walidatorów

Moduł tw2.core zawiera klasę walidatora, z której dziedziczone są inne walidatory. Możliwe jest również zaprojektowanie własnego walidatora na jego podstawie. Poniżej opisano niektóre z ważnych walidatorów -

LengthValidator- Sprawdź, czy wartość ma określoną długość. Minimalne i maksymalne limity są definiowane za pomocą parametrów min i max. Niestandardowe komunikaty o długości poniżej i powyżej min i max można określić jako parametr tooshort i toolong.

tw2.core.LengthValidator(min = minval, max = maxval, 
   msgs = { 'tooshort': (‘message for short length’), 
   'toolong': (‘message for long length)})

RangeValidator- Zwykle używany razem z RangeField. Jest to przydatne do sprawdzania wartości pola liczbowego w granicach minimalnych i maksymalnych. Można dostosować komunikaty dotyczące parametrów zbyt krótkich i długich.

tw2.core.RangeValidator(min = minval, max = maxval, 
   msgs = { 'tooshort': (‘message for short length’), 
   'toolong': (‘message for long length)})

IntValidator- Ta klasa pochodzi z RangeValidator. Jest to zwykle używane do sprawdzenia, czy dane wejściowe w zwykłym polu tekstowym zawierają dane całkowite. Można ustawić minimalne i maksymalne limity, a także komunikaty o błędach. Dodatkowo komunikat o błędzie dla danych wejściowych innych niż całkowite można określić jako parametr „notint”.

tw2.core.IntValidator(msgs = {‘notint’:’Must be Integer’})

OneOfValidator - Ten walidator zmusza użytkownika do wybrania wartości tylko z dostępnych opcji na liście.

tw2.core.OneOfValidator(values = [option1, option2,..], 
   msgs = {‘notinlist’:’Not in List’}}

DateValidator- Bardzo przydatne, aby upewnić się, że dane wprowadzone przez użytkownika są poprawne. Format daty (domyślnie YMD) i komunikat o błędzie można dostosować. Można również określić minimalne i maksymalne limity dat. DateTimeValidator jest również dostępny do weryfikacji obiektu klasy DateTime.

tw2.core.DateValidator(msgs = {format = ’%Y-%m-%d’, 
   'baddatetime': ('baddate', ('Must follow date format $format_str'))}

EmailValidator- Weryfikuje dane wejściowe użytkownika na podstawie prawidłowego adresu e-mail. Ta klasa jest dziedziczona z bardziej ogólnego RegexValidator.

tw2.core.EmailValidator(msgs = {'badregex': ('bademail', 
   ('Must be a valid email address')) }

UrlValidator- Ta klasa jest również dziedziczona po RegexValidator. Sprawdza poprawność danych wejściowych użytkownika pod kątem prawidłowego adresu URL.

tw2.core.UrlValidator(msgs = {'badregex': ('badurl', ('Must be a valid URL’)) }

MatchValidator- Potwierdza, czy wartość jednego pola jest zgodna z innym. Jest to szczególnie przydatne, gdy użytkownik musi wybrać i potwierdzić pole hasła. Typowe użycie MatchValidator pokazano poniżej -

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()

Możliwe jest również skonstruowanie walidatora złożonego, w którym walidacja ma się powieść, jeśli którykolwiek z testów przejdzie pomyślnie. W innych przypadkach możesz chcieć, aby walidacja zakończyła się powodzeniem, tylko jeśli dane wejściowe przejdą wszystkie testy. W tym celu tw2.core udostępnia walidatory Any i All, które są podklasami rozszerzalnego CompoundValidator.

TurboGears zapewnia bardzo wygodny system przesyłania wiadomości do powiadamiania użytkownika w sposób nieuciążliwy. Klasa TGFlash w module tg zapewnia obsługę flashowania wiadomości, które są przechowywane w zwykłym pliku cookie. Ta klasa obsługuje pobieranie wiadomości flash po stronie serwera i klienta za pomocą JavaScript.

Plik render()Metoda klasy TGFlash, gdy jest używana z samego Pythona, może być wywołana z szablonu w celu renderowania wiadomości flash. Jeśli jest używany w JavaScript, udostępnia obiekt WebFlash. To ujawniapayload() i render() metody pobierania aktualnej wiadomości flash i renderowania jej z JavaScript.

Kiedy projekt TurboGears jest tworzony przy użyciu „szybkiego startu”, zawiera on szablon Master.html. Zawiera definicję zmiennej tego obiektu Flash. Treść tej wiadomości flash otrzymanej od kontrolera zastępuje zaznaczony symbol zastępczy w tym szablonie.

<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
   <div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>

Plik tg.flash_obj to obiekt WebFlash, który jest dostępny w każdym renderowanym szablonie poprzez dołączenie master.htmlszablon. Ten obiekt umożliwia pobranie aktualnej wiadomości flash i wyświetlenie jej.

Wiadomości Flash są przechowywane w pliku cookie (którego nazwa domyślnie to webflash) przy użyciu tg.flash()metoda. Następnie przekazywane są do niego parametry komunikatu i statusu.

tg.flash('Message', 'status')

Jeśli metoda o nazwie flash wykonuje przekierowanie, to flash będzie widoczny na przekierowanej stronie. Jeśli metoda bezpośrednio odsłania szablon, to flash będzie widoczny wewnątrz samego szablonu.

Wygląd wiadomości flash można dostosować, stosując style CSS do kodu stanu. Projekt „Szybki start” zawiera kody błędów, ostrzeżeń, informacji i stanu OK dostosowane przez arkusz stylów public / css / style.css. Można również dodać więcej kodów stanu ze stylami.

#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;
}

Ten zewnętrzny arkusz stylów musi być zawarty w szablonie -

<link rel = "stylesheet" type = "text/css" media = "screen" 
   href = "${tg.url('/css/style.css')}" />

Konfigurację obsługi dowolnej wiadomości Flash można uzyskać, ustawiając parametry metody configure () obiektu TGFlash lub w pliku app_cfg.py (w folderze config). Konfigurowalne parametry to -

Sr.No. Parametry i opis
1

flash.cookie_name

Nazwa pliku cookie używanego do przechowywania wiadomości flash. Domyślnie jestwebflash.

2

flash.default_status

Domyślny status wiadomości, jeśli nie został określony (domyślnie ok)

3

flash.template

Używany jako flash template po renderowaniu.

4

flash.allow_html

Obraca się on/off escaping in flash messages, domyślnie HTML nie jest dozwolony.

5

flash.js_call

Kod JavaScript, który zostanie uruchomiony podczas wyświetlania flasha z JavaScript. Domyślnie jestwebflash.render()

6

flash.js_template

string.Template wystąpienie używane do zastąpienia pełnej obsługi JavaScript dla wiadomości flash.

  • pop_payload() - funkcja fetches current flash message, statusi powiązane informacje. Otrzymanie wiadomości flash spowoduje usunięcie pliku cookie.

  • render(container_id, use_js=True) - Renderuj wiadomość flash w szablonie lub zapewnij obsługę JavaScript dla nich.

  • container_id to DIV, w którym będą wyświetlane komunikaty, podczas gdy use_js przełącza między renderowaniem flasha jako HTML a używaniem JavaScript.

  • status - Uzyskaj tylko aktualny stan flashowania, uzyskanie statusu flasha spowoduje usunięcie pliku cookie.

  • message - Pobierz tylko aktualną wiadomość flash, otrzymanie wiadomości flash spowoduje usunięcie pliku cookie.

Jak zrobić prostą wiadomość Flash?

W poniższym przykładzie metoda flash () znajduje się w klasie głównego kontrolera. Wywołuje komunikat flash (), który jest renderowany do udostępnionego szablonu flash.html

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 {}

Kod do tworzenia flash.html w folderze szablonów wygląda następująco

<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>

Uruchom serwer i wejdź http://localhost:8080/flash?user=MVL w przeglądarce

Zmień adres URL na http://localhost:8080/flash i zobacz wiadomość flash w innym formacie, zgodnie z definicją w style.css

Często wymagane jest przechowywanie prostych danych przeglądania dołączonych do przeglądarki użytkownika. Sesje to najczęściej stosowana technika. Sesja reprezentuje dane, które nie muszą być przechowywane w bardziej trwałej formie, takiej jak plik na dysku lub baza danych.

Jednak dane sesji w TurboGears mogą być obsługiwane przez system plików, bazę danych lub zaszyfrowane wartości plików cookie. Niewielka ilość danych sesji jest zazwyczaj przechowywana w plikach cookie, ale w przypadku większej ilości danych sesji używana jest pamięć MemCache.

MemCache to demon na poziomie systemu. Zapewnia szybki dostęp do danych w pamięci podręcznej i jest niezwykle skalowalny. Jednak jest przeznaczony do użytku tylko na bezpiecznych serwerach i dlatego musi być utrzymywany i zabezpieczany przez sysadmin.

Zlewka w zarządzaniu sesjami

TurboGears używa Beaker do zarządzania sesjami. Projekt uruchamiany szybko przez gearbox jest domyślnie skonfigurowany do przechowywania danych sesji za pomocą zaszyfrowanych plików cookie.

Za każdym razem, gdy klient łączy się, oprogramowanie pośredniczące sesji (Beaker) sprawdzi plik cookie przy użyciu nazwy pliku cookie, która została zdefiniowana w pliku konfiguracyjnym. Jeśli plik cookie nie zostanie znaleziony, zostanie ustawiony w przeglądarce. Podczas wszystkich kolejnych wizyt oprogramowanie pośredniczące znajdzie plik cookie i wykorzysta go.

Aby umożliwić zarządzanie sesjami, klasę sesji należy włączyć do projektu, wykonując instrukcję importu -

from tg import session

Aby zapisać dane w zmiennej sesji -

session[‘key’] = value
session.save()

Aby pobrać zmienną sesji -

return session[‘key’]

Pamiętaj, że musisz jawnie zapisać sesję, aby klucze były przechowywane w tej sesji.

Plik delete() metoda obiektu sesji usunie wszystkie sesje użytkownika -

session.delete()

Chociaż nie jest zwyczajowo usuwać wszystkie sesje użytkowników w danym środowisku produkcyjnym, zazwyczaj będzie to robione w celu wyczyszczenia po wykonaniu testów użyteczności lub funkcjonalności.

Poniżej podano prosty przykład pokazujący sesje. Klasa RootController ma rozszerzeniesetsession() metoda, która ustawia zmienną sesji.

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>"

Wchodzić http://localhost:8080/setsession

Link w przeglądarce prowadzi do http://localhost:8080/getsession który pobiera i wyświetla zmienną sesji -

Aby zwiększyć wydajność aplikacji internetowej, zwłaszcza jeśli jest ona zaangażowana w długotrwałe operacje, stosuje się techniki buforowania. TurboGears zapewnia dwa rodzaje technik buforowania -

Whole-page Caching

Działa na poziomie protokołu HTTP, aby uniknąć całych żądań do serwera, ponieważ przeglądarka użytkownika lub pośredni serwer proxy (taki jak Squid) przechwytują żądanie i zwracają buforowaną kopię pliku.

Application-level Caching

Działa to na serwerze aplikacji w celu buforowania obliczonych wartości, często wyników złożonych zapytań do bazy danych, dzięki czemu przyszłe żądania mogą uniknąć konieczności ponownego obliczania wartości. W przypadku aplikacji internetowych buforowanie na poziomie aplikacji zapewnia elastyczny sposób buforowania wyników złożonych zapytań, dzięki czemu całkowite obciążenie danej metody kontrolera można zredukować do kilku zapytań specyficznych dla użytkownika lub przypadku oraz narzutu renderowania szablonu .

Buforowanie na poziomie aplikacji

Jak wspomniano wcześniej, projekt TurboGears „Szybki start” jest skonfigurowany tak, aby umożliwić pakiet Beaker do obsługi buforowania. Beaker obsługuje następujące back-endy używane do przechowywania pamięci podręcznej -

  • memory- Używany do przechowywania na proces. Jest niezwykle szybki.

  • filesystem - przechowywanie na proces, jak również wieloprocesowe.

  • DBM database - na proces, wiele procesów, dość szybko.

  • SQLAlchemy database- pamięć masowa na serwer bazy danych. Wolniej w porównaniu do podanych powyżej opcji.

  • Memcached - wieloserwerowa pamięć podręczna oparta na pamięci.

Buforowanie kontrolera

W celu szybkiego buforowania kontrolera plik cached()dekorator jest dostępny. Cała treść kontrolera jest buforowana w zależności od różnych parametrów żądania. Definicjatg.decorators.cached() dekorator jest następujący

tg.decorators.cached(key, expire, type, 
   query-args, cache_headers, invalidate_on_startup, cache_response)

Opis parametrów jest następujący -

Sr.No. Parametry i opis
1

key

Określa parametry kontrolera używane do generowania klucza pamięci podręcznej.

2

expire

Czas w sekundach przed wygaśnięciem pamięci podręcznej, domyślnie „nigdy”.

3

Type

dbm, memory, file, memcached lub None.

4

cache_headers

Krotka nazw nagłówków wskazujących nagłówki odpowiedzi.

5

invalidate_on_startup

Jeśli prawda, pamięć podręczna jest unieważniana przy każdym uruchomieniu lub ponownym uruchomieniu aplikacji.

6

cache_response

odpowiedź powinna być buforowana lub nie, domyślnie True.

Poniżej znajduje się przykład buforowania kontrolera -

@cached(expire = 100, type = 'memory')
@expose()
def simple(self):
   return "This is a cached controller!"

Buforowanie na poziomie szablonów

Silnik szablonów Genshi pobiera szablon z pamięci podręcznej, jeśli jego zawartość nie uległa zmianie. Domyślny rozmiar tej pamięci podręcznej to 25. Domyślnie automatyczne ponowne ładowanie szablonów jest prawdziwe. Aby poprawić wydajność, w programie można wprowadzić następujące ustawieniaapp_cfg.py -

[app:main]
genshi.max_cache_size = 100
auto_reload_templates = false

Aby zapisać szablon w pamięci podręcznej, wystarczy zwrócić plik tg_cache opcja z kontrolera, który renderuje buforowany szablon.

Tg_cache to słownik, który akceptuje następujące klucze -

  • key - Klucz pamięci podręcznej. Default: Żaden.

  • expire - jak długo cache musi pozostać żywy. Default: nigdy nie wygasa

  • type - pamięć, dbm, memcached. Default: dbm.

Poniższy przykład ilustruje buforowanie szablonów -

@expose(hello.templates.user')
def user(self, username):
   return dict(user = username, tg_cache = dict(key = user, expire = 900))

Chociaż możliwe jest użycie SQL w aplikacji TurboGears do wykonywania operacji CRUD na dowolnej relacyjnej bazie danych, zaleca się użycie SQLAlchemy, zestaw narzędzi Python to potężne narzędzie do mapowania relacji obiektów, które zapewnia programistom aplikacji pełną moc i elastyczność SQL. Oprócz obsługi baz danych opartych na SQL za pośrednictwem SQLAlchemy, TurboGears obsługuje również bazę danych MongoDB przez Ming. W tej sekcji omówiona jest funkcjonalność SQLAlchemy.

Co to jest ORM (Object Relational Mapping)?

Większość platform języków programowania jest zorientowana obiektowo. Z drugiej strony dane na serwerach RDBMS są przechowywane w postaci tabel. Mapowanie relacji z obiektami to technika mapowania parametrów obiektu na podstawową strukturę tabeli RDBMS. Interfejs API ORM zapewnia metody wykonywania operacji CRUD bez konieczności pisania surowych instrukcji SQL.

Gdy projekt TurboGears jest tworzony za pomocą polecenia „quickstart” z zestawu narzędzi skrzyni biegów, obsługa SQLAlchemy jest domyślnie włączona przez następujące ustawienia konfiguracji -

config['use_sqlalchemy'] = True
config['sqlalchemy.url'] = 'sqlite:///devdata.db'

Projekt „quickstarted” tworzy również w nim pakiet modeli. Na przykład projekt „Hello” będzie miał Hello \ hello \ model. W tym pakiecie tworzone są następujące pliki -

  • __init__.py- Tutaj konfigurowany jest dostęp do bazy danych. Obiekty modelu aplikacji są importowane w tym module. Posiada również DBSession - globalnego menedżera sesji, a także DeclarativeBase, która jest klasą bazową dla wszystkich klas modeli.

  • auth.py- Tutaj definiowane są modele używane przez stos uwierzytelniania. Dodatkowe modele baz danych są przechowywane w tym pakiecie jako osobny moduł i dodawane w pliku __init__.py.

Dodajmy model ucznia, który utworzy tabelę studencką w naszym sqlite Baza danych.

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 = '')

Teraz dodaj ten model init_model() funkcja wewnątrz __init__.py.Ta funkcja zawiera już model autoryzacji. Dodaj nasz model studencki poniżej.

# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student

Jeśli chcesz, aby tabela została zainicjowana z pewnymi danymi w czasie ustawiania modeli, dodaj je w pliku bootstrap.py w pakiecie websetup. Dodaj następujące instrukcje wbootstrap() funkcjonować.

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()

Modele są inicjalizowane przez uruchomienie polecenia konfiguracji skrzyni biegów w aplikacji -

gearbox setup-app

Obiekt sesji SQLAlchemy zarządza wszystkimi operacjami trwałości obiektu ORM.

Następujące metody sesji wykonują operacje CRUD -

  • DBSession.add(model object) - wstawia rekord do zmapowanej tabeli.

  • DBSession.delete(model object) - usuwa rekord z tabeli.

  • DBSession.query(model).all() - pobiera wszystkie rekordy z tabeli (odpowiadające zapytaniu SELECT).

Możesz zastosować filtr do pobranego zestawu rekordów za pomocą atrybutu filtru. Na przykład, aby pobrać rekordy z city = 'Hyderabad' w tabeli studentów, użyj następującego stwierdzenia -

DBSession.query(model.student).filter_by(city = ’Hyderabad’).all()

Zobaczymy teraz, jak współdziałać z modelami za pośrednictwem adresów URL kontrolerów.

Najpierw zaprojektujmy formularz ToscaWidgets do wprowadzania danych ucznia

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')

W RootController (root.py aplikacji Hello) dodaj następujące mapowanie funkcji „/ 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)

Zapisz następujący kod HTML jako studentform.html w folderze szablonów -

<!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>

Wchodzić http://localhost:8080/addw przeglądarce po uruchomieniu serwera. W przeglądarce otworzy się następujący formularz informacji o uczniu -

Powyższy formularz przeznaczony jest do przesłania na adres ‘/save_record’URL. Stąd asave_record() funkcja musi zostać dodana w root.pyaby to ujawnić. Dane z formularza studenta są odbierane przez tę funkcję jako plikdict()obiekt. Służy do dodawania nowego rekordu w tabeli ucznia będącej podstawą modelu ucznia.

@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")

Należy pamiętać, że po pomyślnym dodaniu przeglądarka zostanie przekierowana na ‘/listrec’ URL. Ten adres URL jest udostępniany przez rozszerzenielistrec() function. Ta funkcja wybiera wszystkie rekordy w tabeli uczniów i wysyła je w postaci obiektu dyktu do szablonu studentlist.html. Tolistrec() funkcja jest następująca -

@expose ("hello.templates.studentlist")
def listrec(self):
   entries = DBSession.query(student).all()
   return dict(entries = entries)

Szablon studentlist.html wykonuje iterację przez obiekt słownika wpisów, używając dyrektywy py: for. Szablon studentlist.html jest następujący -

<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>

Teraz wróć do http://localhost:8080/addi wprowadź dane w formularzu. Kliknięcie przycisku przesyłania spowoduje przeniesienie przeglądarki do studentlist.html. Zostanie również wyświetlony komunikat „pomyślnie dodano nowy rekord”.

ToscaWidgets zawiera formant DataGrid, który zapewnia szybki sposób prezentacji danych w formie tabelarycznej. Obiekt DataGrid jest zadeklarowany w następujący sposób -

from tw2.forms import DataGrid
student_grid = DataGrid(fields = [('Name', 'name'),('City', 'city'),
   ('Address','address'), ('PINCODE', 'pincode')])

Teraz funkcja showgrid () pobiera wszystkie rekordy z tabeli uczniów i udostępnia dane w szablonie grid.html. Najpierw kod funkcji showgrid (), a następnie kod grid.html jest podany poniżej -

Pokaż siatkę()

@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>

Następujące dane tabelaryczne zostaną wyświetlone, gdy http://localhost:8080/showlist URL jest wpisany w przeglądarce -

TurboGears zapewnia wygodny dekorator o nazwie paginate () do dzielenia wydruku na stronach. Ten dekorator jest połączony z dekoratorem expose (). Dekorator @Paginate () przyjmuje jako argument obiekt słownikowy wyniku zapytania. Ponadto o liczbie rekordów na stronę decyduje wartość atrybutu items_per_page. Upewnij się, że importujesz funkcję paginate z tg.decorators do swojego kodu.

Przepisz funkcję listrec () w root.py w następujący sposób -

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)

Ustawiono trzy elementy na stronę.

W szablonie studentlist.html nawigację po stronach można włączyć poprzez dodanie tmpl_context.paginators.entries.pager () poniżej dyrektywy py: for. Kod tego szablonu powinien wyglądać jak poniżej -

<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>

Wchodzić http://localhost:8080/listrecw przeglądarce. Zostanie wyświetlona pierwsza strona rekordów w tabeli. U góry tej tabeli widoczne są również linki do numerów stron.

Jak dodać obsługę paginacji do Datagrid

Możliwe jest również dodanie obsługi paginacji do datagrid. W poniższym przykładzie datagrid podzielony na strony jest przeznaczony do wyświetlania przycisku akcji. W celu aktywacji przycisku akcji obiekt datagrid jest konstruowany z następującym kodem -

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)))) ])

Tutaj przycisk akcji jest powiązany z parametrem nazwy każdego wiersza w siatce danych.

Przepisz showgrid() działają w następujący sposób -

@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)

Przeglądarka wyświetla dane z podziałem na strony w następujący sposób -

Kliknięcie przycisku Edytuj w trzecim wierszu spowoduje przekierowanie do następującego adresu URL http://localhost:8080/edit?name=Rajesh+Patil

TurboGears udostępnia rozszerzenie tgext.admin, które jest obsługiwane przez tgext.crud i sprox. Ten Sprox to pakiet służący do tworzenia widgetów internetowych bezpośrednio ze schematu bazy danych. Można to wykorzystać do automatycznego tworzenia prostych stron administracyjnych i jest to zestaw narzędzi obsługujący stronę / admin w nowo uruchamianych aplikacjach.

Domyślnie administrator zapewni automatycznie generowany dostęp do wszystkich modeli zaimportowanych do modeli projektu / __ init__.py.

Jak utworzyć administratora TurboGears

Domyślny administrator TurboGears jest tworzony jako obiekt klasy AdminController -

from tgext.admin.controller import AdminController

class RootController(BaseController):
   admin = AdminController(model, DBSession, config_type = TGAdminConfig)

Tworzy to administratora dla wszystkich modeli z domyślną konfiguracją administratora TurboGears.

Na etapie konfiguracji utworzono użytkownika za pośrednictwem menedżera. Teraz można uzyskać dostęp do administratora TurboGears pod adresemhttp://localhost:8080/adminGdy ta strona jest otwierana po raz pierwszy, poprosi o uwierzytelnienie. Możesz po prostu podać nazwę użytkownika i hasło użytkownika, które utworzyło dla nas polecenie setup-app -

Username: manager
Password: managepass

Aby zalogować się do projektu szybkiego startu, dodaj następujące funkcje do klasy RootController (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)

Zaloguj się do aplikacji „quickstarted” po uruchomieniu serwera i odwiedzeniu strony http://localhost:8080/logina następnie wprowadź poświadczenia menedżera, jak pokazano powyżej. Przeglądarka wyświetli stronę administratora, taką jak ta pokazana poniżej -

Strona pokazuje wszystkie modele utworzone w tej aplikacji. Możesz kliknąć dowolny model, aby zobaczyć listę wpisów w nim -

Przycisk „Nowy” na górze tego datagridu umożliwia dodanie rekordu. Podobnie przyciski akcji do edycji i usuwania rekordu są również dostępne w kolumnie akcji tego datagridu. Wyświetlane jest również pole wyszukiwania umożliwiające warunkowe wybieranie rekordów.

Aplikacja TurboGears jest tworzona za pomocą opcji szybkiego startu i konfiguracji aplikacji zestawu narzędzi skrzyni biegów, która ma domyślnie włączoną obsługę autoryzacji i uwierzytelniania. Modele zadeklarowane w auth.py są konfigurowane i inicjowane zgodnie z wartościami przypisanymi w pliku bootstrap.py.

Następujące modele są zadeklarowane w auth.py -

Model użytkownika

Model użytkownika zawiera projekt tabeli tg_user. Ta tabela jest używana przez pakiet repose.who. Ten pakiet repose.who jest potężną i rozszerzalną biblioteką uwierzytelniania dla aplikacji WSGI. Struktura modelu użytkownika jest następująca -

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)

Ten model grupowy zawiera definicję tabeli tg_group. Jego definicja jest podana w auth.py w następujący sposób -

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)

Skonfigurowane jest również inne uprawnienie modelu, które zawiera definicję uprawnienia.

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))

W momencie tworzenia modeli w tych tabelach dodaje się następujące dane -

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)

Model predykatu

Moduł predykatów w pakiecie tg zawiera definicje programów sprawdzających predykaty. Predykat to warunek, który musi być spełniony, aby użytkownik mógł uzyskać dostęp do żądanego źródła. Taki predykat lub warunek może składać się z większej liczby predykatów - nazywamy je predykatami złożonymi. Kontrolery akcji lub kontrolery mogą mieć tylko jeden predykat, pojedynczy lub złożony.

Jeśli użytkownik nie jest zalogowany lub nie ma odpowiednich uprawnień, ten moduł sprawdzania predykatów zgłasza 401 (HTTP Unauthorized), który jest przechwytywany przez repoze. Które oprogramowanie pośredniczące wyświetla stronę logowania umożliwiającą użytkownikowi użytkownik z powrotem na właściwą stronę, kiedy to zrobią.

Różne warunki lub predykaty zdefiniowane w module tg.predicates to -

Sr.No. tg.predicates moduł i opis
1

All

Sprawdź, czy wszystkie określone predykaty są spełnione

2

Any

Sprawdź, czy spełniony jest co najmniej jeden z określonych predykatów

3

is_user

Sprawdź, czy nazwa użytkownika uwierzytelnionego użytkownika jest podana

4

in_group

Sprawdź, czy użytkownik należy do określonej grupy.

5

in_all_groups

Sprawdź, czy użytkownik należy do wszystkich określonych grup.

6

in_any_group

Sprawdź, czy użytkownik należy do co najmniej jednej z określonych grup.

7

is_anonymous

Sprawdź, czy aktualny użytkownik jest anonimowy.

8

has_permission

Sprawdź, czy bieżący użytkownik ma określone uprawnienia.

9

has_all_permissions

Sprawdź, czy bieżącemu użytkownikowi nadano wszystkie określone uprawnienia.

10

has_any_permission

Sprawdź, czy użytkownik ma co najmniej jedno z określonych uprawnień.

Na przykład, jeśli masz predykat, którym jest grant access user belonging to customers group, możesz użyć następującego wbudowanego narzędzia do sprawdzania predykatów -

from tg.predicates import in_group
p in_group(‘customers’)

Poniższy program do sprawdzania predykatów przyzna dostęp użytkownikowi `` root '' lub każdemu z uprawnieniami do zarządzania -

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 obsługuje również bazy danych dokumentów MongoDB. Używa Ming, API Object Document Mapper. Użycie Ming jest bardzo podobne do SQLAlchemy. Język zapytań Ming umożliwia przeniesienie projektu TurboGears opartego na SQLAlchemy do Ming.

Co to jest PyMongo

PyMongo to dystrybucja Pythona zawierająca narzędzia do pracy z MongoDB. Ming rozszerza ofertę PyMongo o -

  • Deklaratywne modele
  • Walidacja i konwersja schematu
  • Schema Evolution
  • Implementacja Pure InMemory MongoDB
  • Jednostka pracy
  • Mapa tożsamości
  • Relacje jeden do wielu, wiele do jednego i wiele do wielu

Przede wszystkim musisz pobrać i zainstalować MongoDB. Najnowszą dystrybucję MongoDB można pobrać z witrynyhttps://www.mongodb.org/downloads

W systemie Windows uruchom serwer MongoDB, podając opcję -dbpath -

C:\mongodb\bin>Mongod --dbpath d:\mongo

D:\mongo folderjest przeznaczony do przechowywania bazy danych MongoDB. Serwer zaczyna nasłuchiwać ohttp://localhost:27017. Teraz, aby uruchomić powłokę MongoDB, użyj następującego polecenia -

C:\mongodb\bin>Mongo

Nasze środowisko MongoDB jest już gotowe.

Teraz utwórz projekt TurboGears z opcją -ming -

gearbox quickstart --ming Hello

Ten projekt szybkiego startu zapewni warstwę uwierzytelniania i autoryzacji, taką jak ta, która jest dostarczana dla wersji SQLAlchemy. Ta aplikacja będzie teraz próbowała połączyć się z serwerem przez port 27017 na komputerze lokalnym. Plik development.ini w folderze projektu zawiera następujące ustawienia -

ming.url = mongodb://localhost:27017/
ming.db = hello

Skonfiguruj projekt za pomocą następującego polecenia -

Python setup.py develop

Folder projektu zawiera podfolder modeli, który zawiera następujące pliki -

  • __init__.py - Tutaj jest databasedostęp jest skonfigurowany. Twoje kolekcje powinny byćimported into this module. Na przykład do tego pakietu dodamy zbiórkę studencką.

  • session.py - Ten plik definiuje rozszerzenie session of your database connection. Będziesz musiał zaimportować to za każdym razem, gdy będziesz musiał zadeklarować plikMappedClass aby określić sesję perform queries.

  • auth.py - Ten plik zostanie utworzony, jeśli masz enabled authentication and authorizationw przewodniku Szybki start. Definiuje trzy kolekcjerepoze.who, który dalej opiera się na: użytkownikach, grupach i uprawnieniach.

Definiowanie Twojej kolekcji

Domyślnie TurboGears konfiguruje Ming w trybie deklaratywnym. Jest to podobne do obsługi deklaratywnej SQLAlchemy i wymaga, aby każdy model dziedziczył z klasy MappedClass.

MappedClass wymaga, aby podklasa __mongometa__ była dostępna w środku, co dodatkowo zawiera szczegóły dotyczące nazwy kolekcji przechowującej dokumenty i sesji używanej do przechowywania dokumentów.

MappedClass zawiera również definicję pól w dokumencie. Moduł odm Ming zawiera definicje różnych typów właściwości pól -

  • FieldProperty
  • ForeignIdProperty
  • RelationProperty

Plik ming.schema module definiuje następujące typy danych -

  • 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

Aby dodać kolekcję uczniów w tym modelu, zapisz następujący kod jako student.py w folderze hello / models.

Witaj \ 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 = ''))

Na koniec umieść ten model w hello \ models \ __ init__.py

# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student

Aby skonfigurować te modele, uruchom następujące polecenie skrzyni biegów -

Gearbox setup-app

Uruchom serwer za pomocą następującego polecenia skrzyni biegów -

Gearbox serve –reload –debug

Otwórz stronę główną tej aplikacji (http://localhost:8080/)i zaloguj się za pomocą poświadczeń menedżera. Strona administratora tej aplikacji pokaże listę skonfigurowanych modeli. (zaloguj się jako menedżer, zarządzanie hasłem)

Tworzenie kolekcji można również zweryfikować w interfejsie WWW MongoDB, a także w powłoce MongoDB.

Sesja ODMS służy do wykonywania kilku operacji na bazie danych przy użyciu następujących funkcji -

  • model.query.find()
  • model.query.find_and_modify()
  • model.remove()
  • model.update()
  • model.flush()

Projektowanie formularza ToscoWidget

Zaprojektujemy teraz formularz ToscoWidget, aby wprowadzić dane uczniów i dodać je do tabeli, na której opiera się model ucznia.

Poniżej znajduje się kod do tworzenia studentform.py -

Witaj \ 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')

W aplikacji Rootcontroller '/ add' URL wywołujący funkcję add (), która otworzy w przeglądarce wyżej zaprojektowany formularz. Jego przycisk przesyłania wywołuje następnie funkcję save_record (). Pobiera dane formularza i zapisuje je w tabeli uczniów i przekierowuje aplikację do adresu URL „/ listrec”, który udostępnia szablon listy uczniów.

Plik root.py dla tego działania jest następujący -

Witaj / 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 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")

W folderze szablonów tworzone są następujące szablony -

Witaj \ 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>

Witaj \ 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>

Zrestartuj serwer i wejdź http://localhost:8080/add w przeglądarce -

Za każdym razem, gdy dane zostaną dodane i naciśnięty zostanie przycisk przesyłania, zostanie wyświetlona lista aktualnych wpisów.

Zestaw narzędzi Gearbox zawiera polecenie scaffold, które jest bardzo przydatne do szybkiego tworzenia nowych komponentów aplikacji TurboGears. Aplikacja wygenerowana poleceniem szybkiego startu gearboxa posiada szkielet szablonu w folderze modelu (model.py.template), folderze szablonów (template.html.template) oraz folderze kontrolerów (controller.py.template). Te pliki „.template” służą jako podstawa do tworzenia nowych rusztowań dla aplikacji

Na przykład, aby utworzyć nowy model o nazwie mymodel, po prostu uruchom następujące polecenie -

gearbox scaffold model mymodel

To polecenie wygeneruje model / mymodel.py ze zdefiniowaną w nim klasą newmodel.

# -*- 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']

Użytkownicy mogą teraz wprowadzać modyfikacje w strukturze tabeli zgodnie ze swoimi wymaganiami, a następnie importować ją do środka model/__init__.py aby model był dostępny w aplikacji.

Aby stworzyć model, klasę kontrolera do jego obsługi i stronę indeksu, wszystkie te trzy komponenty można utworzyć jednocześnie za pomocą następującego polecenia.

gearbox scaffold model controller template mymodel

To polecenie spowoduje utworzenie controllers \ mymodel.py, w których klasa MymodelController jest należycie zdefiniowana.

# -*- 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')

Aby rozpocząć korzystanie z tego kontrolera, zamontuj go w aplikacji RootController, aby zdefiniować wystąpienie MymodelController. Dodaj te linie w pliku controllers \ root.py -

From hello.controller.mymodel import MymodelController

class RootController(BaseController): mymodel = MymodelController()

Szablon rusztowania szablonów \ mymodel.html zostanie również utworzony w folderze szablonów. Będzie działać jako strona indeksu dla adresu URL „/ mymodel”.

Wygenerowany plik mymodel.html file w folderze szablonów będzie wyglądać następująco -

<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>

W TurboGears istnieją trzy sposoby podłączania zachowań w istniejących aplikacjach.

  • Hook - Jest to mechanizm, za pomocą którego można zdefiniować zdarzenie i powiadomić zarejestrowanych słuchaczy o ich emisji.

  • Controller Wrapper- Znajduje się między TurboGears a kontrolerem, dzięki czemu można rozszerzyć kontroler jak dekorator. W ten sposób można go dołączyć do dowolnej aplikacji kontrolera innej firmy.

  • Application Wrapper - Jest podobny do dowolnego oprogramowania pośredniego WSGI, ale działa tylko w kontekście TurboGears.

W tym rozdziale omówimy, jak używać haków wewnątrz istniejącej aplikacji.

Haczyki

Hooki to zdarzenia zarejestrowane w pliku konfiguracyjnym aplikacji app_cfg.py. Każdy kontroler jest następnie podłączany do tych wydarzeń przez dekoratorów wydarzeń.

Następujące haki są zdefiniowane w TurboGears -

Sr.No. Haczyki i opis
1

Startup()

tylko dla całej aplikacji, wywoływane podczas uruchamiania aplikacji.

2

shutdown()

tylko dla całej aplikacji, wywoływana po zamknięciu aplikacji.

3

configure_new_app

nowa aplikacja została utworzona przez konfigurator aplikacji.

4

before_config(app)

tylko dla całej aplikacji, wywoływane zaraz po utworzeniu aplikacji, ale przed skonfigurowaniem opcji i oprogramowania pośredniego

5

after_config(app)

tylko szeroka aplikacja, wywoływana po zakończeniu konfiguracji.

6

before_validate

Wywoływane przed wykonaniem walidacji

7

before_call

Wywoływane po walidacji, przed wywołaniem rzeczywistej metody kontrolera.

8

before_render

Wywoływane przed renderowaniem szablonu kontrolera dane wyjściowe to wartość zwracana przez kontroler.

9

after_render

Wywoływane po zakończeniu renderowania szablonu kontrolera.

Zarejestruj hook

W celu register a Hook, tworzyć funkcje w app_cfg.py a następnie zarejestruj je za pomocą następującego kodu -

tg.hooks.register(hookane, function, controller)

W poniższym kodzie zaczepy on_startup, on_shutdown i before_render są zarejestrowane w app_cfg.py.

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)

Hak before_render jest zarejestrowany w funkcji kontrolera w Rootcontroller. Dodaj następujący kod w pliku controllers \ root.py.

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')

Gdy aplikacja jest obsługiwana, w konsoli wyświetlany jest komunikat startowy.

hello, startup world
Starting Standard HTTP server on http://127.0.0.1:8080

Po wpisaniu adresu URL „/” w przeglądarce na konsoli zostanie wyświetlony komunikat odpowiadający hakowi before_render.

system wide before render
Going to render {'page': 'index'}

Rozszerzenia TurboGears są identyfikowane przez tgext.* package. Zestaw narzędzi Gearbox zawiera polecenie tgext do tworzenia przykładowego rozszerzenia. Na przykład -

gearbox tgext -n myextension

Inne opcjonalne parametry tego polecenia to -

  • --author - nazwisko autora pakietu.

  • --email - e-mail autora pakietu.

  • --licence- licencja używana do pakietu. Wartość domyślna to MIT.

  • --description - Opis opakowania.

  • --keywords - Słowa kluczowe pakietu (domyślnie: turbogears2.extension).

Spowoduje to utworzenie katalogu tgext.myextension, w którym znajduje się proste przykładowe rozszerzenie.

Run the setup.py wewnątrz katalogu -

Python setup.py install

Plik _init_.py plik wewnątrz tgext/myextension folder zawiera -

  • Plugme function - To jest punkt wejścia rozszerzenia.

  • SetupExtension class - tutaj następuje inicjalizacja rozszerzenia.

  • On_startup function - wewnątrz klasy jest podpięcie zarejestrowane w funkcji __call__ wewnątrz klasy.

Krótka wersja 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!')

Po zainstalowaniu rozszerzenia włącz je, wprowadzając następujące dodatki w pliku aplikacji app_cfg.py plik konfiguracyjny.

from tgext.myextension import plugme

plugme(base_config)

Jeśli uruchomimy serwer za pomocą polecenia serwera gearboxa, powiadomienie o nowo zarejestrowanym rozszerzeniu można wyświetlić na konsoli poprzez:

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

Jeśli Twoje rozszerzenie musi udostępniać modele i kontrolery, prawdopodobnie chcesz rzucić okiem na plik Pluggable Applications, które mają na celu tworzenie aplikacji Turbogears wielokrotnego użytku, które można podłączyć do innych aplikacji w celu rozszerzenia ich funkcji.

Użyj następującego polecenia skrzyni biegów, aby utworzyć podłączalną aplikację -

gearbox quickstart-pluggable plugtest

Te dołączane aplikacje mogą definiować własne -

  • Controllers - który zostanie automatycznie zamontowany po wyczyszczeniu aplikacji.

  • Models - który będzie dostępny wewnątrz i na zewnątrz podłączonej aplikacji.

  • Helpers - które mogą być automatycznie widoczne w obiekcie „H” w szablonie aplikacji.

  • Bootstrap - które zostanie wykonane po wywołaniu aplikacji setup.

  • Statics - które będą dostępne na ich własnej prywatnej ścieżce.

Zainstaluj tę aplikację plugtest i zamontuj ją, wprowadzając następujące modyfikacje w app_cfg.py.

from tgext.pluggable import plug
plug(base_config, plugtest)

REST oznacza REprezentacyjny State Tokup. REST to architektura oparta na standardach internetowych i wykorzystuje protokół HTTP do przesyłania danych. Obraca się wokół zasobu, w którym każdy komponent jest zasobem, a dostęp do zasobu uzyskuje się za pomocą wspólnego interfejsu przy użyciu standardowych metod HTTP. REST został po raz pierwszy wprowadzony przezRoy Fielding in 2000.

Co to jest RestController

RestController w TurboGears zapewnia mechanizm dostępu do metody żądania, a nie tylko adresu URL. Standardowe słownictwo HTTP obejmuje: GET, POST, PUT i DELETE. RestController obsługuje je, a także dodaje kilka skrótów do wysyłania adresów URL, które sprawiają, że wyświetlanie danych jako formularzy i list jest nieco łatwiejsze dla użytkownika.

Aby wyjaśnić, jak RESTful współpracuje z TurboGears, zdefiniujemy prostą usługę sieciową, która udostępnia listę uczniów.

Kod modelu studenckiego podano poniżej -

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 = '')

Teraz utwórz kontroler oparty na RestController i zapewnij funkcję widoku, aby wyświetlić listę uczniów w formacie json.

Kontrolery \ 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)

Zamontuj ten StudentController w RootController aplikacji, włączając następujące wiersze w root.py -

from hello.controllers.student import StudentController

class RootController(BaseController):

   students = StudentController()

Isc do http://localhost:8080/students dostarczy listę naszych uczniów zakodowaną w formacie json.

Używamy metody post, aby określić, w jaki sposób będziemy zapisywać naszego ucznia w bazie danych. Ta metoda jest wywoływana za każdym razem, gdy http://localhost:8080/student adres URL jest dostępny za pomocą żądania POST -

@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)

Używając get_one() możemy wyświetlić użytkownikowi jedną pozycję z bazy danych -

@expose('json')
def get_one(self, movie_id):
   newstudent = DBSession.query(student).get(uid)
   return dict(movie = movie)

PUT to metoda używana do aktualizacji istniejącego rekordu za pomocą 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)

Koń roboczy delete jest dołączony do metody post_delete. Tutaj faktycznie usuwamy rekord z bazy danych, a następnie przekierowujemy z powrotem na stronę z listą -

@expose('json')
def post_delete(self, uid, **kw):
   newstudent = DBSession.query(student).get(uid)
   DBSession.delete(newstudent)
   return dict(movie = newstudent.uid)

Aby przełączyć się ze środowiska programistycznego na pełnoprawne środowisko produkcyjne, aplikacja musi zostać wdrożona na prawdziwym serwerze WWW. W zależności od tego, co masz, dostępne są różne opcje wdrażania aplikacji internetowej TurboGears.

Apache z mod_wsgi

Mod_wsgi to moduł Apache opracowany przez Grahama Dumpletona. Umożliwia obsługę programów WSGI przy użyciu serwera WWW Apache.

Po pierwsze, zainstaluj Apache 2.X na swojej platformie, jeśli jeszcze tego nie zrobiłeś. Po zainstalowaniu Apache zainstaluj mod_wsgi. Utwórz i aktywuj wirtualne środowisko Python na serwerze i zainstaluj w nim TurboGears.

Zainstaluj aplikację w aplikacji Director, a następnie utwórz skrypt o nazwie app.wsgi.

Skonfiguruj instalację Apache w następujący sposób -

<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>

Uruchom ponownie Apache

Rodzaj http://www.site1.com/ w przeglądarce, aby uzyskać dostęp do aplikacji.

TurboGears pod Circus i Chaussette

Circus to menedżer procesów i gniazd. Może być używany do monitorowania i sterowania procesami i gniazdami. W połączeniu z serwerem Chaussette WSGI może stać się potężnym narzędziem do wdrażania aplikacji i zarządzania dowolnym powiązanym procesem, którego potrzebują.

TurboGears - GoogleAppEngine

Zainstaluj pakiet SDK Google AppEngine dla języka Python z następującego adresu URL - https://cloud.google.coms

Zainstaluj Google AppEngine w swoim systemie. Następnie otwórz Google Developer Console i zaloguj się na swoje konto Google -https://console.developers.google.com/start

Utwórz nowy projekt o nazwie mytgapp -

Korzystając z programu Google AppEngine Launcher, utwórz nową aplikację o nazwie mytgapp.

W określonym katalogu zostaną utworzone następujące pliki -

  • app.yaml
  • favicon.ico
  • index.yaml
  • main.py

Domyślnie tworzona aplikacja opiera się na frameworku Webapp2. Aby usunąć tę zależność, edytuj plik app.yaml i usuń następującą część -

libraries:
   - name: webapp2
   version: "2.5.2"

Utwórz tymczasowe środowisko wirtualne w katalogu o nazwie mytgapp i zainstaluj TurboGears. Utwórz w nim aplikację TurboGears. Teraz możemy kontynuować edycję plikumain.py plik uruchamiany przez AppEngine w celu uruchomienia naszej aplikacji i napisania tam aplikacji TurboGears.

Dodaj następującą zawartość w 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()

Teraz uruchom aplikację z AppEngine Launcher i kliknij przycisk Przeglądaj, aby zobaczyć, że aplikacja działa poprawnie na hoście lokalnym.

Stworzyliśmy już projekt o nazwie mytgapp w konsoli programisty. Teraz kliknij przycisk wdrażania w programie uruchamiającym. Po zakończeniu procesu wdrażaniahttp://mytgapp.appspot.com/ odwiedź, aby zobaczyć naszą aplikację online.