Aplicações RESTful no Django
O Django é um framework moderno, com muitos recursos “out of box” e módulos inclusos para fazer 54131998944535 coisas. Porém, diferente de frameworks como Pylons e VRaptor, o Django não possui no seu conjunto de módulos uma API RESTful prontinha pra usar, sem complicações. O que a comunidade geralmente faz nestes casos? Desenvolve a API que falta. Por interesse, curiosidade e aprendizado, fui atrás de algumas dessas APIs, para efetuar alguns testes.Vasculhando pela internet, encontrei diversos artigos e projetos sobre o assunto. O básico do básico seria a definição de uma classe, que deveria ser estendida para a criação de um resource. Veja o código da classe, retirado do Django snippets:
"""
Subclass this and add GET / POST / etc methods.
"""
allowed_methods = ('GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'OPTIONS')
def __call__(self, request, *args, **kwargs):
method = nonalpha_re.sub('', request.method.upper())
if not method in self.allowed_methods or not hasattr(self, method):
return self.method_not_allowed(method)
return getattr(self, method)(request, *args, **kwargs)
def method_not_allowed(self, method):
response = HttpResponse('Method not allowed: %s' % method)
response.status_code = 405
return response
Com um pouco de introspecção (bem pouco), o método __call__ analisa o objeto request e faz a chamada a um método (do objeto RestView) de acordo com o método da requisição (HTTP, aqueles verbos legais, tipo PUT, POST, GET, DELETE). Basicamente, um resource seria uma classe descendente de RestView. Na nossa classe resource, implementaríamos um método chamado GET para tratar as requisições GET, um método POST para tratar as requisições POST, e assim sucessivamente. Veja um exemplo de resource
:
def GET(self, request, user_id):
'''Este método obtém um usuário e renderiza um template passando tal usuário como parâmetro'''
user = get_object_or_404(User, pk = user_id)
return render_to_response('ver_usuario.html', locals(), context_instance = RequestContext(request))
def PUT(self, request, user_id):
'''Este método atualiza um usuário no banco de dados'''
user = get_object_or_404(User, pk = user_id)
user.name = request.POST['user_name']
user.save()
return HttpResponseRedirect(reverse('users.views.list_users'))
Assim, poderíamos fazer o seguinte mapeamento no urls.py, para a classe acima:
...
(r'^user/(\d+)/$', UserView()),
...
)
Note que um objeto é passado por parâmetro, e não a classe em si. Esta solução funciona, pelo menos para trabalhar com diferentes tipos de requisição a uma mesma URL. Mas e no caso de queremos explorar mais a REST, com uso de tecnologias como JSON e XML? Certamente, nossa classe RestView não é capaz de nos atender, seria necessário estendê-la, ou simplesmente procurar uma API completa para trabalhar com REST no Django. Existem duas ferramentas muito boas aqui: django-rest e django-piston, sendo a segunda uma incrível e completa ferramenta para trabalhar com diversos recursos, como integração com os models e forms do Django; autenticação plugável (incluindo uma interface transparente para trabalhar com OAuth. Pelas características, vemos que o Piston é muito mais do que uma API RESTful, é uma ferramenta indispensável ao desenvolvedor Django :) Apesar de toda a empolgação com o Piston, vamos deixar ele parar depois. Antes, vamos ao django-rest. Trata-se de uma interface RESTful, quem fornece integração com os models e também algumas generic views inclusas no pacote, facilitando a criação de CRUDs, por exemplo. Existem ainda outros projetos interessantes, como o django-restful-models-views, que é uma aplicação plugável, mas vou abordar aqui apenas as ferramentas citadas no parágrafo anterior. Basicamente, o django-rest trabalha de duas formas: “semi-automático”, onde fornecemos o modelo e ele “se vira” (semelhante às generic views); ou de forma manual, onde configuramos os resources manualmente, muito comum quando não estamos trabalhando restritamente com models. Um exemplo de código ligado ao model User, que possui os atributos name e age, seria o seguinte (arquivo urls.py
):
from django_restapi.model_resource import Collection
from django_restapi.responder import TemplateResponder
from users.models import User
user_resource = Collection(
queryset = User.objects.all(),
permitted_methods = ('GET', 'POST', 'PUT', 'DELETE'),
responder = TemplateResponder(
template_dir = 'users',
template_object_name = 'my_user',
)
)
urlpatterns = patterns('',
url(r'^users/(.*?)/?$', user_resource, {}, 'user_detail'),
)
O objeto user_resource armazena as configurações do nosso resource. Note o atributo responder, que armazena o tipo de resposta. Aqui, poderíamos utilizar além de TemplateResponder, JSONResponder, XMLResponder, dentre outros tipos de retorno. Na linha 8, definimos os métodos que serão permitidos. Assim, este resource responderá pelas seguintes requisições:
- GET /users: Uma lista com todos os usuários;
- GET /users/<id>: Visualização dos detalhes de um usuário;
- POST /users: Cria um usuário;
- PUT /users/<id>: Atualiza os dados de um usuário;
- DELETE /users/<id>: Apaga um usuário.
A documentação do django-rest é bem pobre. Para entender alguns comportamentos básicos, tive que olhar o código fonte da ferramenta. Por isso, vamos agora para a parte mais legal e interessante: django-piston.
Diferente do django-rest, o django-piston possui excelente documentação, e também uma comunidade ativa, sendo a melhor alternativa quando se trata de API RESTful. Vamos rapidamente ver como tratar o exemplo com o model User descrito acima. É importante notar que o django-piston é bastante aconselhável para a criação de APIs. Assim, ele fornece MUITA coisa para trabalhar com APIs, é totalmente voltado para isto. Vamos distorcê-lo um pouco e fazer com que ele transfira dados para os templates.
Precisamos criar um resource, e para a criação de um resource é necessário que antes seja criado um handler. Os handlers são utilizados pelos resource para tratar as requisições. Um handler é um objeto modelado pela classe BaseHandler (por uma descendente de BaseHandler, para ser mais exato). Veja um exemplo de handler:
allowed_methods = ('GET',)
model = User
def read(self, request, user_id = None):
if user_id is None:
users = User.objects.all()
template = 'user_list.html'
else:
user = User.objects.get(pk = user_id)
template = 'user_detail.html'
template = 'users/%s' % template
return render_to_response(template, locals(), context_instance = RequestContext(request))
Este handler é salvo em um arquivo chamado handlers.py, dentro do diretório de nossa aplicação. Agora, basta adicionar o mapeamento da URL e um resource baseado no nosso UserHandler passa a tratar as requisições, de forma RESTful. Veja como ficaria o urls.py:
from piston.resource import Resource
from users.handlers import UserHandler
user_resource = Resource(handler = UserHandler)
urlpatterns = patterns('',
url(r'users/(?P<user_id>\d*)/$', user_resource),
)
O django-piston é uma ferramenta incrível, com muitos recursos, que provavelmente voltará a aparecer aqui no blog. Recomendo que mergulhe nela e veja como é simples criar APIs RESTful usando Django. Em breve eu falo mais sobre django-piston focando no desenvolvimento de APIs :)


Excelente post! Parabéns!
Valeu Henrique! :)
Cara você anda avançando hein ;)
Manda ver!
Falando nisso, você entende de ORMs em Python?
Conheço um pouco o Autumn e um pouco mais o SQLAlchemy.
Tem também o ORM do Django. Por que a pergunta?
Abraços o/
[...] Django e acessando com Java Postado em 06 de fevereiro de 2010 por Francisco Souza No post sobre aplicações RESTful no Django, fiz uma rápida introdução sobre o django-piston. O piston é um framework para construção de [...]
[...] post sobre aplicações RESTful no Django, fiz uma rápida introdução sobre o django-piston. O piston é um framework para construção de [...]
Eu volta e meia pesquisando soluçoes django esbarro no Henrique, rs .. Ótimo post, realmente o que eu precisava. Utilizo soaplib para aplicações B2B mas REST éuma ótima alternativa para aplicações que eu mesmo irei consumir.