Pular para o conteúdo

Criando uma aplicação web com Django e JQuery

Postado em 10 minutos de leitura

Recentemente migrei um projeto de um gerenciador de provedores de internet escrito em PHP utilizando Code Igniter para Django 1.0 e vou utilizar como exemplo para demonstrar como criar uma aplicação web com Django e JQuery usando Ajax. O sistema permite o cadastro de clientes, controle de banda, regras de firewall, fluxo de caixa e relatórios gerenciais, interagindo com ferramentas do terminal Linux.

Iniciando

A aplicação foi escrita em um ambiente contendo as seguintes configurações:

  • Ubuntu 8.04
  • Python 2.5
  • MySQL 5.0
  • VIM editor

Não vou abordar como instalar o Django no Ubuntu. Recomendo uma leitura na documentação oficial pois, dependendo da data que esse texto estiver sendo lido, o processo de instalação pode mudar.

Projeto vs Aplicação

Em Django, projeto é o sistema no todo e aplicação é um módulo desse sistema. No projeto podemos ter várias aplicações como: cliente, rede, relatório etc. Você pode criar uma única aplicação contendo toda funcionalidade do sistema, porém isso deixaria o código mais extenso e de difícil manutenção.

Criando um projeto

Vou chamar o projeto de Sigep (Sistema de Gerenciamento de Provedores - dããã, eu sei). Abra um terminal Linux e execute os comandos abaixo:

django-admin.py startproject sigep
cd sigep
/bin/ls -1 sigep

A saída do comandos ls deve ser:

__init__.py
manage.py
settings.py
urls.py

O django-admin.py criou um diretório com o nome do projeto contendo os seguintes arquivos:

  • init.py: arquivo sem conteúdo utilizado para identificar que é um pacote Python
  • manage.py: script para gerenciar o projeto Django, criar aplicações e rodar o projeto
  • settings.py: contém as configurações do projeto como log e banco de dados
  • urls.py: arquivo de rotas/mapeamento das URLs

Configurando o projeto

Edite o arquivo settings.py adicionando:

import os
LOCAL = lambda *args:os.path.join(os.path.dirname(__file__), *args)

As linhas acimas criam uma função para retornar o caminho absoluto do diretório do projeto. Em seguida, altere as variáveis dentro do settings.py conforme abaixo:

DATABASE_ENGINE = 'mysql'
DATABASE_NAME = 'sigepdjango'
DATABASE_USER = 'usuario_do_mysql_aki'
DATABASE_PASSWORD = 'senha_do_usuario_do_mysql_aki'

TIME_ZONE = 'America/Sao_Paulo'
LANGUAGE_CODE = 'pt-br'
MEDIA_ROOT = LOCAL('media')
TEMPLATE_DIRS = (
    LOCAL('templates')
)

A configuração acima define a conexão com o banco de dados MySQL, ajusta o timezone e idioma de acordo com o Brasil, informa o caminho do MEDIA_ROOT, que é o diretório onde os arquivos externos (imagens, CSS e Javascript) serão armazenados e por último o diretório de templates HTML.

O próximo passo é criar a aplicação principal.

Criando uma aplicação

Utilize o manage.py startpp para criar uma aplicação:

python manage.py startapp cliente

O startapp cria um diretório contendo:

  • init.py: tal como no diretório do projeto, indica que a aplicação também é um pacote
  • models.py: classes que correspondem as tabelas MySQL
  • views.py: contém as funções responsáveis por receber os requests de acordo com a rota definida no urls.py

Criando os modelos

Um model contém a estrutura de dados do sistema. A grosso modo, pode-se dizer que é o arquivo que contém classes que correspondem às tabelas do banco de dados, e os atributos dessas classes correspondem aos campos das tabelas. Os models do Django utilizam um design pattern conhecido como ORM, no qual um objeto possui métodos para lidar com a camada de acesso ao banco de dados. Cada aplicação no Django contém um arquivo chamado models.py. As classes devem ser adicionadas nesse arquivo:

