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

Instalando o Admin – Interface de Administração Automática

A interface de administração automática do Django, vulgo admin, trata-se de uma poderosa interface, simples e rápida de implementar, que possibilita criar, editar, atualizar e deletar registros no banco de dados. É possível criar um sistema funcional em poucas horas usando com seu uso, podendo personalizar a aparência alterarando os templates.
Para instalar o admin, devemos primeiramente adiciona-lo ao INSTALLED_APPS e descomentar 3 linhas no arquivo urls.py.

Arquivo settings.py:

1
2
3
4
5
6
7
8
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'sigep.cliente',
    'django.contrib.admin',
)

Arquivo urls.py:

1
2
3
4
5
6
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),
)

O admin possui várias opções de configuração de modo a personalizar o que é exibido. Vamos usar apenas algumas dessas opções para definir a ordem de exibição dos dados, um filtro e um campo de busca.
Crie um arquivo chamado admin.py dentro do diretório da aplicação contendo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.contrib import admin
from sigep.cliente.models import *
 
class ClienteAdmin(admin.ModelAdmin):
  date_hierarchy = 'data_cadastro'
  ordering = ['nome']
  list_filter = ('id','nome')
  search_fields = ('nome','cpf')
 
admin.site.register(Cliente,ClienteAdmin)
 
class GrupoVencimentoAdmin(admin.ModelAdmin): pass
admin.site.register(GrupoVencimento,GrupoVencimentoAdmin)
 
class BairroAdmin(admin.ModelAdmin): pass
admin.site.register(Bairro,BairroAdmin)
 
class LogradouroAdmin(admin.ModelAdmin): pass
admin.site.register(Logradouro,LogradouroAdmin)

Executaremos novamente o syncdb para aplicar as mudanças:
gu@notebook:~/projetos/sigep$ ./manage.py syncdb

Se os passos anteriores foram seguidos corretamente, podemos “brincar” com nossa aplicação agora. Execute o ./manage.py runserver e tente acessar pelo navegador o site http://localhost:8000/admin/ e então será exibida a tela de login.
Para alterar o template do admin, basta copiar o diretório /usr/lib/python2.5/site-packages/django/contrib/admin/templates/admin para dentro do diretório de templates definido no arquivo settings.py, e alterar o código HTML do mesmo.

Criando os Formulários

Deixaremos o admin de lado pois nossa intenção é criar uma aplicação do zero, onde utilizaremos a interface de administração apenas para operações simples, como cadastrar dados de teste. Assim, faz-se necessário criar os formulários da nossa aplicação onde podemos personaliza-los de maneira mais fácil.
Django provê uma poderosa biblioteca chamada ModelForm para manipulação de formulários. São gerados a partir dos modelos criados no arquivo models.py e são renderizados nos templates. Talvez a maior vantagem do ModelForm seja a facilidade no tratamento de erros e validação dos dados submetidos.
Crie um arquivo chamado forms.py dentro do diretório da aplicação, com o seguinte conteúdo:

1
2
3
4
5
6
7
from sigep.cliente.models import *
from django.forms import *
 
class ClienteForm(ModelForm):
  data_nascimento = DateField(widget=DateTimeInput(format='%d/%m/%Y'))
  class Meta:
    model = Cliente

Assim, automaticamente é criado um formulário contendo todos os campos da tabela cliente. Também é possível inserir algumas propriedades dentro de cada elemento do formulário, como por exemplo style e onblur, utilizando um recurso chamado widgets.
Exemplo usando widgets:

1
2
3
4
5
6
7
wid_nome = TextInput(attrs={'onBlur': mark_safe("alert('Exemplo widget')")})
wid_cpf =  TextInput(attrs={'style':"width:135px;",})
class ClienteForm(ModelForm):
  nome = CharField(max_length=200,widget=wid_nome)
  cpf = CharField(widget=wid_cpf)
  class Meta:
    model = Cliente

Mais informações sobre widgets e API do ModelForm estão disponíveis na documentação oficial.

Templates e arquivos estáticos

