Voando com o Django no Google App Engine

ago 02 2010

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:

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

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:

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)

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:

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

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:

LOGIN_URL = '/login/'
LOGOUT_URL = '/logout/'
LOGIN_REDIRECT_URL = '/'

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:

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

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:

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

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:

('^posts/new/$', 'core.views.new_post'),
('^posts/$', 'core.views.list_posts'),

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:

def list_posts(request):
    posts = Post.objects.all()
    return render_to_response('list_posts.html',
                              locals(), context_instance=RequestContext(request)
                             )

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

7 responses so far

  1. Eu estou desenvolvendo um projeto para rodar no App Engine. No meu caso, está sendo implementado em Java com o Google Web Toolkit, e até agora estou achando essa dupla uma excelente plataforma para desenvolvimento.

    O bom do GAE é que você tem uma quota gratuita que te permite manter a sua aplicação no ar sem custos mesmo que ela ainda não te dê retorno financeiro. E assim que se fizer necessario você compra os recursos computacionais que precisar a preços bem interessantes

  2. [...] This post was mentioned on Twitter by Jeveaux, Francisco Souza. Francisco Souza said: Voando com o Django no Google App Engine: http://bit.ly/bcE1No [...]

  3. Parabéns pela iniciativa, excelente post.

  4. [...] Francisco Souza Open source, Python, Django, Java, Ruby on Rails, agile e outras coisas mais Pular para o conteúdo InícioSobreComunidadeContato ← Voando com o Django no Google App Engine [...]

  5. [...] da série de posts sobre o uso de frameworks Python no Google App Engine. Após abordar o uso do Django e do web2py no App Engine, agora veremos como usar o Flask, um microframework para Python baseado [...]

  6. Parabens pelo post. Eu gostei muito e estou usando para adquirir conhecimento sobre Google App Engine e Django.

  7. Muito bom! Mas acho que vc pode ser ainda melhor se de fato quiser ser um multiplicador eficiente. Digo isto por que sou um usuário windows e não consegui repetir seu sucesso. Como não conheço nenhuma das duas ferramentas fiquei perdido no meio do caminho. Faltou alguma coisa. Contudo achei a idéia espetacular e muito prática.
    Parabens!

Leave a Reply

Spam protection by WP Captcha-Free