11nov

Django com MySQL, JQuery, Ajax e JSON – Parte 1

Posted by gustavohenrique as Django

Criando as Views

Antes de começarmos a falar sobre as views, vamos configurar o arquivo urls.py e mapear nossas URLs. Não detalharemos esse processo muito menos sobre expressões regulares utilizadas.
Vamos mapear todos as nossas views de uma vez, alterando novamente a variável urlpatterns dentro do arquivo urls.py:

1
2
3
4
5
6
7
8
9
urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),
    (r'^cliente/list/$','sigep.cliente.views.list'),
    (r'^cliente/add/$','sigep.cliente.views.add'),
    (r'^cliente/delete/$','sigep.cliente.views.delete'),
    (r'^cliente/edit/$','sigep.cliente.views.edit'),
    (r'^cliente/update/$','sigep.cliente.views.update'),
    (r'^cliente/search/$','sigep.cliente.views.search'),
)

Agora sim, vamos ao que interessa…
No Django as views são os controllers do modelo MVC, ou seja, métodos que intermediam a comunicação entre os modelos (banco de dados) e os templates (HTML).
Vamos escrever nossos métodos no arquivo views.py localizado dentro do diretório da aplicação cliente:

Método 1: list
Descrição: Exibe os clientes cadastrados e um formulário para cadastrar novo cliente. Na realidade o template exibido é o clienteform que por sua vez extende o template clientes.html, resultando na exibição dos 2 ao mesmo tempo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# -*- coding: utf-8 -*-
from sigep.cliente.models import *
from sigep.cliente.forms import *
from django.shortcuts import render_to_response
 
def list(request):
  clienteform = ClienteForm()
  clientes = Cliente.objects.all()
  bairros = Bairro.objects.all()
 
  return render_to_response('clienteform.html',{
    'form':clienteform,
    'clientes':clientes,
    'bairros':bairros,
    'operacao':'Cadastrar',
  })

Explicando o código:
Definimos a codificação do arquivo como UTF8
Criamos um objeto do tipo ClienteForm, que foi definido no arquivo forms.py
A variável clientes obtem todos os clientes cadastrados
A variável bairros obtem todos os bairros cadastrados
O metodo listar retorna o arquivo de template a ser renderizado com o valor das variáveis passadas como argumentos.

Método 2: add
Descrição: Cadastra os dados do cliente no banco de dados.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.http import HttpResponse
def add(request):
  if request.method == 'POST':
    clienteform = ClienteForm(request.POST)
    if clienteform.is_valid():
      clienteform.save()
      mensagem = 'Cadastro realizado com sucesso.'
    else:
      mensagem = 'Erro na validacao do form.'
 
    clientes = Cliente.objects.all()
    operacao = 'Cadastrar'
    return render_to_response('clienteform.html',{'form':clienteform, 'clientes':clientes, 'mensagem':mensagem, 'operacao':operacao})
  else:
    return HttpResponse("Nao foi submetido nenhum formulario.")

Notem o quanto a validação de um formulário é ridiculamente simples no Django. É criado um objeto do tipo ClienteForm, passando como parâmetro o formulário submetido e chamando o método is_valid().
Uma novidade nesse código foi o uso do método HttpResponse que apenas exibe um texto na tela do navegador.

Método 3: delete
Descrição: Remove o cliente do banco de dados a partir do id fornecido.

1
2
3
4
5
6
7
8
9
10
11
def delete(request):
  if request.method == 'POST':
    id = request.POST.get('listaclientes')
    if id > 0:
      Cliente.objects.get(pk=id).delete()
      return HttpResponseRedirect('/cliente/list/')
 
    else:
      return HttpResponse("Nenhum cliente foi selecionado. Id=0.")
  else:
    return HttpResponse("Nao foi submetido nenhum formulario.")

Em

1
Cliente.objects.get(pk=id)

, estamos selecionando na tabela cliente o registro cuja chave primária (pk) seja igual ao valor da variável id. Essa variável poderia ter outro nome, e não necessáriamente o nome do campo da tabela que também é id.

Método 4: edit
Descrição: Obtém os dados do cliente a partir do id fornecido e preenche o formulário usado no cadastro.

1
2
3
4
5
6
7
8
9
10
11
12
13
def edit(request):
  if request.method == 'POST':
    id = request.POST.get('listaclientes')
    if id > 0:
      clientes = Cliente.objects.get(pk=id)
      clienteform = ClienteForm(instance=clientes)
      form_url = '/cliente/update/'
      operacao = 'Atualizar'
      return render_to_response('clientes.html' {'form':clienteform, 'id_cliente':id, 'form_url':form_url, 'operacao':operacao})
    else:
      return HttpResponse("Nenhum cliente foi selecionado. id=0.")
  else:
    return HttpResponse("Nao foi submetido nenhum formulario.")

