O código-fonte está disponível aqui .
Neste aplicativo, vamos construir uma lista de tarefas persistente. O backend e o banco de dados serão gerenciados pelo Django. O framework django rest converterá os dados da tabela em JSON e o angular trará a mágica do frontend.
Clone o projeto inicial
Fiz um projeto inicial de drf angular . Vamos começar a partir daí e construir a todolist. Clone e dê um novo nome
$ git clone git@github.com:jasonshark/django-drf-angular-starter-project.git
$ mv django-drf-angular-starter-project angular-drf-todolist
$ cd angular-drf-todolist
Configurar ambiente virtual
Fazemos isso para instalar os pacotes localmente em vez de em sua máquina. Nossas dependências de projeto são especificadas em requirements.txt
.
$ source ~/.bash_profile
$ mkvirtualenv angular-drf-todolist
$ lsvirtualenv
$ pip install -r requirements.txt
Servidor de lançamento
$ ./manage.py migrate
$ ./manage.py runserver
Isso configura nosso banco de dados e inicia o servidor. Vá para localhost:8000
. Agora angular e drf funcionam bem
Criar modelo Todo
Isso é o mesmo que criar uma tabela em nosso banco de dados para conter todas as tarefas pendentes. Cada tarefa ocupará uma linha na tabela. O modelo define como serão as colunas. Para cada tarefa, teremos um título, uma descrição e is_completed.
jsframework / models.py
“ `
from django.db import models
classe Todo (models.Model):
title = models.CharField (max length = 75)
description = models.TextField ()
is completed = models.BooleanField (default = False)
def __unicode__(self):
return self.title
Then make the migrations that turns the above python into a database table:
$ ./manage.py makemigrations
$ ./manage.py migrate
“ `
Verifique se funcionou abrindo o shell e adicionando uma tarefa:
$ ./manage.py shell
>>> from jsframework.models import Todo
>>> Todo.objects.all()
[]
>>> first_todo = Todo(title='first todo',description='a little bit softer now',is_completed='false')
>>> first_todo.save()
[<Todo: first todo>]
No início não há nada, agora parece que adicionamos um todo ao banco de dados. Na verdade, queremos exibir isso no navegador como JSON para que o angular possa brincar com ele.
Serializar para JSON
Crie um TodoSerializer em um novo arquivo . Isso converterá nossos dados em json.jsframework/serializers.py
from rest_framework import serializers
from jsframework.models import Todo
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
Agora prepare nossas visualizações para renderizar JSON:
from django.shortcuts import render
from rest_framework import viewsets
from jsframework.models import Todo
from serializers import TodoSerializer
# Todos routes automatically generated
class TodoViewSet(viewsets.ModelViewSet):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
# Home route to send template to angular
def index(request):
return render(request, 'jsframework/base.html')
Usamos o ModelViewSet que fornece automaticamente nos pontos finais para , , , , e . É aqui que a magia DRF realmente acontece. Com essa pequena classe acima, temos as visualizações necessárias para criar, ler, atualizar e excluir todos. No roteador, vamos mapear isso..list()
.retrieve()
.create()
.update()
.destroy()
Atualize nossas rotas em . Eles definirão onde e qual JSON deve ser exibido.jsframework/urls.py
from django.conf.urls import patterns, include, url
from rest_framework import routers
from . import views
todo_router = routers.DefaultRouter()
todo_router.register(r'todos', views.TodoViewSet, base_name='todos')
urlpatterns = [
# Send base.html to angular
url(r'^$', views.index, name='index'),
url('^api/', include(todo_router.urls)),
]
Clique em seu navegador e você verá um array JSON de objetos Todo no belo console DRF. Existem botões para criar (usando solicitações PUT), atualizar (solicitações PUT) e excluir (solicitações DELETE).http://localhost:8000/api/todos
Engate este otário no frontend
Iremos um pouco mais rápido sobre as coisas angulares porque há uma API totalmente funcional.
Primeiro defina as rotas e uma constante para nosso endpoint da API.
var app = angular.module('drf-angular', [
'ui.router'
]);
app.constant('BASE_URL', 'http://localhost:8000/api/todos/');
app.config(function($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: '/',
templateUrl: '/static/templates/home.html',
controller: 'MainCtrl'
})
.state('add-todo', {
url: "/add",
templateUrl: 'static/templates/add_todo.html',
controller: 'MainCtrl'
});
$urlRouterProvider.otherwise('/');
});
Nota especial, estamos usando ui-router . Além disso, certifique-se de ter barras no final de seus urls ao fazer solicitações ao DRF. O golpe final nos deixou perplexos um pouco.
// will break without slash at the end
app.constant('BASE_URL', 'http://localhost:8000/api/todos/');
Em seguida, defina um serviço que faça solicitações ao DRF e retorne promessas. Provavelmente poderíamos ter usado $ resource ou Restangular aqui, mas não estou muito familiarizado com eles e não sei se sobreviverão no Angular 2.0. $ http é simples e direto. Faça solicitações http e retorne promessas.
app.service('Todos', function($http, BASE_URL){
var Todos = {};
Todos.all = function(){
return $http.get(BASE_URL);
};
Todos.update = function(updatedTodo){
return $http.put(BASE_URL + updatedTodo.id, updatedTodo);
};
Todos.delete = function(id){
return $http.delete(BASE_URL + id + '/');
};
Todos.addOne = function(newTodo){
return $http.post(BASE_URL, newTodo)
};
return Todos;
});
Chame os métodos de serviço no controlador:
app.controller('MainCtrl', function($scope, Todos, $state){
$scope.newTodo = {};
$scope.addTodo = function() {
Todos.addOne($scope.newTodo)
.then(function(res){
// redirect to homepage once added
$state.go('home');
});
};
$scope.toggleCompleted = function(todo) {
Todos.update(todo);
};
$scope.deleteTodo = function(id){
Todos.delete(id);
// update the list in ui
$scope.todos = $scope.todos.filter(function(todo){
return todo.id !== id;
})
};
Todos.all().then(function(res){
$scope.todos = res.data;
});
});
A função de exclusão é um pouco complicada. Temos que atualizar o cliente e realmente não queremos executar o ciclo de resumo novamente ou enviar outra solicitação http, não há necessidade. Poderíamos tratar de alguns erros para garantir que o todo foi realmente excluído do banco de dados. Aqui, filtramos o array normal, se a propriedade id corresponde ao que queremos excluir, nos livramos dele. Essa solução veio de StacktotheOverflow .$scope.todos
Adicionar adicionar a marcação
jsframework / static / templates / home.html
“ `
<div class = ‘row text-center’>
<div class = ‘col-sm-4 col-sm-offset-4’>
<h1> Todos </ h1 >
<button ui-sref="add-todo" class='btn btn-primary btn-lg' style='margin-bottom:20px;'>Add Todo</button>
<ul class="list-group">
<li ng-repeat='todo in todos' ng-class="{completed: todo.is_completed}" class="list-group-item">
<input type="checkbox" ng-checked="todo.is_completed" ng-change="toggleCompleted(todo)" ng-model='todo.is_completed'> {{todo.title}}
<span class='badge' ng-click="deleteTodo(todo.id)">X</span>
</li>
</ul>
</div>
</div>
“ `
A marcação será sobre todos. ng-change é uma diretiva bacana que executa uma função quando tudo o que você passa para ela é atualizado ou alterado. Eu roubei isso da implementação Angular.js TodoMVC . ng-verificado irá marcar a caixa de seleção com base no valor verdadeiro ou falsey que passamos para ele. ng-class também é legal. scotch.io tem um tutorial lá sobre as várias maneiras de usar o ngClass.ng-repeat
O CSS para este projeto é extremamente simples:
.completed {
text-decoration: line-through;
}
.badge {
cursor: pointer;
}
Então, temos uma página para adicionar um todo:
jsframework / static / templates / add_todo.html
<div class='row text-center'>
<div class='col-sm-4 col-sm-offset-4'>
<h1>Add a todo</h1>
<input type="text" ng-model="newTodo.title" placeholder="title" class='form-control' />
<textarea name="textarea" class="form-control" rows="5" ng-model="newTodo.description" placeholder="description"></textarea>
<button class='btn btn-success btn-lg' ng-click="addTodo()">Add</button>
</div>
</div>
Se você gostou do tutorial, dê uma estrela ao repo !