from django.db import models
 
class Bairro(models.Model):
	bairro = models.CharField(max_length=150)
	def __unicode__(self):
		return self.bairro
	class Meta:
		db_table = 'bairro'

class Logradouro(models.Model):
	bairro = models.ForeignKey(Bairro)
	logradouro = models.CharField(max_length=250)
	def __unicode__(self):
		return self.logradouro

    class Meta:
		db_table = 'logradouro'

class GrupoVencimento(models.Model):
	grupo_vencimento = models.CharField("Grupo",max_length=20)
	dia_vencimento = models.IntegerField("Dia",max_length=2)
	def __unicode__(self):
		return self.grupo_vencimento
	class Meta:
		db_table = 'grupovencimento'
		verbose_name = 'Grupo de Vencimento'
		verbose_name_plural = 'Grupos de Vencimento'
		unique_together = ['grupo_vencimento']
 
class Cliente(models.Model):
	TIPO_PESSOA = (
		('F','Pessoa Fisica'),
		('J','Pessoa Juridica'),
		('R','Representante de Pessoa Juridica')
	)
	grupovencimento = models.ForeignKey(GrupoVencimento,verbose_name="Grupo")
	nome = models.CharField("Nome/Razao Social",max_length=200)
	apelido = models.CharField("Apelido/Nome Fantasia",max_length=200,blank=True,null=True)
	cpf = models.CharField("CPF/CNPJ",max_length=14,unique=True)
	rg = models.CharField("RG/IE",max_length=11,blank=True,null=True)
	orgao_rg = models.CharField("Orgao RG",max_length=6,blank=True,null=True)
	tipo_pessoa = models.CharField(max_length=1,choices=TIPO_PESSOA)
	data_nascimento = models.DateField(blank=True,null=True)
	data_cadastro = models.DateField(auto_now_add=True)
	logradouro = models.ForeignKey(Logradouro,verbose_name='Endereco',blank=True,null=True)
	numero = models.CharField(max_length=50,blank=True,null=True)
	referencia = models.CharField(max_length=250,blank=True,null=True)
	cep = models.PositiveIntegerField(max_length=8,blank=True,null=True)
	def __unicode__(self):
		return self.nome
	class Meta:
		db_table = 'cliente'
		unique_together = ('nome','cpf','rg')

Crie o database no MySQL e em seguida rode o comando manage.py syncdb para criar as tabelas:

mysqladmin -u root -p create sigepdjang
python manage.py syncdb

Uma mensagem perguntando se deseja você deseja criar um super-usuário para acesso ao nosso sistema será exibida. Esse tipo de autenticação do Django é usado na interface de administração automática (conhecido como Django Admin). Digite yes para poder criar uma conta. Digite o nome do super-usuário, um e-mail válido e uma senha. Se tudo deu certo, no final será exibido:

Superuser created successfully.
Installing index for auth.Permission model
Installing index for auth.Message model

Adicione a aplicação na variável INSTALLED_APPS dentro do arquivo settings.py. Essa variável contém as aplicações utilizadas no projeto, portanto, cada aplicação criada precisa ser inserida dentro desse array:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'sigep.cliente',
)

Habilitando o Django Admin

O Django Admin é uma interface simples e prática para utilizar no dia-a-dia. Ela fornece um CRUD completo sobre os modelos criados em cada aplicação. Para habilitá-la, adicione no INSTALLED_APPS e descomente algumas linhas no arquivo urls.py:

# settings.py
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'sigep.cliente',
    'django.contrib.admin',  # Adicione após as aplicações criadas 
)

# urls.py
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),
)

Cada classe modelo precisa ser configurada para funcionar no Django Admin. Isso é feito criando o arquivo admin.py dentro do diretório da aplicação contendo uma chamada à função admin.site.register. O Django Admin possui várias opções de configuração que são definidas através de herança (conceito de orientação à objetos). Para customizar o Admin, é necessário criar uma classe que extende de admin.ModelAdmin:

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)

