SQLAlchemy no TurboGears
Depois de tempos postando sobre política posso dizer que estou voltando a ativa novamente. Neste post trataremos de um assunto que nunca mais havia tocado: TurboGears.
A minha framework web favorita escrita em Python está na versão 1.0.2.2 e correndo para a versão 1.1, principalmente depois de um sprint que ocorreu recentemente. Os desenvolvedores substituirão o sistema de templates Kid pelo Genshi e o SQLObject pelo SQLAlchemy. O que posso dizer é que podemos usar o SQLAlchemy atualmente sem muitos problemas. Constatei isso implementando um exemplo bem conhecido em Ruby on Rails: um livro de receitas eletrônico (cookbook em inglês).
Vamos mostrar algum código, uma vez que isso é mais divertido. Precisamos do TurboGears e do SQLAlchemy:
easy_install -U TurboGears easy_install SQLAlchemy
Antes de criarmos uma infraestrutura para o projeto, gostaria que vocês conseguissem o servidor de banco de dados MySQL. Vamos fazer o nosso exemplo de acordo com o do Rails. Se vocês quisserem fazer o mesmo exemplo em Rails sugiro lerem alguns posts do blog do Brasília on Rails. Vamos criar nosso banco de dados com o seguinte comando num terminal bash do Linux:
$ mysql -u root -p > create database cookbook; > grant all on cookbook.* to 'usuario@localhost';
O esquema do banco é o seguinte:
drop table if exists recipes;
drop table if exists categories;
create table categories ( id int not null auto_increment,
name varchar(100) not null default '',
primary key(id)
) engine=InnoDB;
create table recipes ( id int not null auto_increment,
category_id int not null,
title varchar(100) not null default '',
description varchar(255) null,
date date null,
instructions text null,
constraint fk_recipes_categories foreign key (category_id) references categories(id),
primary key(id)
) engine=InnoDB;
Colem este esquema num arquivo (digamos, create.sql) e executem:
mysql cookbook < db create.sql
Feito isso, vamos ao TurboGears:
tg-admin quickstart --sqlalchemy
Chamarei o projeto de cookbook. Selecionem ‘não‘ quando perguntado se querem usar o Identity.
Dentro da pasta do projeto há o arquivo dev.cfg para as configurações no ambiente de desenvolvimento. Lá informaremos à aplicação a string de conexão:
sqlalchemy.dburi="mysql://root:oinc@localhost/cookbook"
Executemos o script start-cookbook.py para rodar o servidor. Depois acesse o endereço http://localhost:8080/ para testar a aplicação.
python start-cookbook.py
Depois disso, vamos no arquivo cookbook/model.py para mapear para objetos o nosso banco com SQLALchemy:
from sqlalchemy import *
from turbogears.database import metadata, session, bind_meta_data
#from sqlalchemy.ext.assignmapper import assign_mapper
bind_meta_data()
categoria_tabela = Table('categories',metadata,autoload=True)
receita_tabela = Table('recipes',metadata,autoload=True)
class Categoria(object):
def __init__(self,name):
self.name = name
def __repr__(self):
return self.name
class Receita(object):
def __init__(self,title):
self.title = title
def __repr__(self):
return self.title
def nome_categoria(self):
return self.categoria.name
mapper(Categoria, categoria_tabela, properties={'receitas' : relation(Receita,backref='categoria')})
mapper(Receita, receita_tabela)
Para o post não ficar muito grande, faremos somente uma página que lista todas as receitas. Eu não cheguei a implementar todo o exemplo do Cookbook, no entanto é muito mais do que mostrarei para vocês daqui pra frente. Como não tenho nenhum local na internet para disponibilizar este exemplo, vocês terão de informar e-mail para que eu envie-os.
Copiem o template welcome.kid e criem o arquivo receita_list.kid. Retirem o corpo da página e coloquem somente o seguinte:
${grid.display(receitas)}
Editem o arquivo cookbook/controllers.py. Escreveremos um método que acesse o banco de dados para pegar todas as receitas e passe essa lista para o template que criamos.
@expose(template="cookbook.templates.receita_list")
def receitas(self):
receitas = session.query(Receita).select()
grid = DataGrid(fields=[('Nome','title'), ('Categoria',Receita.nome_categoria)])
return dict(receitas = receitas, grid = grid)
Para que esse método funcione, temos de importar model.py e widgets.DataGrid.
from model import * from turbogears.widgets import DataGrid
A primeira linha do método utiliza o objeto session para fazer uma consulta no banco na tabela recipes (mapeada pela classe Receita). Na segunda linha, instanciamos o DataGrid que será usado para gerar a tabela de resultados. Por fim, a última declara os objetos que serão usados em nosso template.
Acessemos a URL http://localhost:8080/receitas. Espero que tenha funcionado!
Problemas e dúvidas, por favor, comentem.
Atualização: Baixem a aplicação. Oferecimento: Walter Cruz
Vou dar uma testada mais tarde, com PostgreSQL.
Framework é uma palavre feminina?
Walter, curiosamente eu insisto em tratar ‘framework’ como uma palavra do gênero feminino. É como se fluísse melhor.
Ou, quer o local para disponibilizar os arquivos?
Caro, Walter, sim. Conversamos via GTalk.
Já testou o assign_mapper?
Sim, já testei o assign_mapper.
Porque você não sou metadata.create_all() depois de ter definido as tabelas no model? Eu sempre prefiro fazer assim, me livra de escrever SQL, fica mais fácil de fazer modificações e elimina o (pequeno) processamento requerido pra introspecção…
*não usou…
Olá, Geron!
Eu simplesmente não usei o método que sugeriu porque copiei o código SQL do exemplo do cookbook do Rails, enfatizando o fato de estar escrevendo em TurboGears algo já feito para outro framework.
Valeu o comentário!