Método 5: update
Descrição: Atualiza os dados do cliente e tenta fazer a validação do mesmo jeito que o método add.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def update(request):
  if request.method == 'POST':
    id = request.POST.get('id')
    if id > 0:
      cliente = Cliente.objects.get(pk=id)
      clienteform = ClienteForm(request.POST,instance=cliente)
      if clienteform.is_valid():
        clienteform.save()
        return HttpResponseRedirect('/cliente/list/')
      else:
        mensagem = 'erro'
        operacao = 'Atualizar'
        return render_to_response('clienteform.html',{'form':clienteform, 'mensagem':mensagem, 'id_cliente':id, 'operacao':operacao})
 
    else:
      return HttpResponse("Nenhum cliente foi selecionado. id=0.")
  else:
    return HttpResponse("Nao foi submetido nenhum formulario.")

Método 6: search
Descrição: A partir da palavra-chave fornecida, é feita uma busca case-insensitive na tabela cliente nos campos nome e cpf. Equivalente em SQL à WHERE nome LIKE “%palavra%” OR cpf LIKE “%palavra%”. Para tal tarefa vamos utilizar o objeto Q, pertecente à biblioteca django.db.models.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def search(request):
  if request.method == 'POST':
    palavra = request.POST.get('busca')
    if len(palavra) > 0:
      from django.db.models import Q
      clientes = Cliente.objects.filter(Q(nome__icontains=palavra) | Q(cpf__icontains=palavra))
      bairros = Bairro.objects.all()
      clienteform = ClienteForm()
      return render_to_response('clienteform.html',{
        'form':clienteform,
        'clientes':clientes,
        'bairros':bairros,
        'operacao':'Cadastrar',
        'titulo':'RESULTADO DA BUSCA'
      })
    else:
      return HttpResponse("Nao foi digitado nada no campo de busca.")
  else:
      return HttpResponse("O formulario nao foi submetido.")

Terminamos de criar nossas views, entretanto nosso sistema não possui a mínima segurança. Vamos criar então nossa interface de autenticação de usuários.

Autenticação de Usuários

Nosso método de autenticação será o mesmo utilizado pelo admin. Criaremos apenas a interface de login, um template simples, e todo o processo de autenticação e validação será feito pelo Django.
Na primeira vez em que foi executado o script manage.py syncdb, o Django perguntou se você queria criar uma conta de super-usuário. Essa é a mesma conta usada pelo admin. Se por acaso você não criou essa conta, execute o comando abaixo para criar um novo:
gu@notebook:~/projetos/sigep$ ./manage.py createsuperuser

Vamos criar nosso template de login, dentro do diretório de templates, com o nome loginform.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>SIGEP - Login</title>
  <meta http-equiv="content-type" content="text/html;charset=utf-8" />
  <script language="Javascript" type="text/javascript">
  function Validar(objForm)
  {
    if (objForm.username.value != "" && objForm.password.value != "")
      return true;
      else {
        alert("Preencha corretamente todos os campos.");
        objForm.username.focus();
        return false;
      }
    }
  </script>
</head>
 
<body>
<center>
<form action="." name="login" id="frmLogin" method="post" onsubmit="return Validar(this)">
<div id="divLogin" align="left">
  <br />Usuario: {{form.username}}
  <br />Senha: {{form.password}}
  <input type="hidden" name="next" value="{{ next }}" />
  <br /><br />
  <input type="submit" name="btOk" value="Ok" />
</div>
</form>
 
{% if form.errors %}
<div align="center" style="padding-top:50px;font-size:16px;color:red;">
  Erro: Usuario ou senha incorretos.
</div>
{% endif %}
 
</center>
</body>
</html>

Nosso template é um arquivo HTML simples, com uma função Javascript que verifica se os campos usuario e senha foram preenchidos e então envia o formulário. No action foi inserido um ponto (.) porque o método que vai renderizar esse template automaticamente substituirá pelo action verdadeiro.

E então vamos fazer o mapeamento de URL para o processo de login. No arquivo urls.py, adicione na variável urlpatterns o seguinte:

1
2
r'^auth/login/$','django.contrib.auth.views.login', {'template_name': '/home/gu/projetos/sigep/templates/loginform.html'}),
(r'^auth/logout/$','django.contrib.auth.views.logout_then_login'),

Observem que não estamos fazendo um mapeamento para nenhuma das views que criamos, pois o Django provê métodos próprios para esse tipo de autenticação. Definimos apenas o template que criamos anteriormente para ser usado.
Existem 3 variáveis que não vêm definidas por padrão e que são necessárias para a autenticação funcionar. Vamos defini-las então no arquivo settings.py:

