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.