Francisco Souza

Open source, Python, Django, Java, agile e outras coisas mais

Voando Com O Django No Google App Engine

O Google App Engine é uma ferramenta sensacional para desenvolvedores web. Uma ferramente certamente útil e que deveria pelo menos ser experimentada por todo desenvolvedor web que se preza :) A primeira linguagem de programação suportada pelo App Engine foi o Python, e hoje a linguagem Java também é suportada. Python é uma linguagem com muitos frameworks web (muitos mesmo), e você pode usar alguns deles no App Engine. Resolvi, então, criar uma série com três posts sobre como usar três frameworks web Python no Google App Engine: Django, Flask e web2py.

Em todos os casos, desenvolverei uma aplicação simples, que será enviada para o Google App Engine e disponibilizada publicamente :) Nesta primeira parte, abordarei o Django, o mais famoso dentre os frameworks Python para a web.

O principal recurso do Django é a camada de modelo, chamada Django models. Trata-se de uma camada de abstração de dados composta por um poderoso framework de mapeamento objeto-relacional, que suporta diversos sistemas de gerenciamento de banco de dados relacionais. O único problema é que o Google App Engine não usa um banco de dados relacional, o App Engine usa o BigTable, um poderoso banco de dados para armazenamento de dados em larga escala. Assim, a poderosa camada de modelo do Django é simplesmente inútil, pelo menos nativamente falando.

Não há motivo para pânico, existe um fork do Django, o projeto django-nonrel, que visa trazer o poder do Django models para bancos de dados não-relacionais, como o BigTable. Na aplicação deste post, foi utilizado o subprojeto djangoappengine, que une o Django ao BigTable de forma descomplicada.

A aplicação de exemplo não será nenhum exemplo de criatividade: um blog extremamente simples, com apenas uma página para listar os posts e outra para cadastrá-los (protegida por login). Vamos utilizar a autenticação nativa do Django, e não a API de autenticação fornecida pelo App Engine.

O primeiro passo é deixar o ambiente pronto para receber nosso código (e voar em produção =P). De acordo com a documentação oficial do djangoappengine, é necessário baixar quatro arquivos e juntá-los. Comecei pela aplicação, baixei o arquivo django-testapp.zip, extraí e renomeei o diretório de django-testapp para blog_gae. Depois eu baixei as outras bibliotecas, de forma que a estrutura do projeto ficou da seguinte forma:

Estrutura do projetoO diretório “django” foi extraído do pacote django-nonrel.zip, o diretório “djangoappengine” do pacote djangoappengine.zip e o “djangotoolbox” extraído do pacote djangotoolbox.zip. Junto à estrutura de exemplo da aplicação está presente o arquivo app.yaml, que é o arquivo de configuração da aplicação no Google App Engine. Neste arquivo, é necessário apenas mudar o ID da aplicação (primeira linha). Veja como fica o arquivo após a mudança:

[cc lang=”yaml”]application: gaeseries version: 1 runtime: python api_version: 1

default_expiration: ‘365d’

handlers: - url: /remote_api script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py login: admin

  • url: /_ah/queue/deferred script: djangoappengine/deferred/handler.py login: admin

  • url: /media/admin static_dir: django/contrib/admin/media/

  • url: /.* script: djangoappengine/main/main.py[/cc]

A cada parte da série de posts eu vou fazer o deploy de uma versão diferente, assim, todas as versões ficarão disponíveis online dentro de uma mesma aplicação do Google App Engine. Como esta é a primeira parte, então será a primeira versão =P Outro ponto é o arquivo de configuração do Django (settings.py), neste momento, a única mudança neste arquivo é “descomentar” a linha django.contrib.auth na tupla INSTALLED_APPS, para que possamos utilizar a aplicação de autenticação nativa do Django.

Agora nosso ambiente está devidamente configurado, podemos iniciar uma nova aplicação Django e começar a codar. A forma de iniciar a aplicação é a mesma de sempre (daqui pra frente, tudo se parecerá naturalmente Django): basta rodar o startapp.

$ ./manage.py startapp core

Criamos a aplicação principal do projeto, chamada core. É criado o diretório da aplicação com os módulos Python “normais”: models, views e tests. Vamos então criar o model Post. Note que tudo está em inglês, pois esta aplicação foi desenvolvida em inglês :) Eis o código do módulo models.py, com a classe Post:

[cc lang=”python”]from django.db import models from django.contrib.auth.models import User

class Post(models.Model):

