Crie uma lista de tarefas com angular e DRF

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.

isso é angular

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

django à direita

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 !