Templates são as páginas HTML que podem ser renderizadas por algum método controlador. Podem ser considerados arquivos estáticos as imagens, arquivos javascript, arquivos css e qualquer outro arquivo externo ao django.
O sistema de templates do Django permite o uso de tags como if e for em conjunto com o HTML. Não será explicado o uso de tal tags nesse momento.
É possível também usar herança, ou seja, um template filho pode conter os atributos do template pai. Esse conceito ficará mais claro quando criarmos nossos templates.
A princípio serão 3 templates – a página inicial (base.html), a página onde serão exibidos os nomes dos clientes cadastrados (clientes.html) e o formulário para cadastrar clientes (clienteform.html).
Primeiro, vamos criar os diretórios dos arquivos estáticos e dos templates dentro do diretório do projeto. Os nomes devem ser iguais aos que foram definidos nas variáveis MEDIA_ROOT e TEMPLATES_DIR no arquivo settings.py:

gu@notebook:~/projetos/sigep$ mkdir files
gu@notebook:~/projetos/sigep$ mkdir templates

Arquivos Estáticos

Como nossa aplicação ainda está em desenvolvimento não vamos nos preocupar com o visual, logo, não mexeremos com CSS e tão pouco imagens. Mas o importante agora é o Javascript. Utilizaremos uma biblioteca javascript chamada JQuery, que possui muitos recursos e torna bem mais fácil a manipulação de elementos e o uso do ajax.
Vamos ao passo-a-passo:

    1. Baixem a JQuery no site www.jquery.com e coloquem dentro do diretório files que criamos ainda a pouco.

    2. Criaremos o arquivo sigep.js dentro do diretório files. Esse arquivo terá todas as nossas funções em Javascript.
    Graças à JQuery podemos nos referir à um elemento HTML com pouco código. Ao invés de usar o document.getElementsById() usamos $('#id_do_elemento').

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    function Editar(urlprocess,objForm,objSelect)
    {
      var id = $('#'+objSelect+' option:selected').val();
      if ((id > 0) && (id != '')) {
        $('#'+objForm).attr('action',urlprocess);
        $('#'+objForm).submit();
      } else
        alert('Selecione um item primeiro.');
    }
     
    function Excluir(urlprocess,objForm,objSelect)
    {
      if (confirm('Tem certeza?'))
        Editar(urlprocess,objForm,objSelect)
    }

    3. Vamos fazer um mapeamento de URL apontando para o diretório files.
    Edite o arquivo urls.py e adicione no urlpatterns:

    1
    
    (r'^files/(.*)','django.views.static.serve',{'document_root':'/home/gu/projetos/sigep/files'}),

    Agora utilize um editor HTML e vamos para criar nossos templates.

    Arquivos de Templates

    1. base.html

    Esse arquivo será o esqueleto do nosso template. É muito importante que a JQuery seja o primeiro javascript a ser chamado. Basta incluí-lo para poder usar todos os seus recursos.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    <!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>
      <meta http-equiv="content-type" content="text/html;charset=utf-8" />
      <title>SIGEP - Sistema de Gest&atilde;o de Provedor</title>
      <script language="javascript" type="text/javascript" src="/files/jquery-1.2.6.min.js"></script>
      <script language="javascript" type="text/javascript" src="/files/sigep.js"></script>
      <style type="text/css">
        ul, li { list-style: none; padding: 0px; margin: 0px; }
      </style>
    </head>
    <body>
      <div id="divMenuSuper">
        <a href="/cliente/list/">Pagina Principal</a>
      </div>
      <div id="divEsqueleto">
        {% block principal %}
        {% endblock %}
      </div>
    </body>
    </html>

    2. clientes.html

    Nesse arquivo serão listados todos os clientes cadastrados. Reparem que não foi definido um action para o form pois será utilizado javascript para submeter o formulário via post.

    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
    
    {% extends 'base.html' %}
    {% block principal %}
     
    {% ifequal operacao "Cadastrar" %}
    <form name="buscacliente" id="frmBuscaCliente" method="post" action="/cliente/search/">
    <div id="divBuscaCliente">
      <br />Buscar por nome ou CPF: <input type="text" name="busca" id="id_busca">
      <input type="submit" name="btBuscar" value="Buscar">
    </div>
    </form>
     
    <form name="listacliente" id="frmListaCliente" method="post" action="">
    <div id="divListaCliente">
     
      <h2>{{titulo|default:"CLIENTES CADASTRADOS"}} - TOTAL: {{clientes|length}}</h2>
      {% if not clientes %}
        Nenhum cliente cadastrado.
      {% else %}
     
        Nome:
        <select name="listaclientes" id="id_cliente">
          {% for c in clientes %}
            <option value="{{c.id}}">{{c.nome|upper}}</option>
          {% endfor %}
        </select>
     
        <br /><br />
        <input type="button" name="btEditar" value="Editar" onclick="Editar('/cliente/edit/','frmListaCliente','id_cliente')">
        <input type="button" name="btExcluir" value="Excluir" onclick="Excluir('/cliente/delete/','frmListaCliente','id_cliente')">
      {% endif %}
     
    </div>
    </form>
    {% endifequal %}
    {% block clienteform %}{% endblock %}
    {% endblock %}

    3. clienteform.html

    Contém nosso formulário para cadastrar e editar dados do cliente. A variável form é um objeto do tipo ClienteForm. É possível gerar todos os campos utilizando {{form.as_table}} ou {{form.as_p}}, porém os campos seriam exibidos dentro de uma tabela ou em parágrafos.

    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
    41
    42
    43
    44
    45
    46
    
    {% extends 'clientes.html' %}
     
    {% block clienteform %}
    <form name="clienteform" id="frmCliente" method="post" action="{{form_url|default:"/cliente/add/"}}">
    <div id="divFormCliente">
     
      <h2>{{operacao|upper|default:"CADASTRAR"}} CLIENTE</h2>
      <!-- ID do cliente -->
      <input type="hidden" name="id" id="id_cliente" value="{{id_cliente}}">
      Nome ou Raz&atilde;o Social: {{form.nome}}<br />
      Apelido ou Nome Fantasia: {{form.apelido}}<br />
      CPF ou CNPJ: {{form.cpf}}<br />
      RG ou Insc. Estadual: {{form.rg}}<br />
      Org&atilde;o Exp. RG: {{form.orgao_rg}}<br />
      Tipo Pessoa: {{form.tipo_pessoa}}<br />
      Data de Nasc.: {{form.data_nascimento}}<br />
      Grupo: {{form.grupovencimento}}<br />
      Bairro:
      <select name="bairro">
        {% for b in bairros %}
     
          <option value="{{b.id}}">{{b.bairro}}</option>
        {% endfor %}
      </select><br />
      Endereco: <select name="logradouro" id="id_logradouro"></select>
      Numero: {{form.numero}} CEP: {{form.cep}}<br />
      Referencia: {{form.referencia}}<br /><br />
     
      <input type="submit" value="{{operacao|default:"Cadastrar"}}">
    </div>
    </form>
     
    <div id="divErro" style="color:red;">
      <br />
      {% ifequal mensagem "ok" %}
        Cadastro realizado com sucesso.
      {% else %}
        {% for campo in form %}
          {% if campo.errors %}
            <br />{{campo.label}} {{campo.errors}}
          {% endif %}
        {% endfor %}
      {% endifequal %}
    </div>
     
    {% endblock %}

    Reparem que criamos manualmente um elemento para representar o endereço (logradouro). Fizemos isso porque esse campo será preenchido utilizando ajax quando for selecionado um bairro.
    O formulário será submetido e os campos validados. Então a variável mensagem receberá o valor “ok” se o formulário passar na validação ou “erro” se não passar, e então varre o vetor form obtendo o objeto chamado campo e verifica se há alguma mensagem de erro referente ao campo. Uma melhor abordagem sobre ModelForm pode ser obtida na documentação do Django.
    Agora que já criamos nossos templates, podemos começar a escrever nossas views.

    Pages: 1 2 3 4 5

You can leave a response, or trackback from your own site.

11 Responses to “Django com MySQL, JQuery, Ajax e JSON – Parte 1”

  1. Relsi disse:

    Muito legal o tuto, parabéns!!

    Hugs!!

  2. Abaster disse:

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

  3. Rânielli The head disse:

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

  4. Leandro disse:

    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 ?

  5. 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…

  6. 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…

  7. Maria disse:

    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

  8. Excelente tutorial, colega. :)

    Parabéns XD

  9. Helder disse:

    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” )

  10. luiz Martins disse:

    Ola gostei do material que vc publicou, vc terminou a segunda parte deste tutorial referente ao sistema???

    • gustavohenrique disse:

      @Luiz, nao cheguei a terminar, mas escrevi um artigo aqui no blog que fala um pouco sobre. O titulo é “Servidor Linux com Proxy e Controle de Banda”.
      []’s

Leave a Reply

Powered by WordPress | Shop the Best Verizon Wireless Deals. | Thanks to Best CD Rates, Credit Cards and Credit card