1
2
3
LOGIN_URL = '/auth/login/'
LOGOUT_URL = '/auth/logout'
LOGIN_REDIRECT_URL = '/cliente/list/'

LOGIN_URL e LOGOUT_URL devem ter o mesmo valor que foi utilizado no mapeamento de URL logo acima. LOGIN_REDIRECT_URL é a view a ser chamada quando o login for efetuado.

Para finalizar essa parte, precisamos definir quais das nossas views só poderão ser acessadas se o usuário estiver logado. Para isso vamos utilizar o método login_required() presente na biblioteca django.contrib.auth.decorators.
No arquivo views.py, devemos importar o método login_required. Para cada view que seja necessário o login efetuado, devemos declarar uma variavel com o mesmo nome da view, recebendo o valor de login_required passando como argumento a view. Ex.:

1
2
3
4
from django.contrib.auth.decorators import login_required
def welcome(request):
  return HttpResponse('Bem-vindo! Voce esta logado no sistema.')
welcome = login_required(welcome)

Conforme o exemplo acima, vamos usar o login_required() abaixo de cada view que escrevemos.

1
2
3
4
5
6
7
def list(request):
  ...
list = login_required(list)
 
def add(request):
 ...
add = login_required(add)

Nossa aplicação está quase completa. Está faltando o uso do ajax para exibir as ruas cadastradas a partir do bairro selecionado.

Páginas: 1 2 3 4 5


Versão para Impressora Versão para Impressora

9 Responses to Django com MySQL, JQuery, Ajax e JSON – Parte 1

Relsi

novembro 11th, 2008 at 18:20

Muito legal o tuto, parabéns!!

Hugs!!

Abaster

novembro 11th, 2008 at 19:20

Muito bom, dei só uma olhada mas com esse tipo de material o Django ira crescer cada vez mais.

Rânielli The head

novembro 11th, 2008 at 23:58

Fala rapaz parabens ai ficou muito bom ,,
uma abraço

Leandro

novembro 13th, 2008 at 14:21

Gustavo,

Meus sinceros parabéns pelo material, está excelente.

Um desafio:
– O que tu achas de fazer uma versão desse ajax com a biblioteca mootools ?

Bernardo Marambaia

março 15th, 2009 at 23:12

Parabéns Gustavo,

Ouvi falar da eficiência do Django a poucos dias e procurei algo simples que pudesse me comprovar isso…
Vc sintetizou nesse post tudo o que eu estava procurando! Agora é só me aprofundar no framework. Se existirem mais posts como esse por aí tenho certeza que a comunidade Python e Django vão crescer muito em quantidade e principalmente em qualidade! 100% produção…

Bernardo Marambaia

março 16th, 2009 at 0:24

Verifiquei que no arquivo forms.py ao usarmos o método mark_safe, devemos incluir a classe safestring do Django.
Para resolver o problema devemos incluir a linha from django.utils.safestring import mark_safe no início do arquivo /cliente/forms.py para importar o método mark_safe.
Abs…

Maria

maio 5th, 2009 at 17:29

na linha
$(”#”+objHtmlReturn).append(”+item.fields[fieldreturn]+”);

qd escolho o bairro da um erro dizendo q a palavra ou o campo “fieldreturn” nao está definido por isso nao carrega as ruas no outro select

Francisco Souza

agosto 10th, 2009 at 10:09

Excelente tutorial, colega. :)

Parabéns XD

Helder

agosto 27th, 2009 at 16:41

Opa, tudo bom.
Primeiro quero parabenizá-lo pelo artigo. Segundo informo que o método javascript declarado acima para atualizar o select html está quebrado. Criei outro método jQuery, que ficou assim:

$( function() {
$(”select#id_bairro”).change(
function() {
$.getJSON( “/cliente/getlogradouros?id=” + $(this).val(),
function(j) {
var options = ‘———- ‘;
for ( var i = 0; i < j.length; i++) {
options += ”
+ j[i].fields['logradouro']
+ ”;
}
$(”#id_logradouro”).html(options);
$(”#id_logradouro option:first”).attr(’selected’,
’selected’);
$(”#id_logradouro”).attr(’disabled’, false);
})
$(”#id_logradouro”).attr(’selected’, ’selected’);
})
})

Para que ele funcione, o metodo no módulo views.py precisa ser mudado para o método GET, que no meu caso ficou assim:

def getlogradouros( request ):
id = int( request.GET.get( ‘id’ ) )
lista = Logradouro.objects.filter( bairro = id )
if lista.count() > 0:
json = serializers.serialize( “json”, lista )
else:
lista = [{"pk":"0", "fields":{'logradouro':"Nenhum registro"}}]
json = simplejson.dumps( lista )
return HttpResponse( json, mimetype = “application/json” )

Comment Form