Turbogears - Guia Rápido
O que é Web Framework?
Web Application Framework ou simplesmente Web Framework representa uma coleção de bibliotecas e módulos, que permite a um desenvolvedor de aplicativos da web escrever aplicativos, sem ter que se preocupar com detalhes de baixo nível, como protocolos, gerenciamento de threads, etc.
O que é TurboGears?
TurboGears é uma estrutura de aplicativo da web escrita em Python. Originalmente criado por Kevin Dangoor em 2005, sua última versão TurboGears (ver 2.3.7) é gerenciada por um grupo de desenvolvedores liderado por Mark Ramm e Florent Aide.
TurboGears segue o paradigma Model-View-Controller assim como a maioria dos frameworks web modernos como Rails, Django, Struts, etc.
Controlador de visualização de modelo
MVC é um padrão de design de software para o desenvolvimento de aplicativos da web. Um padrão Model View Controller é composto de três partes -
Model - O nível mais baixo do padrão é responsável por manter os dados.
View - É responsável por exibir todos ou uma parte dos dados ao usuário.
Controller - Código de software que controla as interações entre o modelo e a visualização.
MVC é popular porque isola a lógica do aplicativo da camada de interface do usuário e oferece suporte à separação de interesses. Aqui, o Controlador recebe todas as solicitações do aplicativo e, em seguida, trabalha com o Modelo para preparar os dados necessários para a Visualização. A Visualização então usa os dados preparados pelo Controlador para gerar uma resposta final apresentável. A abstração MVC pode ser representada graficamente da seguinte forma -
O modelo
O modelo é responsável por gerenciar os dados do aplicativo. Ele responde à solicitação da visualização e também às instruções do controlador para se atualizar.
A vista
Uma apresentação de dados em um formato específico, desencadeada pela decisão de um controlador de apresentar os dados. Eles são sistemas de modelos baseados em script muito fáceis de integrar com a tecnologia AJAX.
O controlador
O controlador é responsável por responder à entrada do usuário e realizar interações nos objetos do modelo de dados. O Controlador recebe a entrada, ele valida a entrada e, em seguida, realiza a operação de negócios que modifica o estado do modelo de dados.
O TurboGears é construído em cima de uma série de bibliotecas e ferramentas. Essas ferramentas mudaram entre as diferentes versões do TurboGears. Os componentes da versão atual (ver 2.3.7) estão listados abaixo.
SQLAlchemy
É um kit SQL de código aberto que fornece mapeamento de relação de objeto (ORM) para código Python.
Genshi
Este mecanismo de modelagem é usado para construir o front-end dos aplicativos TG. Um sistema de modelos da web combina um modelo com uma determinada fonte de dados para renderizar páginas da web dinâmicas.
ToscaWidgets
É uma biblioteca de widgets para gerar formulários HTML com controles do lado do servidor. O Tosca também atua como um middleware para se conectar com widgets e kits de ferramentas JavaScript.
Caixa de velocidade
Ele fornece um conjunto de comandos para gerenciar projetos e aplicativos de servidor TurboGears. Os aplicativos TurboGears podem ser implantados em qualquer servidor da web compatível com WSGI.
A Web Server Gateway Interface (WSGI) foi adotada como um padrão para o desenvolvimento de aplicativos da Web em Python. WSGI é uma especificação para interface universal entre o servidor da web e os aplicativos da web. O pacote wsgiref é uma implementação de referência do WSGI. É usado para adicionar suporte WSGI ao framework web TurboGears. O módulo simple_server neste pacote implementa um servidor HTTP simples que serve aplicativos WSGI. Devemos usá-lo para testar aplicativos desenvolvidos durante este tutorial.
Pré-requisito
Python 2.6 ou superior. As versões anteriores do TurboGears não eram compatíveis com Python 3.X. A versão mais recente afirma funcionar bem no Python 3.X. No entanto, a documentação oficial do TurboGears ainda é baseada no ambiente Python 2.7.
O seguinte comando installs virtualenv -
pip install virtualenv
Este comando precisa administratorprivilégios. Adicionarsudo before pipno Linux / Mac OS. Se você estiver no Windows, faça login como Administrador. No Ubuntu, o virtualenv pode ser instalado usando seu gerenciador de pacotes.
Sudo apt-get install virtualenv
Depois de instalado, o novo ambiente virtual é criado em uma pasta.
mkdir newproj
cd newproj
virtualenv venv
Para ativar o ambiente correspondente, em Linux/OS X
venv/bin/activate
em Windows
venv\scripts\activate
Agora estamos prontos para install TurboGearsneste ambiente. Uma instalação mínima do TurboGears é feita seguindo o comando -
pip install TurboGears2
O comando acima pode ser executado diretamente sem ambiente virtual para instalação em todo o sistema.
Para instalar TurboGears junto com ferramentas de desenvolvimento, use o seguinte comando -
pip install tg.devtools
O TurboGears possui um modo mínimo que torna possível criar aplicativos de arquivo único rapidamente. Exemplos e serviços simples podem ser criados rapidamente com um conjunto mínimo de dependências.
A classe de aplicativo em um aplicativo TG é herdada de TGControllerclasse. Métodos nesta classe estão disponíveis para acesso por@expose decorador de tgmódulo. Em nossa primeira aplicação,index()método é mapeado como raiz de nosso aplicativo. A classe TGController também precisa ser importada detg módulo.
from tg import expose, TGController
class MyController(TGController):
@expose()
def index(self):
return 'Hello World turbogears'
Em seguida, defina a configuração do aplicativo e declare o objeto do aplicativo. AppConfig o construtor de classe aqui leva dois parâmetros - atributo mínimo definido como verdadeiro e a classe do controlador.
config = AppConfig(minimal = True, root_controller = RootController())
application = config.make_wsgi_app()
o make_wsgi_app() função aqui constrói o objeto do aplicativo.
Para servir este aplicativo, agora precisamos iniciar o servidor HTTP. Conforme mencionado anteriormente, devemos usarsimple_server módulo em wsgirefpacote para configurá-lo e iniciá-lo. Este módulo temmake_server() método que requer o número da porta e o objeto do aplicativo como argumentos.
from wsgiref.simple_server import make_server
server = make_server('', 8080, application)
server.serve_forever()
Isso significa que nosso aplicativo será servido na porta número 8080 do localhost.
A seguir está o código completo de nosso primeiro aplicativo 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()
Execute o script acima do shell Python.
Python app.py
Entrar http://localhost:8080 na barra de endereços do navegador para visualizar a mensagem 'Hello World TurboGears'.
o tg.devtoolsde TurboGears contém caixa de engrenagens. É um conjunto de comandos úteis para o gerenciamento de projetos TG mais complexos. Projetos full stack podem ser criados rapidamente pelo seguinte comando Gearbox -
gearbox quickstart HelloWorld
Isso criará um projeto chamado HelloWorld.
Um projeto TurboGears contém os seguintes diretórios -
Config - Onde a instalação e configuração do projeto dependem
Controllers - Todos os controladores de projeto, a lógica da aplicação web
i018n - Arquivos de tradução para os idiomas suportados
Lib - Funções e classes utilitárias do python
Model - Modelos de banco de dados
Public Static Files - CSS, JavaScript e imagens
Templates - Templates expostos por nossos controladores.
Tests - O conjunto de testes realizados.
Websetup - Funções para executar na configuração do aplicativo.
Como instalar um projeto
Este projeto agora precisa ser instalado. UMAsetup.pyjá é fornecido no diretório base do projeto. As dependências do projeto são instaladas quando este script é executado.
Python setup.py develop
Por padrão, as seguintes dependências são instaladas no momento da configuração do projeto -
- Beaker
- Genshi
- zope.sqlalchemy
- sqlalchemy
- alembic
- repoze.who
- tw2.forms
- tgext.admin ≥ 0,6.1
- WebHelpers2
- babel
Após a instalação, comece a servir o projeto no servidor de desenvolvimento, emitindo o seguinte comando no shell -
Gearbox serve –reload –debug
Siga o comando mencionado acima para servir a um projeto de exemplo pré-construído. Abrirhttp://localhost:8080no navegador. Este aplicativo de amostra pronto fornece uma breve introdução sobre a própria estrutura do TurboGears.
Neste projeto Hello, o controlador padrão é criado no diretório de controladores como Hello/hello/controllers.root.py. Deixe-nosmodify root.py com o seguinte código -
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"
Quando um aplicativo básico de trabalho estiver pronto, mais visualizações podem ser adicionadas na classe do controlador. NoMycontroller classe acima, um novo método sayHello()Está adicionado. o@expose() decorador anexa /sayHelloURL para ele. Esta função foi projetada para aceitar um nome como parâmetro do URL.
Depois de iniciar o servidor por meio do comando 'caixa de engrenagens', http://localhost:8080. A mensagem Hello World será exibida no navegador, mesmo se os seguintes URLs forem inseridos -
http://localhost:8080/
http://localhost:8080/index
Todos esses URLs são mapeados para RootController.index()método. Esta classe também tem_default()método que será chamado, sempre que um URL não for mapeado para qualquer função específica. A resposta ao URL é mapeada para uma função pelo decorador @expose ().
É possível enviar um parâmetro para uma função exposta da URL. A função a seguir lê o parâmetro de nome do URL.
@expose()
def sayHello(self, name):
return '<h3>Hello %s</h3>' %name
A seguinte saída será vista no navegador como uma resposta ao URL - http://localhost:8080/?name=MVL
Hello MVL
O TurboGears mapeia automaticamente os parâmetros de URL para argumentos de função. Nossa classe RootController é herdada de BaseController. Isso é definido comobase.py no lib folder de aplicação.
Seu código é o seguinte -
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__ despacha para o método do controlador para o qual a solicitação é roteada.
Um evento embora o conteúdo HTML possa ser retornado ao navegador, para uma saída mais avançada, o uso do mecanismo de modelo é sempre preferido. Em um projeto de pilha completa 'iniciado rapidamente' pela caixa de engrenagens, Genshi é habilitado como o renderizador de modelo padrão. Em um aplicativo mínimo, no entanto, o Genshi (ou qualquer outro mecanismo de modelo, como o jinja) precisa ser instalado e ativado. O mecanismo de template Genshi permite escrever templates em xhtml puro e valida-os para detectar problemas em tempo de compilação e prevenir páginas quebradas.
Os modelos são referidos usando uma notação pontilhada. Em nosso projeto Hello, um diretório de modelos é fornecido para armazenar páginas da web de modelo. Conseqüentementesample.html será referido como hello.templates.sample(extensão não mencionada). O TurboGears renderiza este modelo através de um decorador de exposição para vincular o método do controlador a ele portg.render_template() função.
A função do controlador exposta retorna um objeto de dicionário Python. Este objeto de dicionário, por sua vez, é passado para o modelo vinculado. Os marcadores de posição no modelo são preenchidos com valores de dicionário.
Para começar, vamos exibir uma página da web com script html simples. O controlador exposto retorna umnull dictionary object pois não temos a intenção de enviar nenhum dado para ser analisado dentro do script HTML.
Como criar um exemplo de HTML
Nosso sample.htmlé fornecido abaixo. Certifique-se de que ele esteja armazenado no diretório de modelos do projeto.
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, Welcome to TurboGears!.</h2>
</body>
</html>
Adicionar sample() função em root.py e expor sample.html por meio dele.
@expose("hello.templates.sample")
def sample(self):
return {}
O seguinte resultado será exibido no navegador quando um URL http://localhost:8080/sample é inserido após iniciar o servidor da web.
Conforme mencionado acima, um objeto de dicionário é enviado como uma coleção de parâmetros para um modelo Genshi. Este modelo contém 'marcadores de posição', que são preenchidos dinamicamente com os parâmetros recebidos do controlador.
Vamos mudar o sample() função para enviar um objeto de dicionário para o modelo de amostra.
@expose("hello.templates.sample")
def sample(self,name):
mydata = {'person':name}
return mydata
Crio sample.html na pasta de modelos (templates\sample.html)
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h2>Hello, my name is ${person}!.</h2>
</body>
</html>
No código HTML acima, ${person}é o espaço reservado. Entrarhttp://localhost:8080/sample?name=MVLcomo URL no navegador. Este URL está mapeado parasample()método em nosso controlador raiz. Ele retorna um objeto de dicionário. Isso é escolhido pela página de modelo vinculada sample.html no diretório de modelos. O $ {person} é então substituído por MVL na página da web.
Também é possível acessar os dados do formulário HTML em uma função de controlador. O formulário HTML usa para enviar dados do formulário.
O protocolo Http é a base da comunicação de dados na rede mundial de computadores. Diferentes métodos de recuperação de dados do URL especificado são definidos neste protocolo. A tabela a seguir resume os diferentes métodos http -
Sr. Não. | Métodos HTTP e descrição |
---|---|
1 | GET Envia dados de forma não criptografada para o servidor. Método mais comum. |
2 | HEAD Igual a GET, mas sem corpo de resposta |
3 | POST Usado para enviar dados de formulário HTML para o servidor. Os dados recebidos pelo método POST não são armazenados em cache pelo servidor. |
4 | PUT Substitui todas as representações atuais do recurso de destino com o conteúdo carregado. |
5 | DELETE Remove todas as representações atuais do recurso de destino fornecidas por um URL |
Criação de um formulário HTML
Vamos criar um formulário HTML e enviar os dados do formulário para um URL. Salve o seguinte script como 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>
Os dados inseridos neste formulário devem ser enviados para ‘/login’ URL. Agora crie uma função de controladorloginpage() e expor a página html acima para ele.
@expose("hello.templates.login")
def loginpage(self):
return {}
Para receber os dados do formulário, forneça um login()controlador, que possui atributos de formulário como parâmetros. Aqui‘nm’ é o nome do campo de entrada de texto no formulário de login, o mesmo é usado como um parâmetro da função login ().
@expose("hello.templates.sample")
def login(self, nm):
name = nm
return {'person':name}
Como pode ser visto, os dados recebidos do formulário de login estão sendo enviados para o template sample.html (usado anteriormente). É analisado por umGenshi template engine para gerar a seguinte saída -
Método POST
Quando o formulário HTML usa o método POST para enviar dados para o atributo URL in action, os dados do formulário não são expostos no URL. Os dados codificados são recebidos em umdictargumento pela função do controlador. O **kw o argumento abaixo é o objeto de dicionário que contém os dados.
O formulário HTML contém dois campos de texto de entrada.
<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>
o marks() o controlador recebe os dados do formulário e os envia para sample.htmlmodelo. Código pararoot.py é o seguinte -
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
Finalmente, o modelo sample.html é o seguinte -
<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>
Inicie o servidor (se ainda não estiver em execução)
Gearbox server –reload –debug
Entrar http://localhost::8080/marksform no navegador
o sample.html irá renderizar a seguinte saída -
Genshi é uma linguagem de template baseada em XML. É similar àKid, que costumava ser o mecanismo de modelo para versões anteriores do TurboGears. Genshi e Kid são inspirados por outras linguagens de template conhecidas comoHSLT, TAL e PHP.
Um modelo Genshi consiste em diretivas de processamento. Essas diretivas são elementos e atributos em um modelo. As diretivas Genshi são definidas em um namespacehttp://genshi.edgewall.org/. Portanto, este namespace precisa ser declarado no elemento raiz do template.
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:py = "http://genshi.edgewall.org/"
lang = "en">
...
</html>
A declaração acima significa que o namespace padrão é definido como XHTML e as diretivas Genshi têm o prefixo 'py'.
Diretivas Genshi
Uma série de diretrizes são definidas em Genshi. A lista a seguir enumera as diretivas Genshi -
- py:if
- py:choose
- py:for
- py:def
- py:match
- py:with
- py:replace
- py:content
- py:attrs
- py:strip
Seções condicionais
Genshi fornece duas diretivas para renderização condicional de content− py: if e py: choose.
py: se
O conteúdo do elemento desta diretiva será processado apenas se a expressão em if clauseavalia como verdadeiro. Assumindo que os dados no contexto do modelo são{‘foo’:True, ‘bar’:’Hello’}, a seguinte diretiva -
<div>
<b py:if = "foo">${bar}</b>
</div>
vai resultar em
Hello
Esta saída, no entanto, não seria renderizada se ‘foo’ is set to False.
Esta diretiva também pode ser usada como elemento. Nesse caso<py:if> deve ser fechado pelo correspondente </py:if>
<div>
<py:if test = "foo">
<b>${bar}</b>
</py:if>
</div>
py: escolha
O processamento condicional avançado é possível com o uso de py:choose em combinação com py:when e py:otherwisediretivas. Este recurso é semelhante aswitch – case construir em C/C++.
Expressão em py:choose diretiva é verificada com diferentes valores identificados com py:whenalternativas e conteúdos correspondentes serão processados. Uma alternativa padrão pode ser fornecida na forma depy:otherwise diretiva.
<div py:choose = "foo”>
<span py:when = "0">0</span>
<span py:when = "1">1</span>
<span py:otherwise = "">2</span>
</div>
O exemplo a seguir ilustra o uso de py:choose e py:whendiretivas. O formulário HTML envia dados para /marks URL. omarks() função redireciona marcas e resultados na forma de um objeto de dicionário para total.htmlmodelo. A exibição condicional deresult Pass/Fail é conseguido usando py:choose e py:when diretivas.
Script HTML de marcas de entrada (marks.html) é o seguinte -
<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>
O código completo de root.pyé o seguinte. omarks() controlador está enviando marcas e resultados para total.html modelo -
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
o total.html na pasta de modelos recebe dados do dicionário e os analisa na saída html condicionalmente da seguinte forma -
<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>
Inicie o servidor (se ainda não estiver em execução)
Gearbox server –reload –debug
Entrar http://localhost::8080/marksform no navegador -
o total.html irá renderizar a seguinte saída -
py: para
O elemento na diretiva py: for é repetido para cada item em um iterável, normalmente um objeto List Python. E seitems = [1,2,3] está presente em um contexto de modelo, ele pode ser iterado seguindo py: para diretiva -
<ul>
<li py:for = "item in items">${item}</li>
</ul>
A seguinte saída será renderizada -
1
2
3
O exemplo a seguir mostra os dados do formulário HTML renderizados no modelo total.html usando a diretiva py: for também pode ser usada da seguinte maneira -
<py:for each = "item in items">
<li>${item}</li>
</py:for>
Script de formulário 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>
o loop() o controlador lê os dados do formulário e os envia para total.template na forma de um objeto de lista.
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})
O modelo temp.html usa o loop py: for para renderizar o conteúdo do objeto dict na forma de uma tabela.
<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>
Inicie o servidor (se ainda não estiver em execução)
gearbox server –reload –debug
Entrar http://localhost::8080/marksform no navegador.
A seguinte saída será exibida no navegador quando o formulário acima for enviado.
py: def
Esta diretiva é usada para criar uma macro. Uma macro é um fragmento reutilizável de código de modelo. Muito parecido com uma função Python, tem um nome e pode opcionalmente ter parâmetros. A saída dessa macro pode ser inserida em qualquer lugar de um modelo.
A diretiva py: def segue a seguinte sintaxe -
<p py:def = "greeting(name)">
Hello, ${name}!
</p>
Esta macro pode ser renderizada com um valor variável para o parâmetro 'nome'.
${greeting('world')} ${greeting('everybody)}
Esta diretiva também pode ser usada com outra versão da sintaxe da seguinte forma -
<py:def function = "greeting(name)">
<p>Hello, ${name}! </p>
</py:def>
No exemplo a seguir, macro() controlador em root.py envia um dict objeto com duas chaves name1 e name2 para macro.html template.
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'}
Este modelo macro.html contém a definição de uma macro chamada saudação. É usado para gerar mensagem de saudação para dados recebidos do controlador.
<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>
Inicie o servidor usando a caixa de engrenagens
gearbox serve –reload –debug
Invoque o controlador de macro () inserindo a seguinte URL no navegador -
http://localhost:8080/macro
A saída a seguir será renderizada no navegador -
py: com
Esta diretiva permite atribuir expressões a variáveis locais. Essas variáveis locais tornam a expressão interna menos detalhada e mais eficiente.
Supondo que x = 50 seja fornecido nos dados de contexto de um modelo, o seguinte será o py: com diretiva -
<div>
<span py:with = "y = 50; z = x+y">$x $y $z</span>
</div>
Isso resultará na seguinte saída -
50 50 100
Uma versão alternativa para py: com diretiva também está disponível -
<div>
<py:with = "y = 50; z = x+y">$x $y $z</py:with>
</div>
No exemplo a seguir, o controlador macro () retorna um objeto dict com as chaves name, phy e maths.
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}
O modelo macro.html adiciona valores de chaves phy e matemáticas usando a diretiva 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>
O navegador irá renderizar a seguinte saída em resposta ao URL http://localhost:8080/macro
Diretivas de manipulação de estrutura
o py:attrs diretiva adiciona, modifica ou remove atributos do elemento.
<ul>
<li py:attrs = "foo">Bar</li>
</ul>
E se foo = {‘class’:’collapse’} está presente em um contexto de modelo, que o snippet acima renderizará.
<ul>
<li class = "collapse">Bar</li>
</ul>
o py:content diretiva substitui qualquer conteúdo aninhado com o resultado da avaliação da expressão -
<ul>
<li py:content = "bar">Hello</li>
</ul>
Dado bar = 'Tchau' nos dados de contexto, isso produziria
<ul>
<li>Bye</li>
</ul>
o py:replace diretiva substitui o próprio elemento com o resultado da avaliação da expressão -
<div>
<span py:replace = "bar">Hello</span>
</div>
Dado bar = 'Tchau' nos dados de contexto, produziria
<div>
Bye
</div>
O conteúdo de outro documento XML (especialmente documento HTML) pode ser incluído usando tags de inclusão no documento atual. Para permitir tal inclusão, o namespace XInclude deve ser declarado no elemento raiz do documento HTML.
<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:xi = "http://www.w3.org/2001/XInclude >
A declaração acima especifica que a diretiva include contém ‘xi’prefixo. Para adicionar conteúdo de outra página html no documento atual, use a diretiva xi: include da seguinte forma -
<xi:include href = "somepage.html" />
No exemplo a seguir, root.py contém o controlador include (), que expõe include.html.
from hello.lib.base import BaseController
from tg import expose, request
class RootController(BaseController):
@expose('hello.templates.include')
def include(self):
return {}
HTML de cabeçalho e rodapé
Em include.html, o namespace include é declarado e os conteúdos de header.html e footer.html são adicionados. Aqui está o script HTML de templates \ include.html -
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:xi = "http://www.w3.org/2001/XInclude">
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<xi:include href = "heading.html" />
<h2>main content </h2>
<xi:include href = "footer.html" />
</body>
</html>
Aqui está o código templates \ header.html -
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h1>This is page Header</h1>
</body>
</html>
A seguir está o templates \ footer.html
<html>
<head>
<title>TurboGears Templating Example</title>
</head>
<body>
<h3>This is page footer</h3>
</body>
</html>
Comece o desenvolvimento usando uma caixa de engrenagens e entre http://localhost:8080/includeno navegador. A saída renderizada será como mostrado abaixo -
Desta forma, a construção modular das vistas pode ser alcançada. Se o recurso mencionado na diretiva xi: include não estiver disponível, um erro será gerado. Nesse caso, um recurso alternativo pode ser carregado usando xi: fallback.
<xi:include href = “main.html”>
<xi:fallback href = ”default.html”/>
</xi.include>
A inclusão de conteúdo pode ser tornada dinâmica como um atributo href que pode conter expressões.
Adicione o seguinte controlador em root.py.
@expose('hello.templates.ref-include')
def refinclude(self):
return {'pages':['heading','main','footer']}
Salve o código a seguir como ref-include.html na pasta de modelos.
<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>
Antes de iniciar o servidor, certifique-se de que a pasta de modelos tenha um header.html, main.html e footer.html. Entrarhttp://localhost:8082/refinclude no navegador para obter o seguinte resultado
o @expose()decorator por padrão renderiza o conteúdo html. No entanto, isso pode ser definido comojson content type. TurboGears suporta renderização json através detg.jsonify.JSONEncoder (**kwargs)classe. Para renderizar dados json, simplesmente passe json como tipo de conteúdo para expor o decorador.
@expose('json')
def jsondata(self, **kwargs):
return dict(hello = 'World')
Se o URL '/ jsondata' for inserido no navegador, ele responderá mostrando -
{"hello": "World"}
Renderização jsonp
jsonp significa json com preenchimento. Ele funciona de forma semelhante à saída json, exceto pelo fato de que fornece uma resposta de aplicativo / javascript com uma chamada para uma função javascript fornecendo todos os valores retornados pelo controlador como argumentos de função.
Para habilitar a renderização jsonp, você deve primeiro anexá-lo à lista de motores necessários dentro de seu aplicativo - config/app_cfg.py -
base_config.renderers.append('jsonp')
Escreva seu decorador de exposição da seguinte maneira -
@expose('json')
@expose('jsonp')
def jsonpdata (self, **kwargs):
return dict(hello = 'World')
Ao acessar / jsonpdata? Callback = callme, você verá -
callme({"hello": "World"});
Às vezes, um aplicativo da web pode exigir uma estrutura de URL com mais de um nível. O TurboGears pode percorrer a hierarquia de objetos para encontrar o método apropriado que pode lidar com sua solicitação.
Um projeto de 'início rápido' com caixa de engrenagens tem uma classe BaseController na pasta lib do projeto. Ele está disponível como 'Hello / hello / lib / base.py'. Ele serve como classe base para todos os subcontroladores. Para adicionar um subnível de URL no aplicativo, projete uma subclasse chamada BlogController, derivada de BaseController.
Este BlogController tem duas funções de controlador, index () e post (). Ambos são projetados para expor um modelo cada, blog.html e post.html.
Note - Esses modelos são colocados dentro de uma subpasta - modelos / 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}
Agora declare um objeto desta classe na classe RootController (em root.py) da seguinte maneira -
class RootController(BaseController):
blog = BlogController()
Outras funções de controlador para URLs de nível superior estarão presentes nesta classe como anteriormente.
Quando um URL http://localhost:8080/blog/for inserido, ele será mapeado para a função do controlador index () dentro da classe BlogController. Similarmente,http://localhost:8080/blog/post irá invocar a função post ().
O código para blog.html e post.html é o seguinte -
Blog.html
<html>
<body>
<h2>My Blog</h2>
</body>
</html>
post.html
<html>
<body>
<h2>My new post dated $date</h2>
</body>
</html>
Quando um URL http://localhost:8080/blog/ for inserido, ele produzirá a seguinte saída -
Quando um URL http://localhost:8080/blog/post for inserido, ele produzirá a seguinte saída -
Um dos aspectos mais essenciais de qualquer aplicativo da web é apresentar a interface do usuário para um usuário. HTML fornece uma tag <form> que é usada para projetar uma interface. Os elementos do formulário, como entrada de texto, rádio, seleção, etc., podem ser usados de forma adequada. Os dados inseridos pelo usuário são enviados na forma de mensagem de solicitação Http para o script do lado do servidor pelo método GET ou POST.
O script do lado do servidor precisa recriar os elementos do formulário a partir dos dados do pedido http. Portanto, neste caso, os elementos do formulário devem ser definidos duas vezes - uma vez em HTML e novamente em script do lado do servidor.
Outra desvantagem de usar o formulário HTML é que é difícil (se não impossível) renderizar os elementos do formulário dinamicamente. O próprio HTML não fornece nenhuma maneira de validar a entrada do usuário.
ToscaWidgets2
O TurboGears depende do ToscaWidgets2, uma biblioteca flexível de validação e renderização de formulários. Usando ToscaWidgets, podemos definir os campos do formulário em nosso script Python e renderizá-los usando um modelo HTML. Também é possível aplicar validação ao campo tw2.
A biblioteca ToscaWidgets é uma coleção de muitos módulos. Alguns módulos importantes estão listados abaixo -
tw2.core- Fornece funcionalidades básicas. Os widgets neste módulo não devem estar disponíveis para o usuário final.
tw2.forms- Esta é uma biblioteca de formulários básicos. Ele contém widgets para campos, conjuntos de campos e formulários.
tw2.dynforms - Contém funcionalidade de formulários dinâmicos.
tw2.sqla - Esta é uma interface para o banco de dados SQLAlchemy.
tw2.forms
Ele contém uma classe Form, que atua como uma base para formulários personalizados. Existe uma classe TableForm que é útil para renderizar campos em uma tabela de duas colunas. ListForm apresenta seus campos em uma lista não ordenada.
Sr. Não. | Campos e Descrição |
---|---|
1 | TextField Um campo de entrada de texto de linha única |
2 | TextArea Campo de entrada de texto multilinha |
3 | CheckBox Apresenta uma caixa retangular marcável com etiqueta |
4 | CheckBoxList Caixas de seleção de pf de grupo multi-selecionável |
5 | RadioButton Um botão de alternância para selecionar / desmarcar |
6 | RadioButtonList Grupo de botões de rádio mutuamente exclusivos |
7 | PasswordField Semelhante ao campo de texto, mas as chaves de entrada não são reveladas |
8 | CalendarDatePicker Permite ao usuário escolher uma data |
9 | SubmitButton Botão para enviar um formulário |
10 | ImageButton Botão clicável com uma imagem no topo |
11 | SingleSelectField Permite a seleção de um único item de uma lista |
12 | MultipleSelectField Permite a seleção de vários itens da lista |
13 | FileField Campo para upload de arquivo |
14 | EmailField Um campo de entrada de e-mail |
15 | URLField Um campo de entrada para inserir o URL |
16 | NumberField Um número spinbox |
17 | RangeField Um controle deslizante de número |
No exemplo a seguir, um formulário usando alguns desses widgets é construído. Enquanto a maioria desses widgets são definidos em tw2.forms, CalendarDateField é definido no módulo tw2.Dynforms. Portanto, esses dois módulos juntamente com tw2.core são importados no início -
import tw2.core as twc
import tw2.forms as twf
import tw2.dynforms as twd
Um formulário ToscaWidgets é uma classe derivada de tw2.forms.formclasse base. Os widgets necessários são colocados dentro de um objeto Layout. Neste exemplo,TableLayouté usado. Os Widgets são renderizados em uma tabela de duas colunas. A primeira coluna mostra a legenda e a segunda coluna mostra o campo de entrada ou seleção.
Um objeto TextField é criado usando o seguinte construtor -
twf.TextField(size, value = None)
Se não for mencionado, o objeto TextField assume um tamanho padrão e fica inicialmente em branco. Ao declarar o objeto TextArea, o número de linhas e colunas pode ser mencionado.
twf.TextArea("",rows = 5, cols = 30)
O objeto NumberField é um TextField que pode aceitar apenas dígitos. Setas para cima e para baixo são geradas na borda direita para aumentar ou diminuir o número dentro dela. O valor inicial também pode ser especificado como um argumento no construtor.
twf.NumberField(value)
À direita de uma caixa CalendarDatePicker, um botão de calendário é exibido. Quando pressionado, um seletor de data é exibido. O usuário pode digitar manualmente uma data na caixa ou selecionar no seletor de data.
twd.CalendarDatePicker()
O objeto EmailField apresenta um TextField, mas o texto nele deve estar no formato de e-mail.
EmailID = twf.EmailField()
O formulário a seguir também possui uma RadioButtonList. O construtor desta classe contém um objeto List como um valor do parâmetro options. Um botão de rádio para cada opção será renderizado. A seleção padrão é especificada com o parâmetro value.
twf.RadioButtonList(options = ["option1","option2"],value = option1)
A CheckBoxList renderiza caixas de seleção para cada opção na lista.
twf.CheckBoxList(options = [option1, option2, option3])
A lista suspensa é chamada de SingleSelectfield nesta biblioteca ToscaWidgets. Os itens em um objeto de Lista correspondente ao parâmetro de opções formam a lista suspensa. A legenda visível é definida como um valor do parâmetro prompt_text.
twf.SingleSelectField(prompt_text = 'text', options=['item1', 'item2', 'item3'])
Por padrão, o formulário exibe um botão Enviar com sua legenda como 'salvar'. Para exibir outra legenda, crie um objeto SubmitButton e especifique-o como parâmetro de valor.
twf.SubmitButton(value = 'Submit')
O formulário é enviado para um URL, que é especificado como um valor do parâmetro de ação do formulário. Por padrão, os dados do formulário são enviados pelo método http POST.
action = 'URL'
No código a seguir, um formulário denominado AdmissionForm é projetado usando os widgets explicados acima. Adicione este código em root.py antes da classe 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')
Agora salve este código abaixo como twform.html no diretório de modelos -
<!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>
Na classe RootController (em root.py), adicione a seguinte função de controlador -
@expose('hello.templates.twform')
def twform(self, *args, **kw):
return dict(page = 'twform', form = MovieForm)
Na classe AdmissionForm, temos stipulated/save_formcomo URL de ação. Portanto, adicionesave_form() função no RootController.
@expose()
def save_movie(self, **kw):
return str(kw)
Certifique-se de que o servidor está funcionando (usando o serviço da caixa de câmbio) Entrarhttp://localhost:8080/twform no navegador.
Pressionar o botão enviar postará esses dados em save_form() URL, que exibirá os dados do formulário na forma de um objeto de dicionário.
{
'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'
}
Uma boa biblioteca de widgets de Formulários deve ter um recurso de validação de entrada. Por exemplo, o usuário deve ser forçado a inserir dados em um campo obrigatório, ou verificar se um campo de email contém um email válido, sem recorrer a nenhum outro meio programático (como função JavaScript) para validação.
As primeiras versões da Biblioteca de Formulários ToscaWidgets costumavam contar com o módulo FormEncode para suporte de validação. ToscaWidgets2 agora tem suporte de validação embutido disponível no módulo tw2.core. No entanto, ainda é possível usar técnicas de validação de FormEncode.
Para submeter um formulário ToscaWidgets à validação, o decorador @validate é usado.
@validate(form, error_handler, validators)
o ’form’ é o objeto de formulário ToscaWidgets a ser validado.
o ‘error-handler’ é o método do controlador usado para lidar com erros de formulário.
o ‘validators’ são um objeto de dicionário contendo validadores FormEncode.
Tipos de validadores
O módulo tw2.core contém uma classe validadora da qual outros validadores são herdados. Também é possível projetar um validador personalizado com base nele. Alguns dos validadores importantes são descritos abaixo -
LengthValidator- Verifique se um valor tem um comprimento prescrito. Os limites mínimo e máximo são definidos com os parâmetros mínimo e máximo. Mensagens personalizadas para comprimento abaixo e acima de mínimo e máximo podem ser especificadas como parâmetro tooshort e toolong.
tw2.core.LengthValidator(min = minval, max = maxval,
msgs = { 'tooshort': (‘message for short length’),
'toolong': (‘message for long length)})
RangeValidator- Normalmente usado com RangeField. É útil para validar o valor de um campo numérico dentro dos limites mínimo e máximo. Mensagens para parâmetros tooshort e toolong podem ser personalizadas.
tw2.core.RangeValidator(min = minval, max = maxval,
msgs = { 'tooshort': (‘message for short length’),
'toolong': (‘message for long length)})
IntValidator- Esta classe é derivada do RangeValidator. Isso normalmente é usado para validar se a entrada em um campo de texto normal contém dados inteiros. Limites mínimo e máximo, bem como mensagens de erro, podem ser definidos. Além disso, a mensagem de erro para entrada não inteira pode ser especificada como parâmetro 'notint'.
tw2.core.IntValidator(msgs = {‘notint’:’Must be Integer’})
OneOfValidator - Este validador força o usuário a selecionar um valor apenas das opções disponíveis na lista.
tw2.core.OneOfValidator(values = [option1, option2,..],
msgs = {‘notinlist’:’Not in List’}}
DateValidator- Muito útil para garantir que a entrada do usuário seja uma data válida. O formato da data (o padrão é YMD) e a mensagem de erro são personalizáveis. Os limites de data mínimo e máximo também podem ser especificados. DateTimeValidator também está disponível para verificar o objeto da classe DateTime.
tw2.core.DateValidator(msgs = {format = ’%Y-%m-%d’,
'baddatetime': ('baddate', ('Must follow date format $format_str'))}
EmailValidator- Valida a entrada do usuário em um endereço de e-mail válido. Esta classe é herdada de um RegexValidator mais geral.
tw2.core.EmailValidator(msgs = {'badregex': ('bademail',
('Must be a valid email address')) }
UrlValidator- Esta classe também é herdada de RegexValidator. Ele valida a entrada do usuário para um URL válido.
tw2.core.UrlValidator(msgs = {'badregex': ('badurl', ('Must be a valid URL’)) }
MatchValidator- Confirma se o valor de um campo é compatível com o outro. Isso é especialmente útil, quando o usuário precisa escolher e confirmar um campo de senha. O uso típico do MatchValidator é mostrado abaixo -
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()
Também é possível construir um validador composto, onde se deseja que a validação seja bem-sucedida, se alguma das verificações passar. Em outros casos, você pode querer que a validação seja bem-sucedida, apenas se a entrada passar em todas as verificações. Para isso, tw2.core fornece os validadores Any e All, que são subclasses do CompoundValidator extensível.
O TurboGears fornece um sistema de mensagens muito conveniente para notificar informações ao usuário de uma forma não intrusiva. A classe TGFlash no módulo tg fornece suporte para mensagens instantâneas armazenadas em um cookie simples. Esta classe oferece suporte à busca de mensagens flash no lado do servidor e também no lado do cliente por meio de JavaScript.
o render()O método da classe TGFlash, quando usado a partir do próprio Python, pode ser chamado a partir do modelo para renderizar uma mensagem flash. Se usado em JavaScript, fornece um objeto WebFlash. Expõepayload() e render() métodos para buscar a mensagem flash atual e renderizá-la em JavaScript.
Quando um projeto TurboGears é criado usando 'início rápido', ele tem um modelo Master.html. Ele contém a definição de uma variável desse objeto flash. O conteúdo desta mensagem flash recebida do controlador substitui o marcador de posição marcado neste modelo.
<py:with vars = "flash = tg.flash_obj.render('flash', use_js = False)">
<div py:if = "flash" py:replace = "Markup(flash)" />
</py:with>
o tg.flash_obj é o objeto WebFlash, que está disponível dentro de qualquer modelo renderizado, incluindo master.htmlmodelo. Este objeto permite recuperar a mensagem flash atual e exibi-la.
As mensagens Flash são armazenadas em um cookie (cujo nome por padrão é webflash) usando tg.flash()método. Os parâmetros de mensagem e status são então passados para ele.
tg.flash('Message', 'status')
Se o método chamado flash realizar um redirecionamento, o flash ficará visível dentro da página redirecionada. Se o método expõe diretamente um modelo, o flash ficará visível dentro do próprio modelo.
A aparência da mensagem flash pode ser personalizada aplicando o estilo CSS ao código de status. Um projeto de 'início rápido' contém códigos de erro, aviso, informações e status ok personalizados por uma folha de estilo public / css / style.css. Mais códigos de status com estilos também podem ser adicionados.
#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;
}
Esta folha de estilo externa precisa ser incluída no modelo -
<link rel = "stylesheet" type = "text/css" media = "screen"
href = "${tg.url('/css/style.css')}" />
A configuração de qualquer suporte de mensagem Flash pode ser obtida definindo parâmetros para o método configure () do objeto TGFlash ou em app_cfg.py (na pasta config). Os parâmetros configuráveis são -
Sr. Não. | Parâmetros e descrição |
---|---|
1 | flash.cookie_name Nome do cookie usado para armazenar mensagens flash. O padrão éwebflash. |
2 | flash.default_status Status da mensagem padrão se não for especificado (ok por padrão) |
3 | flash.template Usado como o flash template quando renderizado. |
4 | flash.allow_html Turns on/off escaping in flash messages, por padrão, HTML não é permitido. |
5 | flash.js_call Código JavaScript que será executado ao exibir o flash do JavaScript. O padrão éwebflash.render() |
6 | flash.js_template string.Template instância usada para substituir o suporte JavaScript completo para mensagens flash. |
pop_payload() - função fetches current flash message, statuse informações relacionadas. Receber a mensagem flash excluirá o cookie.
render(container_id, use_js=True) - Renderize a mensagem flash dentro do template ou forneça suporte Javascript para eles.
container_id é o DIV onde as mensagens serão exibidas, enquanto use_js alterna entre renderizar o flash como HTML ou para uso de JavaScript.
status - Obtenha apenas o status do flash atual, obter o status do flash excluirá o cookie.
message - Obter apenas a mensagem flash atual, obter a mensagem flash excluirá o cookie.
Como fazer uma mensagem flash simples?
No exemplo a seguir, um método flash () é fornecido na classe do controlador raiz. Ele chama uma mensagem flash () que é renderizada no modelo exposto, 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 {}
O código para fazer flash.html na pasta de modelos é a seguinte
<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>
Inicie o servidor e entre http://localhost:8080/flash?user=MVL no navegador
Alterar URL para http://localhost:8080/flash e veja a mensagem flash formatada de forma diferente de acordo com a definição em style.css
Freqüentemente, é necessário manter dados de navegação simples anexados ao navegador do usuário. As sessões são a técnica mais comumente usada. A sessão representa os dados que não precisam ser armazenados de uma forma mais persistente, como arquivo de disco ou banco de dados.
No entanto, os dados da sessão no TurboGears podem ser apoiados pelo sistema de arquivos, banco de dados ou valores de cookies com hash. Uma pequena quantidade de dados de sessão geralmente é mantida em cookies, mas para o maior volume de dados de sessão, MemCache é usado.
MemCache é um daemon no nível do sistema. Ele fornece acesso rápido aos dados armazenados em cache e é extremamente escalonável. No entanto, ele deve ser usado apenas em servidores seguros e, portanto, deve ser mantido e protegido pelo administrador do sistema.
Copo no gerenciamento de sessão
O TurboGears usa o Beaker para gerenciamento de sessão. Um projeto de início rápido por caixa de engrenagens é, por padrão, configurado para usar cookies com hash para armazenar dados da sessão.
Cada vez que um cliente se conecta, o middleware de sessão (Beaker) inspeciona o cookie usando o nome do cookie, que foi definido no arquivo de configuração. Se o cookie não for encontrado, ele será definido no navegador. Em todas as visitas subsequentes, o middleware encontrará o cookie e o utilizará.
A fim de habilitar o gerenciamento de sessão, a classe de sessão deve ser incorporada ao projeto seguindo a instrução de importação -
from tg import session
Para salvar os dados em uma variável de sessão -
session[‘key’] = value
session.save()
Para recuperar a variável de sessão -
return session[‘key’]
Observe que você precisa salvar explicitamente a sessão para que suas chaves sejam armazenadas nessa sessão.
o delete() método do objeto de sessão irá apagar todas as sessões do usuário -
session.delete()
Mesmo que não seja comum excluir todas as sessões de usuário em um determinado ambiente de produção, você normalmente fará isso para limpeza após a execução dos testes de usabilidade ou funcional.
Abaixo está um exemplo simples para demonstrar as sessões. A classe RootController tem umsetsession() método que define uma variável de sessão.
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>"
Entrar http://localhost:8080/setsession
Um link no navegador leva a http://localhost:8080/getsession que recupera e exibe a variável de sessão -
A fim de aprimorar o desempenho de um aplicativo da web, especialmente se ele estiver envolvido em operações demoradas, são utilizadas técnicas de cache. TurboGears oferece dois tipos de técnicas de cache -
Whole-page Caching
Ele funciona no nível do protocolo HTTP para evitar solicitações inteiras ao servidor, fazendo com que o navegador do usuário ou um servidor proxy intermediário (como o Squid) intercepte a solicitação e retorne uma cópia em cache do arquivo.
Application-level Caching
Isso funciona dentro do servidor de aplicativos para armazenar valores calculados em cache, geralmente os resultados de consultas complexas de banco de dados, de forma que solicitações futuras possam evitar a necessidade de recalcular os valores. Para aplicativos da web, o armazenamento em cache no nível do aplicativo fornece uma maneira flexível de armazenar em cache os resultados de consultas complexas para que a carga total de um determinado método do controlador possa ser reduzida a algumas consultas específicas do usuário ou específicas do caso e o overhead de renderização de um modelo .
Cache em nível de aplicativo
Conforme mencionado anteriormente, o projeto TurboGears de 'início rápido' é configurado para habilitar o pacote Beaker para suporte de cache. O copo suporta os seguintes back-ends usados para armazenamento em cache -
memory- Usado para armazenamento por processo. É extremamente rápido.
filesystem - armazenamento por processo, bem como multi-processo.
DBM database - por processo, multiprocesso, bastante rápido.
SQLAlchemy database- armazenamento por servidor de banco de dados. Mais lento em comparação com as opções fornecidas acima.
Memcached - cache baseado em memória multi-servidor.
Cache de controlador
Para armazenamento em cache do controlador rápido, um cached()decorador está disponível. Todo o corpo do controlador é armazenado em cache dependendo de vários parâmetros da solicitação. A definição detg.decorators.cached() decorador é o seguinte
tg.decorators.cached(key, expire, type,
query-args, cache_headers, invalidate_on_startup, cache_response)
A descrição dos parâmetros é a seguinte -
Sr. Não. | Parâmetros e descrição |
---|---|
1 | key Especifica os parâmetros do controlador usados para gerar a chave do cache. |
2 | expire Tempo em segundos antes que o cache expire. O padrão é “nunca”. |
3 | Type dbm, memória, arquivo, memcached ou nenhum. |
4 | cache_headers Uma tupla de nomes de cabeçalho indicando cabeçalhos de resposta. |
5 | invalidate_on_startup Se for True, o cache é invalidado toda vez que o aplicativo é iniciado ou reiniciado. |
6 | cache_response a resposta deve ser armazenada em cache ou não, o padrão é True. |
A seguir está um exemplo de armazenamento em cache do controlador -
@cached(expire = 100, type = 'memory')
@expose()
def simple(self):
return "This is a cached controller!"
Cache de nível de modelo
O mecanismo de modelo Genshi recupera o modelo de um cache se seu conteúdo não foi alterado. O tamanho padrão desse cache é 25. Por padrão, o recarregamento automático de modelos é verdadeiro. Para melhorar o desempenho, as seguintes configurações podem ser feitas emapp_cfg.py -
[app:main]
genshi.max_cache_size = 100
auto_reload_templates = false
Para armazenar em cache um modelo, você só precisa retornar o tg_cache opção do controlador que renderiza o modelo em cache.
O tg_cache é um dicionário que aceita as seguintes chaves -
key - A chave do cache. Default: Nenhum.
expire - quanto tempo o cache deve permanecer ativo. Default: nunca expira
type - memória, dbm, memcached. Default: dbm.
O exemplo a seguir ilustra o cache de modelo -
@expose(hello.templates.user')
def user(self, username):
return dict(user = username, tg_cache = dict(key = user, expire = 900))
Embora seja possível usar SQL no aplicativo TurboGears para executar operações CRUD em qualquer banco de dados relacional, é aconselhável usar SQLAlchemy, um kit de ferramentas Python é um mapeador de relação de objeto poderoso que oferece aos desenvolvedores de aplicativos todo o poder e flexibilidade do SQL. Além do suporte para bancos de dados baseados em SQL por meio de SQLAlchemy, o TurboGears também oferece suporte a banco de dados MongoDB por meio de Ming. Nesta seção, a funcionalidade do SQLAlchemy é discutida.
O que é ORM (Object Relational Mapping)?
A maioria das plataformas de linguagem de programação são orientadas a objetos. Os dados nos servidores RDBMS, por outro lado, são armazenados como tabelas. O mapeamento de relação de objeto é uma técnica de mapear parâmetros de objeto para a estrutura de tabela RDBMS subjacente. Uma API ORM fornece métodos para realizar operações CRUD sem a necessidade de escrever instruções SQL brutas.
Quando um projeto TurboGears é criado usando o comando 'quickstart' do kit de ferramentas da caixa de engrenagens, o suporte SQLAlchemy é habilitado por padrão pelas seguintes configurações -
config['use_sqlalchemy'] = True
config['sqlalchemy.url'] = 'sqlite:///devdata.db'
O projeto de 'início rápido' também cria um pacote de modelos dentro dele. Por exemplo, um projeto 'Hello' terá Hello \ hello \ model. Os seguintes arquivos são criados neste pacote -
__init__.py- É aqui que o acesso ao banco de dados é configurado. Os objetos de modelo do aplicativo são importados neste módulo. Também possui um DBSession - um gerenciador de sessão global e também um DeclarativeBase, que é uma classe base para todas as classes do modelo.
auth.py- Aqui é onde os modelos usados pela pilha de autenticação são definidos. Modelos de banco de dados adicionais são armazenados neste pacote, como um módulo separado, e adicionados no __init__.py.
Vamos adicionar um modelo de aluno que irá configurar uma mesa de aluno em nosso sqlite base de dados.
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 = '')
Agora adicione este modelo em init_model() função dentro __init__.py.Esta função já contém o modelo de autenticação nela. Adicione nosso modelo de aluno abaixo dele.
# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student
Se você deseja que a tabela seja inicializada com alguns dados no momento de configurar os modelos, adicione-a em bootstrap.py no pacote websetup. Adicione as seguintes declarações nobootstrap() função.
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()
Os modelos são inicializados executando o comando setup-app da caixa de câmbio -
gearbox setup-app
O objeto de sessão de SQLAlchemy gerencia todas as operações de persistência do objeto ORM.
Os seguintes métodos de sessão realizam operações CRUD -
DBSession.add(model object) - insere um registro na tabela mapeada.
DBSession.delete(model object) - exclui o registro da tabela.
DBSession.query(model).all() - recupera todos os registros da tabela (correspondendo a uma consulta SELECT).
Você pode aplicar o filtro ao conjunto de registros recuperado usando um atributo de filtro. Por exemplo, a fim de recuperar registros com city = 'Hyderabad' na tabela de alunos, use a seguinte declaração -
DBSession.query(model.student).filter_by(city = ’Hyderabad’).all()
Veremos agora como interagir com os modelos por meio de URLs de controlador.
Primeiro, vamos projetar um formulário da ToscaWidgets para inserir os dados do aluno
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')
No RootController (root.py do aplicativo Hello), adicione a seguinte função de mapeamento '/ 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)
Salve o seguinte código HTML como studentform.html na pasta de modelos -
<!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>
Entrar http://localhost:8080/addno navegador após iniciar o servidor. O seguinte formulário de informações do aluno será aberto no navegador -
O formulário acima foi elaborado para ser enviado ao ‘/save_record’URL. Daí umsave_record() função precisa ser adicionada no root.pypara expô-lo. Os dados do formulário do aluno são recebidos por esta função como umdict()objeto. É usado para adicionar um novo registro à tabela do aluno subjacente ao modelo do aluno.
@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")
Observe que após a adição bem-sucedida, o navegador será redirecionado para ‘/listrec’ URL. Este URL é exposto por umlistrec() function. Esta função seleciona todos os registros na tabela de alunos e os envia na forma de um objeto dict para o modelo studentlist.html. estelistrec() função é a seguinte -
@expose ("hello.templates.studentlist")
def listrec(self):
entries = DBSession.query(student).all()
return dict(entries = entries)
O modelo studentlist.html itera através do objeto de dicionário de entradas usando a diretiva py: for. O modelo studentlist.html é o seguinte -
<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>
Agora revisite o http://localhost:8080/adde insira os dados no formulário. Ao clicar no botão enviar, o navegador será levado para studentlist.html. Ele também exibirá uma mensagem 'novo registro adicionado com sucesso'.
O ToscaWidgets contém um controle DataGrid que fornece uma maneira rápida de apresentar dados em forma tabular. O objeto DataGrid é declarado da seguinte maneira -
from tw2.forms import DataGrid
student_grid = DataGrid(fields = [('Name', 'name'),('City', 'city'),
('Address','address'), ('PINCODE', 'pincode')])
Agora, a função showgrid () recupera todos os registros na tabela do aluno e expõe os dados ao modelo grid.html. Primeiro, o código para a função showgrid () e, em seguida, o código grid.html é fornecido abaixo -
mostre as grades()
@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>
Os seguintes dados tabulares serão exibidos quando http://localhost:8080/showlist O URL é inserido no navegador -
O TurboGears fornece um decorador conveniente chamado paginate () para dividir a saída nas páginas. Este decorador é combinado com o decorador expose (). O decorador @Paginate () leva o objeto de dicionário do resultado da consulta como argumento. Além disso, o número de registros por página é decidido pelo valor do atributo items_per_page. Certifique-se de importar a função de paginação de tg.decorators em seu código.
Reescreva a função listrec () em root.py da seguinte forma -
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)
Os itens por página são definidos em três.
No modelo studentlist.html, a navegação de página é habilitada adicionando tmpl_context.paginators.entries.pager () abaixo da diretiva py: for. O código para este modelo deve ser o seguinte -
<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>
Entrar http://localhost:8080/listrecno navegador. A primeira página de registros na tabela é exibida. No topo desta tabela, links para números de página também são vistos.
Como adicionar suporte de paginação ao datagrid
Também é possível adicionar suporte de paginação a datagrid. No exemplo a seguir, datagrid paginado é projetado para exibir o botão de ação. Para ativar o botão de ação, o objeto datagrid é construído com o seguinte código -
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)))) ])
Aqui, o botão de ação está vinculado ao parâmetro de nome de cada linha na grade de dados.
Reescreva o showgrid() funcionar da seguinte forma -
@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)
O navegador mostra datagrid paginado da seguinte forma -
Ao clicar no botão Editar na terceira linha, ele redirecionará para o seguinte URL http://localhost:8080/edit?name=Rajesh+Patil
TurboGears fornece a extensão tgext.admin, que é alimentada por tgext.crud e sprox. Este Sprox é um pacote usado para a criação de widgets da web diretamente do esquema do banco de dados. Isso pode ser usado para criar automaticamente páginas de administração simples e é o kit de ferramentas que alimenta a página / admin nos aplicativos de início rápido recentemente.
Por padrão, o admin fornecerá um acesso gerado automaticamente a todos os modelos importados em seus modelos de projeto / __ init__.py.
Como criar o administrador do TurboGears
O administrador TurboGears padrão é criado como um objeto da classe AdminController -
from tgext.admin.controller import AdminController
class RootController(BaseController):
admin = AdminController(model, DBSession, config_type = TGAdminConfig)
Isso cria um administrador para todos os modelos com a configuração de administrador padrão do TurboGears.
Através do gerenciador, um usuário foi criado durante a fase de configuração. Agora, é possível obter acesso ao Administrador do TurboGears emhttp://localhost:8080/adminNa primeira vez que esta página for acessada, ela solicitará autenticação. Você pode simplesmente fornecer o nome de usuário e a senha do usuário que o comando setup-app criou para nós -
Username: manager
Password: managepass
Para fazer o login no projeto de início rápido, adicione as seguintes funções à classe 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)
Faça login no aplicativo de 'início rápido' depois de iniciar o servidor e visitar http://localhost:8080/logine, em seguida, insira as credenciais de gerente conforme exibido acima. O navegador exibirá uma página de administração como a mostrada abaixo -
A página mostra todos os modelos criados neste aplicativo. Você pode clicar em qualquer modelo para ver a lista de entradas nele -
O botão 'Novo' no topo desta datagrid permite que o registro seja adicionado. Da mesma forma, botões de ação para editar e excluir um registro também são fornecidos na coluna de ações deste datagrid. Uma caixa de pesquisa também é exibida para selecionar registros condicionalmente.
Um aplicativo TurboGears é criado por opções de início rápido e aplicativo de configuração do kit de ferramentas da caixa de engrenagens, que tem o suporte de autorização e autenticação habilitado por padrão. Os modelos declarados em auth.py são configurados e inicializados de acordo com os valores atribuídos em bootstrap.py.
Os seguintes modelos são declarados em auth.py -
Modelo de Usuário
O modelo de usuário contém o design de uma tabela tg_user. Esta tabela é usada pelo pacote repose.who. Este pacote repose.who é uma biblioteca de autenticação poderosa e extensível para aplicativos WSGI. A estrutura de um modelo de usuário é a seguinte -
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)
Este modelo de grupo contém a tabela de definição tg_group. Sua definição é dada em auth.py da seguinte forma -
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)
Outra permissão de modelo também é configurada, que contém a definição de permissão.
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))
No momento da configuração dos modelos, os seguintes dados são adicionados a essas tabelas -
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)
Modelo Predicado
O módulo de predicados no pacote tg contém definições para verificadores de predicado. Um predicado é uma condição que deve ser atendida para que o usuário possa acessar a fonte solicitada. Tal predicado, ou condição, pode ser feito de mais predicados - esses são chamados de predicados compostos. Os controladores de ação, ou controladores, podem ter apenas um predicado, seja único ou composto.
Se um usuário não estiver logado, ou não tiver as permissões adequadas, este verificador de predicado lança um 401 (HTTP não autorizado), que é capturado pelo middleware repoze.who para exibir a página de login permitindo que o usuário faça login e redirecionando o usuário de volta à página apropriada quando terminar.
As diferentes condições ou predicados definidos no módulo tg.predicates são -
Sr. Não. | Módulo tg.predicates e descrição |
---|---|
1 | All Verifique se todos os predicados especificados são atendidos |
2 | Any Verifique se pelo menos um dos predicados especificados é atendido |
3 | is_user Verifique se o nome de usuário do usuário autenticado é o especificado |
4 | in_group Verifique se o usuário pertence ao grupo específico. |
5 | in_all_groups Verifique se o usuário pertence a todos os grupos especificados. |
6 | in_any_group Verifique se o usuário pertence a pelo menos um dos grupos especificados. |
7 | is_anonymous Verifique se o usuário atual é anônimo. |
8 | has_permission Verifique se o usuário atual tem a permissão especificada. |
9 | has_all_permissions Verifique se o usuário atual recebeu todas as permissões especificadas. |
10 | has_any_permission Verifique se o usuário tem pelo menos uma das permissões especificadas. |
Por exemplo, se você tiver um predicado, que é grant access user belonging to customers group, então você pode usar o seguinte verificador de predicado integrado -
from tg.predicates import in_group
p in_group(‘customers’)
O seguinte verificador de predicado concederá acesso ao usuário 'root' ou a qualquer pessoa com permissão de 'gerenciamento' -
from tg.predicates import Any, is_user, has_permission
p = Any(is_user('root'), has_permission('manage'),
sg = 'Only administrators can remove blog posts')
O TurboGears também suporta bancos de dados de documentos MongoDB. Ele usa Ming, uma API Object Document Mapper. O uso de Ming é muito semelhante ao SQLAlchemy. A linguagem de consulta Ming torna possível portar o projeto TurboGears baseado em SQLAlchemy para Ming.
O que é PyMongo
PyMongo é uma distribuição Python que contém ferramentas para trabalhar com MongoDB. Ming estende PyMongo fornecendo -
- Modelos Declarativos
- Validação e conversão de esquema
- Evolução do esquema
- Implementação do Pure InMemory MongoDB
- Unidade de Trabalho
- Mapa de Identidade
- Relações Um-para-Muitos, Muitos-Para-Um e Muitos-Para-Muitos
Em primeiro lugar, você precisa baixar e instalar o MongoDB. A distribuição mais recente do MongoDB pode ser baixada emhttps://www.mongodb.org/downloads
No Windows, inicie o servidor MongoDB fornecendo a opção -dbpath -
C:\mongodb\bin>Mongod --dbpath d:\mongo
D:\mongo folderé designado para armazenar o banco de dados MongoDB. O servidor começa a escutar àshttp://localhost:27017. Agora, para iniciar o shell do MongoDB, use o seguinte comando -
C:\mongodb\bin>Mongo
Nosso ambiente MongoDB agora está pronto.
Agora crie um projeto TurboGears com a opção -ming -
gearbox quickstart --ming Hello
Este projeto de início rápido fornecerá uma camada de autenticação e autorização como a fornecida para a versão SQLAlchemy. Este aplicativo agora tentará se conectar a um servidor na porta 27017 na máquina local. O arquivo development.ini na pasta do projeto contém as seguintes configurações -
ming.url = mongodb://localhost:27017/
ming.db = hello
Configure o projeto usando o seguinte comando -
Python setup.py develop
A pasta do projeto contém a subpasta de modelos que contém os seguintes arquivos -
__init__.py - É aqui que o databaseo acesso está configurado. Suas coleções devem serimported into this module. Por exemplo, devemos adicionar a coleção do aluno neste pacote.
session.py - Este arquivo define o session of your database connection. Você precisará importar isso sempre que precisar declarar umMappedClass para especificar a sessão para perform queries.
auth.py - Este arquivo será criado, se você tiver enabled authentication and authorizationno início rápido. Ele define três coleçõesrepoze.who, que depende ainda de: Usuário, Grupo e Permissão.
Definindo sua coleção
Por padrão, TurboGears configura Ming em um modo declarativo. Isso é semelhante ao suporte declarativo SQLAlchemy e precisa que cada modelo herde da classe MappedClass.
O MappedClass requer que uma subclasse __mongometa__ esteja disponível dentro, o que fornece mais detalhes sobre o nome da coleção que armazena os documentos e a sessão usada para armazenar os documentos.
MappedClass também contém a definição de campos no documento. O módulo odm de Ming tem definições de diferentes tipos de propriedades de campo -
- FieldProperty
- ForeignIdProperty
- RelationProperty
o ming.schema module define os seguintes tipos de dados -
- 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
Para adicionar a coleção do aluno neste modelo, salve o seguinte código como student.py na pasta hello / models.
Olá \ 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 = ''))
Por fim, inclua este modelo em hello \ models \ __ init__.py
# Import your model modules here.
from hello.model.auth import User, Group, Permission
from hello.model.student import student
Para configurar esses modelos, execute o seguinte comando da caixa de engrenagens -
Gearbox setup-app
Inicie o servidor com o seguinte comando da caixa de velocidades -
Gearbox serve –reload –debug
Abra a página inicial deste aplicativo (http://localhost:8080/)e faça login com credenciais de gerente. A página de administração deste aplicativo mostrará a lista de modelos configurados. (faça login como gerente, senha para gerenciar)
A criação de coleções também pode ser verificada na interface da web do MongoDB, bem como no shell do MongoDB.
A ODMSession é usada para realizar várias operações de banco de dados usando as seguintes funções -
- model.query.find()
- model.query.find_and_modify()
- model.remove()
- model.update()
- model.flush()
Projetando um formulário ToscoWidget
Devemos agora projetar um formulário ToscoWidget para inserir os dados do aluno e adicioná-los à tabela subjacente ao modelo do aluno.
A seguir está o código para criar um studentform.py -
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')
Na URL '/ add' do controlador raiz do aplicativo que chama a função add (), que abrirá o formulário projetado acima no navegador. Seu botão de envio invoca a função save_record (). Ele recupera os dados do formulário e os salva na tabela do aluno e redireciona o aplicativo para a URL '/ listrec', que expõe o modelo da lista de alunos.
O root.py para esta atividade é o seguinte -
Olá / 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")
Os seguintes modelos são criados na pasta de modelos -
Hello \ 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>
Hello \ 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>
Reinicie o servidor e entre http://localhost:8080/add no navegador -
Cada vez que os dados são adicionados e o botão enviar é pressionado, a lista de entradas atuais será exibida.
O kit de ferramentas Gearbox contém o comando scaffold, que é muito útil para criar rapidamente novos componentes do aplicativo TurboGears. Uma aplicação gerada pelo comando de início rápido da caixa de engrenagens possui um template de esqueleto na pasta model (model.py.template), uma pasta de templates (template.html.template) e uma pasta de controladores (controller.py.template). Esses arquivos '.template' são usados como base para a criação de novos scaffolds para um aplicativo
Por exemplo, para criar um novo modelo chamado mymodel, basta executar o seguinte comando -
gearbox scaffold model mymodel
Este comando irá gerar model / mymodel.py com a classe newmodel definida nele.
# -*- 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']
Os usuários agora podem fazer modificações na estrutura da tabela de acordo com suas necessidades e, em seguida, importá-la dentro model/__init__.py para disponibilizar o modelo dentro do aplicativo.
Para criar um modelo, uma classe de controlador para tratá-lo e uma página de índice de todos esses três componentes podem ser criados simultaneamente pelo comando a seguir.
gearbox scaffold model controller template mymodel
Este comando resultará em controllers \ mymodel.py no qual a classe MymodelController está devidamente definida.
# -*- 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')
Para começar a usar este controlador, monte-o dentro de sua aplicação RootController apenas para definir uma instância de MymodelController. Adicione essas linhas no arquivo controllers \ root.py -
From hello.controller.mymodel import MymodelController
class RootController(BaseController): mymodel = MymodelController()
Um scaffold template templates \ mymodel.html também será criado na pasta de templates. Ele funcionará como uma página de índice para a URL '/ mymodel'.
O gerado mymodel.html file na pasta de modelos será a seguinte -
<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>
Existem três maneiras no TurboGears de conectar comportamentos dentro dos aplicativos existentes.
Hook - É um mecanismo pelo qual é possível definir um evento e notificar os ouvintes registrados à medida que os eventos são emitidos.
Controller Wrapper- Ele fica entre o TurboGears e o controlador, de modo que é possível estender o controlador como um decorador. Portanto, ele pode ser anexado a qualquer aplicativo de controlador de terceiros.
Application Wrapper - É semelhante a qualquer middleware WSGI, mas funciona apenas no contexto do TurboGears.
Aqui neste capítulo, discutiremos como usar ganchos dentro de um aplicativo existente.
Ganchos
Ganchos são eventos registrados no arquivo de configuração do aplicativo app_cfg.py. Qualquer controlador é então conectado a esses eventos por decoradores de eventos.
Os seguintes ganchos são definidos no TurboGears -
Sr. Não. | Ganchos e descrição |
---|---|
1 | Startup() apenas em todo o aplicativo, chamado quando o aplicativo é iniciado. |
2 | shutdown() somente em todo o aplicativo, chamado quando o aplicativo é encerrado. |
3 | configure_new_app novo aplicativo foi criado pelo configurador de aplicativos. |
4 | before_config(app) apenas em todo o aplicativo, chamado logo após a criação do aplicativo, mas antes de configurar opções e middleware |
5 | after_config(app) apenas em todo o aplicativo, chamado após terminar de configurar tudo. |
6 | before_validate Chamado antes de realizar a validação |
7 | before_call Chamado após a validação, antes de chamar o método do controlador real. |
8 | before_render Chamado antes de renderizar um template de controlador, output é o valor de retorno do controlador. |
9 | after_render Chamado após terminar a renderização de um template de controlador. |
Registrar um gancho
A fim de register a Hook, criar funções em app_cfg.py e depois registrá-los usando o seguinte código -
tg.hooks.register(hookane, function, controller)
No código a seguir, os ganchos on_startup, on_shutdown e before_render são registrados em 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)
O gancho before_render é registrado com uma função de controlador no Rootcontroller. Adicione o seguinte código em 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')
Quando o aplicativo é servido, a mensagem de inicialização é exibida no console.
hello, startup world
Starting Standard HTTP server on http://127.0.0.1:8080
Quando '/' URL é inserido no navegador, uma mensagem correspondente ao gancho before_render é exibida no console.
system wide before render
Going to render {'page': 'index'}
As extensões do TurboGears são identificadas por tgext.* package. Um kit de ferramentas Gearbox fornece o comando tgext para criar uma extensão de amostra. Por exemplo -
gearbox tgext -n myextension
Outros parâmetros opcionais para este comando são -
--author - nome do autor do pacote.
--email - email do autor do pacote.
--licence- licença usada para o pacote. O padrão é MIT.
--description - Descrição do pacote.
--keywords - Palavras-chave do pacote (padrão: turbogears2.extension).
Isso criará um diretório tgext.myextension, que contém uma extensão de amostra simples.
Run the setup.py dentro do diretório -
Python setup.py install
o _init_.py arquivo dentro tgext/myextension pasta contém -
Plugme function - Este é o ponto de entrada da extensão.
SetupExtension class - a inicialização da extensão ocorre aqui.
On_startup function - dentro da classe está um gancho registrado na função __call__ dentro da classe.
Breve versão do 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!')
Assim que a extensão for instalada, ligue-a fazendo as seguintes adições no aplicativo app_cfg.py arquivo de configuração.
from tgext.myextension import plugme
plugme(base_config)
Se iniciarmos o servidor usando um comando de servidor de caixa de engrenagens, a notificação de uma extensão recém-registrada pode ser vista no console da seguinte forma -
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
Se sua extensão precisa expor modelos e controladores, você provavelmente deseja dar uma olhada no Pluggable Applications, que têm como objetivo criar aplicativos Turbogears reutilizáveis que podem ser conectados a outros aplicativos para estender seus recursos.
Use o seguinte comando de caixa de engrenagens para criar um aplicativo plugável -
gearbox quickstart-pluggable plugtest
Esses aplicativos plugáveis podem definir seus próprios -
Controllers - que será montado automaticamente quando o aplicativo for removido.
Models - que estará disponível dentro e fora do aplicativo conectado.
Helpers - que pode ser automaticamente exposta no objeto 'H' em um modelo de aplicativo.
Bootstrap - que será executado quando setup-app for chamado.
Statics - que estará disponível em seu próprio caminho privado.
Instale este aplicativo de teste e monte-o fazendo as seguintes modificações em app_cfg.py.
from tgext.pluggable import plug
plug(base_config, plugtest)
REST significa REapresentacional STate Transfer. REST é uma arquitetura baseada em padrões da web e usa protocolo HTTP para comunicação de dados. Ele gira em torno de um recurso onde cada componente é um recurso e um recurso é acessado por uma interface comum usando métodos padrão HTTP. REST foi introduzido pela primeira vez porRoy Fielding in 2000.
O que é um RestController
O RestController no TurboGears fornece um mecanismo para acessar o método da solicitação, não apenas a URL. A verborragia HTTP padrão inclui: GET, POST, PUT e DELETE. O RestController suporta isso e também adiciona alguns atalhos para envio de URL que torna a exibição dos dados como formulários e listas um pouco mais fácil para o usuário.
Para explicar como o RESTful funciona com o TurboGears, vamos definir um serviço da web simples que expõe uma lista de alunos.
O código para o modelo do aluno é fornecido abaixo -
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 = '')
Agora crie um controlador com base no RestController e forneça uma função de visualização para listar a lista de alunos no formato json.
Controladores \ 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)
Monte este StudentController no RootController do aplicativo, incorporando as seguintes linhas em root.py -
from hello.controllers.student import StudentController
class RootController(BaseController):
students = StudentController()
Indo para o http://localhost:8080/students ele fornecerá a lista de nossos alunos codificados no formato json.
Usamos o método post para definir como salvamos nosso aluno no banco de dados. Este método é chamado sempre que o http://localhost:8080/student url é acessado usando uma solicitação 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)
Usando o get_one() método, podemos exibir um item do banco de dados para o usuário -
@expose('json')
def get_one(self, movie_id):
newstudent = DBSession.query(student).get(uid)
return dict(movie = movie)
PUT é o método usado para atualizar um registro existente usando 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)
O cavalo de batalha da exclusão é anexado ao método post_delete. Aqui, removemos o registro do banco de dados e, em seguida, redirecionamos de volta para a página de listagem -
@expose('json')
def post_delete(self, uid, **kw):
newstudent = DBSession.query(student).get(uid)
DBSession.delete(newstudent)
return dict(movie = newstudent.uid)
Para mudar de um ambiente de desenvolvimento para um ambiente de produção completo, o aplicativo precisa ser implantado em um servidor web real. Dependendo do que você tem, existem diferentes opções disponíveis para implantar um aplicativo da web TurboGears.
Apache com mod_wsgi
O mod_wsgi é um módulo Apache desenvolvido por Graham Dumpleton. Ele permite que programas WSGI sejam servidos usando o servidor web Apache.
Em primeiro lugar, instale o Apache 2.X para sua plataforma, se ainda não o fez. Depois de instalar o Apache, instale o mod_wsgi. Crie e ative o ambiente virtual Python no servidor e instale o TurboGears nele.
Instale seu aplicativo no diretor de aplicativos e, em seguida, crie um script chamado app.wsgi.
Configure a instalação do Apache da seguinte maneira -
<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>
Reinicie o Apache
Tipo http://www.site1.com/ em um navegador para acessar o aplicativo.
TurboGears sob Circus e Chaussette
Circus é um gerenciador de processos e soquetes. Ele pode ser usado para monitorar e controlar processos e tomadas. Quando emparelhado com o servidor Chaussette WSGI, ele pode se tornar uma ferramenta poderosa para implantar seu aplicativo e gerenciar qualquer processo relacionado que seus aplicativos precisam.
TurboGears - GoogleAppEngine
Instale o SDK do Google AppEngine para Python a partir do seguinte URL - https://cloud.google.coms
Instale o Google AppEngine em seu sistema. Em seguida, abra o console do Google Developer e faça login com sua Conta do Google -https://console.developers.google.com/start
Crie um novo projeto chamado mytgapp -
Usando o Google AppEngine Launcher, crie um novo aplicativo chamado mytgapp.
Os seguintes arquivos serão criados no diretório especificado -
- app.yaml
- favicon.ico
- index.yaml
- main.py
Por padrão, o aplicativo criado depende da estrutura Webapp2. Para remover essa dependência, edite o arquivo app.yaml e exclua a seguinte parte -
libraries:
- name: webapp2
version: "2.5.2"
Crie um ambiente virtual temporário em um diretório chamado mytgapp e instale o TurboGears. Crie um aplicativo TurboGears nele. Agora podemos continuar editando omain.py que é iniciado pelo AppEngine para executar nosso aplicativo e realmente escrever um aplicativo TurboGears lá.
Adicione o seguinte conteúdo em 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()
Agora execute o aplicativo do AppEngine Launcher e clique no botão de navegação para ver se o aplicativo funciona corretamente no localhost.
Já criamos um projeto chamado mytgapp no console do desenvolvedor. Agora clique no botão implantar no Launcher. Depois que o processo de implantação terminar,http://mytgapp.appspot.com/ visite para ver nosso aplicativo online.