Aplique as configurações do Django Admin executando o comando syncdb. Rode a aplicação com o comando runserver e acesse pelo browser o endereço http://localhost:8000/admin.

python manage.py syncdb
python runserver

Se quiser alterar o visual 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 forms

O Django permite que sejam gerados forms a partir das classes modelos. Desse modo é possível tratar os erros de preenchimento utilizando métodos nativos para validação de formulários. Para criar esse tipo de form, basta criar uma classe que estende de ModelForm e adicionar o model desejado. Crie o arquivo forms.py dentro do diretório da aplicação contendo:

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:

widget_nome = TextInput(attrs={'onBlur': mark_safe("alert('Exemplo widget')")})
widget_cpf =  TextInput(attrs={'style':"width:135px;",})
class ClienteForm(ModelForm):
    nome = CharField(max_length=200,widget=widget_nome)
    cpf = CharField(widget=widget_cpf)
    class Meta:
        model = Cliente

Arquivos estáticos

São imagens, documentos, código Javascript e CSS. Eles devem ficar armazenados no diretório definido na variável MEDIA_ROOT no settings.py. Crie o diretório media na raiz do projeto. Faça o download da biblioteca JQuery e coloque dentro desse diretório:

mkdir media
cd media
wget http://www.jquery.com/download/jquery-1.2.6.min.js

JQuery é uma poderosa biblioteca Javascript que facilita a manipulação de elementos HTML e o uso de Ajax para obter dados sem precisar atualizar a página. Crie o arquivo sigep.js dentro do diretório media contendo:

function editar(url, form, select) {
    var id = $('#'+select+' option:selected').val();
    var $form = $('#'+form);
    if (id && id > 0) {
        $form.attr('action', url);
        $form.submit();
    } else {
        alert('Selecione um item primeiro.');
    }
}
 
function excluir(url, form, select) {
    if (confirm('Tem certeza?')) {
        editar(url, form, select);
    }
}

O arquivo sigep.js possui 2 funções: editar, que verifica se foi selecionada alguma opção com id diferente de zero no <select> e faz um submit do <form>; e excluir, que pede confirmação do usuário antes de submeter o formulário.

Para configurar o Django para servir os arquivos estáticos, altere o urls.py adicionando dentro da variável urlpatterns:

(r'^files/(.*)','django.views.static.serve',{'document_root':'./files'}),

Templates

Templates são arquivos HTML que são renderizados pelo Django, substituindo variáveis pelos seus respectivos valores. O sistema de templates do Django permite o uso de tags como if e for em conjunto com o HTML. É possível também usar herança, ou seja, um template filho pode conter os atributos do template pai. Os templates devem ficar dentro do diretório definido na variável TEMPLATES_DIR no settings.py.

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 (form.html).

Criando o diretório templates

mkdir templates

Criando o template base

Esse é o template que serve como base para os outros templates. Nesse arquivo que você deve carregar os estáticos. Crie o base.html:

<!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="/media/jquery-1.2.6.min.js"></script>
	<script language="javascript" type="text/javascript" src="/media/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>

Criando o template para listagem de clientes

Esse arquivo será utilizado para mostrar a lista de clientes cadastrados. Reparem que não foi definido um action para o form pois será utilizado Javascript para submeter o formulário via POST, através da função editar do arquivo sigep.js. Crie o clientes.html:

{% 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 form %}{% endblock %}
{% endblock %}

Criando o formulário de cadastro

Nesse template vou utilizar algumas das facilidades fornecidas pelo ModelForm do Django. A variável form é uma instância da classe ClienteForm criada no arquivo forms.py. É possível simplicar ainda mais a criação do formulário se utilizar os métodos {{form.as_p}} ou {{form.as_table}}. Crie o arquivo form.html:

{% 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>
		<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. Depois varre o array 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.

O próximo passo é a criação das views.

Infelizmente não consegui recuperar o restante desse texto escrito em 2008.