Back-End

30 mar, 2015

Usando AngularJS com Django

Publicidade

A ideia desse artigo é explicar uma maneira de usar AngularJS em um projeto Django. Se você não conhece Django, saiba que é um framework web, escrito em Python, muito popular. Já o AngularJS é um framework em JavaScript que faz umas coisas bem legais com o HTML: adiciona funcionalidades, manipula elementos e tem se tornado uma grande tendência entre desenvolvedores front-end. Neste artigo, vamos ver como integrar o AngularJS em um projeto Django sem utilizar pacotes prontos.

Lembramos que esse artigo é apenas um guia de integração entre as ferramentas, por isso seria ideal que o leitor tenha alguma experiência com AngularJS e Django, além de aplicações assíncronas.

Vale lembrar que essa é uma solução dita híbrida, como forma de obter alguns benefícios do Angular.js, dentro do contexto de uma aplicação Django. A solução pura de uma Single Page Application usaria somente o Angular.js ou similares e implementaria a API com Django ou outros web application frameworks, BaaS ou outros frameworks server side, como o Node.js.

Hoje, vamos usar o exemplo de desenvolvimento de um site com um carrinho de compras. Vamos lá!

Definição da estrutura

Comece criando uma aplicação para carrinho de compras:

$ django-admin startapp cart

Crie a estrutura para os arquivos estáticos.

$ mkdir -p cart/static/controllers cart/static/directives cart/static/filters cart/static/services cart/static/tests

Importante: A estrutura que utilizaremos para AngularJS não é uma obrigação. Você pode usufruir dele da forma que achar mais conveniente.

Adicione a app no settings do projeto:

STORE = (‘cart’)
INSTALLED_APPS += STORE
views.py

Crie uma view básica para renderizar o carrinho e outras duas para serem usadas como APIs:

from django.shortcuts import render
from django.http import HttpResponse
import json
 
 
def index(request):
	return render(request, 'cart.html', {})
 
def adicionar_item(request):
	itens_pedido = request.session.get('itens_pedido', [])
 
	item = json.loads(request.body)['item']
	itens_pedido.append(item)
 
	request.session['itens_pedido'] = itens_pedido
	return HttpResponse(json.dumps(itens_pedido))
 
def excluir_item(request, index):
	itens_pedido = request.session.get('itens_pedido', [])
 
	del itens_pedido[int(index)]
 
	request.session['itens_pedido'] = itens_pedido
	return HttpResponse(json.dumps(itens_pedido))

urls.py

Crie as rotas das views:

from django.conf.urls import patterns, url
 
 
urlpatterns = patterns('cart.views',
	url(r'^#039;, 'index'),  # NOQA
	url(r'^adicionar/', 'adicionar_item'),
	url(r'^atualizar/', 'atualizar_item'),
	url(r'^excluir/(?P<index>[0-9]+)', 'excluir_item'),
)

Adicione-as no urls.py do projeto:

urlpatterns += patterns('',
 url(r'', include('cart.urls')),
)

app.js

Atenção, esta é a parte mais importante do artigo! Sem essa configuração surgirá uma série de problemas. Vá na pasta cart/static/app e crie um arquivo chamado app.js com o seguinte conteúdo:

(function() {
 'use strict';
 angular.module('app',[
	'ngCookies'
 ], function($interpolateProvider){
	// Contorna prroblema de interpolação da renderização de template do django
	$interpolateProvider.startSymbol('{[{');
	$interpolateProvider.endSymbol('}]}');
 })
 .run( function run($http, $cookies ){
	// Evita problemas relacionados ao CSRF
	$http.defaults.headers.post['X-CSRFToken'] = $cookies['csrftoken'];
 });
})();

cart-controller.js

Vá na pasta cart/static/app/controllers e crie um arquivo chamado cart-controller.js com o seguinte conteúdo:

(function() {
 'use strict';
 angular.module('app').controller('CartController', function($scope, $http) {
	$scope.pedido = {
 	itens: [],
 	total: function() {
   	var total = 0;
   	angular.forEach($scope.pedido.itens, function(item) {
     	total += item.qtd * item.preco;
   	})
   	return total;
 	}
	}
 
	$scope.adicionarItem = function() {
 	var produto = {
   	descricao: 'A guerra dos tronos - The Board Game',
   	preco: 150.0,
   	qtd: 1
 	}
 
 	$http.post('/adicionar/', {item: produto})
   	.success(function(data) {
     	$scope.pedido.itens = data;
   	})
	}
 
	$scope.excluirItem = function(index) {
 	$http.post('/excluir/' + index)
   	.success(function(data) {
     	$scope.pedido.itens = data;
   	})
	}
 });
})();

cart.html

Agora, iremos criar a página do carrinho. Crie um html em cart/templates/cart.html:

<html>
 <head>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular-cookies.min.js"></script>
	<script src="{{ STATIC_URL }}app.js"></script>
	<script src="{{ STATIC_URL }}controllers/cart-controller.js"></script>
 </head>
 <body ng-app="app">
	<h2>Carrinho de Compras</h2>
	<div ng-controller="CartController">
 	<table class="table">
   	<tr>
     	<th>Descrição</th>
     	<th>Quantidade</th>
     	<th>Custo</th>
     	<th>Total</th>
     	<th></th>
   	</tr>
   	<tr ng-repeat="item in pedido.itens">
     	<td>{[{ item.descricao }]}</td>
     	<td><input type="number" ng-model="item.qtd" min="1" max="10"></td>
     	<td>{[{ item.preco }]}</td>
     	<td>{[{item.qtd * item.preco | currency}]}</td>
     	<td>
       	[<a href ng-click="excluirItem($index)">X</a>]
     	</td>
   	</tr>
   	<tr>
     	<td><a href ng-click="adicionarItem()" class="btn btn-small">Adicionar Item</a></td>
     	<td></td>
     	<td>Total:</td>
     	<td>{[{pedido.total() | currency}]}</td>
   	</tr>
 	</table>
	</div>
 </body>
</html>

Conclusão

Mostramos neste artigo um exemplo de uso do AngularJS com o Django, definindo uma forma híbrida entre os dois frameworks. A solução foi simplificada ao ponto de não tratar possíveis problemas e requisitos básicos, mas a ideia mais importante era demonstrar o uso dessas ferramentas no mundo real. Às vezes, implementar uma solução com menos dependências externas é mais interessante do que contornar o problema com aplicações de terceiros, simplesmente por termos mais controle sobre o que estamos criando. Veremos mais desse conceito em um próximo artigo, que abordará como criar testes para AngularJS.

Ah! Caso você queira, veja o repositório pronto no bitbucket da Concrete. Se ficou alguma dúvida, tem alguma sugestão ou crítica, deixe seu comentário abaixo.