title = models.CharField(max_length = 200)
content = models.TextField()
date = models.DateTimeField(auto_now_add = True)
user = models.ForeignKey(User)[/cc]

Agora basta instalar a aplicação core colocando-a dentro da tupla INSTALLED_APPS no arquivo settings.py. Como vamos utilizar a aplicação de autenticação do Django, vamos criar um usuário de administração (super-usuário) para gerenciar toda a bagunça:

$ ./manage.py createsuperuser

Após informar o nome de usuário, o e-mail e a senha, o usuário estará criado no banco de dados. Agora vamos fazer nossa aplicação estar preparada para fazer login e logout. Primeiro, vamos mapear as URLs de login e logout no arquivos urls.py:

[cc lang=”python”]from django.conf.urls.defaults import *

urlpatterns = patterns(”,

('^$', 'django.views.generic.simple.direct_to_template',
{'template': 'home.html'}),
('^login/$', 'django.contrib.auth.views.login'),
('^logout/$', 'django.contrib.auth.views.logout'),

)[/cc]

Note as linhas 6 e 7, onde as URLs são mapeadas. Você pode também conferir os códigos dos templates registration/login.html e registration/logged_out.html. Finalmente, basta adicionar três linhas ao settings.py:

[cc lang=”python”]LOGIN_URL = ‘/login/’ LOGOUT_URL = ‘/logout/’ LOGIN_REDIRECT_URL = ‘/’[/cc]

Agora as URLs de login e logout já estão prontas para voar, podemos criar nossas views de cadastro e listagem dos posts. Vamos primeiro criar a view de cadastro, que contará com um formulário composto pelos campos title (título) e content (conteúdo). Será um ModelForm atrelado ao modelo Post. Além dos campos title e content, o atributo user do modelo Post será preenchido automaticamente com o usuário logado. Eis o código completo do formulário:

[cc lang=”python”]class PostForm(forms.ModelForm):

class Meta:
    model = Post
    exclude = ('user',)

def save(self, user, commit = True):
    post = super(PostForm, self).save(commit = False)
    post.user = user

if commit:
    post.save()

return post[/cc]

Agora basta criar a view para cadastro de um post. Vamos criar também a view de listagem com um simples redirecionamento para que as coisas funcionem bem aqui. Eis o código do módulo views.py:

[cc lang=”python”]from django.contrib.auth.decorators import login_required from django.shortcuts import render_to_response from django.template import RequestContext from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from forms import PostForm

@login_required def new_post(request):

form = PostForm()
if request.method == 'POST':
    form = PostForm(request.POST)
    if form.is_valid():
        form.save(request.user)
        return HttpResponseRedirect(reverse('core.views.list_posts'))
return render_to_response('new_post.html',
                      locals(), context_instance=RequestContext(request)
                 )

def list_posts(request):

return HttpResponseRedirect('/')[/cc]

Agora, para que a view new_post funcione, precisamos apenas mapear as duas views acima para suas respectivas URLs, e criar o template new_post.html. Eis o mapeamento de URLs:

cc lang=”python”, (’posts/$’, ‘core.views.list_posts’),[/cc]

Confira também o template new_post.html.

Finalmente já podemos ver alguma coisa através do navegador. Rodando o comando ./manage.py runserver no terminal temos o servidor inicializado, então é possível acessar a URL http://localhost:8000/posts/new no navegador para ver um formulário de cadastro de posts, onde os posts podem ser escritos e salvos (lembre-se apenas que é necessário efetuar login para acessar esta view). Agora, precisamos apenas listar todos os posts na URL /posts/. A view list_posts já está mapeada para a URL /posts/, então a única coisa a fazer é escrever o código da view, que lista todos os posts do banco de dados e envia para um template:

[cc lang=”python”]def list_posts(request):

posts = Post.objects.all()
return render_to_response('list_posts.html',
                          locals(), context_instance=RequestContext(request)
                         )[/cc]

Confira o template list_posts.html. Finalmente nossa aplicação está pronta para o deploy, mas como fazemos isso? De uma maneira muito difícil:

$ ./manage.py deploy

Pronto, aplicação em produção :) Para poder ter acesso como usuário na aplicação, basta apenas rodar o comando para criar o usuário remotamente:

$ ./manage.py remote createsuperuser

Você pode ver esta aplicação voando neste link: http://1.latest.gaeseries.appspot.com/ (para logar-se no sistema, utilize o nome de usuário demo com a senha demo)

E também ver o código fonte completo neste link: http://github.com/fsouza/gaeseries/tree/django

Nos vemos na próxima parte ;)