sexta-feira, 1 de junho de 2007

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

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.
blog comments powered by Disqus