15
Django Módulo Básico Desenvolvendo uma aplicação WEB usando o framework DJANGO (parte II) Antonio Sérgio Nogueira 2010

Django Módulo Básico Parte II

Embed Size (px)

DESCRIPTION

Continuação da parte I, agora melhoramos nosso CMS, inserimos URL de busca, desenvolvemos uma URL para contato

Citation preview

Page 1: Django Módulo Básico Parte II

Django Módulo Básico Desenvolvendo uma aplicação WEB

usando o frameworkDJANGO(parte II)

Antonio Sérgio Nogueira2010

Page 2: Django Módulo Básico Parte II

Sumário1.Sofisticando seu CMS...........................................................................................32.Adicionando um Editor de Rich-Text..................................................................33.Adicionando um sistema de busca.......................................................................5 4.Melhorando o sistema de busca............................................................................85.Cuidados com a segurança quando usamos um sistema de busca..................106. Desenvolvendo uma URL para contato............................................................10

Page 3: Django Módulo Básico Parte II

1. Sofisticando seu CMS – no último capítulo, da parte I deste documento, disponibilizamos um sistema de gerenciamento de conteúdo, através das aplicações contrib, projetadas para adicionar características que diminuem a quantidade de código. Nesta ocasião citamos o admin e mostramos as páginas planas (flatpages). As flatpages são bastantes simples e vamos customizá-las utilizando um editor rich-text no admin.

2. Adicionando um editor de Rich-Text (formato de arquivo de documento desenvolvido e de propriedade da Microsoft desde 1987 para intercâmbio de documentos entre diversas plataformas ) - as aplicações que usam flatpages já possuem qualidade, mas você pode adicionar um pouco mais de qualidade a estas aplicações (nos sites desenvolvidos com Django normalmente a página “About page” é uma flatpage), sem ter que digitar um texto HTML. Existem vários editores rich-text em Javascript, mas aqui nós usaremos um chamado TinyMCE, que é bastante popular e é o que tem um suporte melhor para navegadores. Além disso é software livre e você pode baixar uma cópia dele em http://tinymce.moxiecode.com/ , descompacte o pacote e dentro do pacote você encontrará um diretório jscripts/tiny_mce. Agora anote o diretório onde você colocou o arquivo e copie a pasta /tiny_mce para o diretório /meu_site/foto/js. No meu caso o diretório onde serão armazenados os arquivos estáticos é o diretório /meu_site/foto e depois edite o arquivo urls.py de seu projeto. Modifique o arquivo urls.py para que fique como abaixo ( atenção o path do document_root deve ser o caminho que está em seu micro):

from django.conf.urls.defaults import *from meu_site.views import *from django.conf import settings

# Uncomment the next two lines to enable the admin:from django.contrib import adminadmin.autodiscover()

urlpatterns = patterns('', # Example: # (r'^meu_site/', include('meu_site.foo.urls')),

# Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: #(r'^admin/doc/', include('django.contrib.admindocs.urls')),

# Uncomment the next line to enable the admin: (r'^admin/(.*)', admin.site.root), #(r'^admin/',include('django.contrib.admin')), (r'^livros/$','meu_site.livros.views.lista_livros'),

Page 4: Django Módulo Básico Parte II

(r'^foto/(.*)$', 'django.views.static.serve', {'document_root':settings.MEDIA_ROOT}), (r'^tiny_mce/(?P<path>.*)$', 'django.views.static.serve', { 'document_root': '/../../foto/js/tiny_mce/tiny_mce.js' }), (r'',include('django.contrib.flatpages.urls')),)

No arquivo settings.py coloque esta linha com o endereço da mídia, para que o software localize o arquivos de mídia.#settings.py

# Absolute path to the directory that holds media.# Example: "/home/media/media.lawrence.com/"MEDIA_ROOT = os.path.join(PROJECT_ROOT_PATH,'foto').replace('\\','/')

Recomendação: O uso do Django para servir arquivos estáticos terá impacto negativo na sua aplicação, por isso ao colocar o software em produção veja as especificações do Django para que o servidor de aplicação faça esse serviço.

Nós adicionamos ao nosso site uma chamada de JavaScript para usarmos com as nossas páginas planas. Agora nós necessitamos de um modelo(template) que será usado para edição e adição das páginas planas. Por default, a aplicação admin buscará pela template em vários locais, e usará o primeiro que encontrar. Os nomes de template, por ordem de busca, que serão procurados são:

1. admin/flatpages/flatpage/change_form.html2. admin/flatpages/change_form.html3. admin/change_form.html

Após encontrar a template o Django usará ela para adição e edição de todas as páginas que não forem fornecida a template, usando uma lista de templates o Django permite que você sobreponha a interface para uma aplicação específica. Agora vamos criar um diretório em templates “admin/flatpages/flatpage e dentro dele vamos colocar um arquivo chamado change_form.html. Este arquivo encontra-se em django/contrib/admin/templates/admin/change_form.html(diretório onde está instalado o Django). Agora vamos abrir o arquivo e alterá-lo para que tenhamos acesso ao JavaScript do TinyMCE. Este arquivo é bastante complexo podendo ser adaptado para qualquer modelo de dados. A mudança que faremos é a seguinte:

– Localize a linha 6 e veja que nela temos: {{ media }}– Adicione abaixo dela:

<script type="text/javascript" src="/../../foto/js/tiny_mce/tiny_mce.js"> </script><script type="text/javascript">tinyMCE.init({

Page 5: Django Módulo Básico Parte II

mode: "textareas", theme: "advanced"});</script>

Veja que você fará uso da URL que você definiu para servir os arquivos TinyMCE.Após salvar a modificação volte ao navegador e acesse as páginas planas e veja que existe um editor TinyMCE, que pode ser customizado, agregado a página de conteúdo. Outros editores(RTE -Rich Text Editor) também podem ser agregados desta mesma maneira.

3. Adicionando um sistema de busca – agora desenvolveremos nossas aplicações em Python e adicionaremos esta característica ao Django. Vamos desenvolver um sistema de busca independente que pode ser usado para consultar e retornar uma lista de páginas que contenham o assunto procurado.Digite o comando: python manage.py startapp busca.Um diretório de projeto foi criado:

Page 6: Django Módulo Básico Parte II

/busca __init__.py → este arquivo indica que o diretório é um módulo Python views.py → contém as funções de controle que respondem ao HTTP models.py → contém os modelos de dados da aplicação

Agora vamos importar os módulos necessários para desenvolver nossa vista(não se esqueça que a view é onde armazenamos o módulo de controle, modelo MVC).#views.py# classe que retorna a resposta no formato HTTP adequado p/ servidorfrom django.http import HttpResponse# módulo loader, funções para trabalhar as templates (diretório especificado em # TEMPLATE_DIRS)# Context classe usada para representar variáveis das templatesfrom django.template import loader, Context# FlatPage é um modelo de classe que representa as páginas CMSfrom django.contrib.flatpages.models import FlatPage

# define a função Python, com request uma instância de django.http.HttpRequestdef busca(request):

# busca uma variável q. O Django analisa ela e resulta uma HttpRequest com # como http://www.example.com/busca?q=oquevcquer # o atributo GET é um dicionário com o nome q e o valor oquevcquer

query = request.GET['q']

# quase todas as classes Django possuem um atributo objects # que pode ser usado para busca no modelo, neste caso filtrado através do #método filters nas flatpages, com argumento content_icontains

results = FlatPage.objects.filter(content__icontains=query)

#com a busca e seu resultado produzimos o HTML e anexamos o conteúdo da # busca e retornamos a resposta com o HTML final processado

template = loader.get_template('busca/busca.html')context = Context({ 'query': query, 'results': results })response = template.render(context)return HttpResponse(response)

Vamos criar o template busca.html no subdiretório templates/busca do meu_site e dentro dele armazenamos o arquivo.

Busca.html<html> <head> <title>Busca</title>

Page 7: Django Módulo Básico Parte II

</head> <body> <p>Você procura por:"{{ query }}"; o resultado está abaixo.</p> <ul> {% for page in results %} <li><a href="{{ page.get_absolute_url }}">{{ page.title }}</a></li> {% endfor %} </ul> </body></html>Note que o arquivo faz uso das variáveis passadas para ele (query e results) veja que o arquivo usa as variáveis entre dois parantêses, é a forma de mostrar diretamente o resultado da variável. Nós também estamos usando as tags do template for e endfor para fazer um loop e mostrar todos os resultados obtidos. Veja também que temos dentro do loop {{page.title}} o campo título e o método {{page.get_absolute_url}} que retorna o URL usado para referenciar o objeto, isto faz parte do modelo FlatPage . Abra o arquivo urls.py e digite a linha abaixo depois da linha TinyMCE e antes da linha que captura todos os padrões das páginas planas.from django.conf.urls.defaults import *from meu_site.views import *from django.conf import settings#from meu_site.livros.views import *

# Uncomment the next two lines to enable the admin:from django.contrib import adminadmin.autodiscover()

urlpatterns = patterns('', # Example: # (r'^meu_site/', include('meu_site.foo.urls')),

# Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: #(r'^admin/doc/', include('django.contrib.admindocs.urls')),

# Uncomment the next line to enable the admin: (r'^admin/(.*)', admin.site.root), #(r'^admin/',include('django.contrib.admin')), (r'^livros/$','meu_site.livros.views.lista_livros'), (r'^foto/(.*)$', 'django.views.static.serve', {'document_root':settings.MEDIA_ROOT}), (r'^tiny_mce/(?P<path>.*)$', 'django.views.static.serve',

{ 'document_root': '/../../foto/js/tiny_mce/tiny_mce.js' }),

Page 8: Django Módulo Básico Parte II

(r'^busca/$', 'meu_site.busca.views.busca'), (r'',include('django.contrib.flatpages.urls')), ) Use a seguinte URL para testar as buscas, substitua sss pela palavra que procura:http://localhost:8080/busca/?q=sss .

Este arquivo views.py abaixo quando você digitar apenas http://localhost:8080/busca/ não dá erro porque você definiu através do get um valor default para a variável q, o que não ocorre com o anterior.# Create your views here.from django.http import HttpResponsefrom django.template import loader, Contextfrom django.contrib.flatpages.models import FlatPage

def busca(request):query = request.GET.get('q', " ")results = FlatPage.objects.filter(content__icontains=query)template = loader.get_template('busca/busca.html')context = Context({ 'query': query, 'results': results })response = template.render(context)return HttpResponse(response)

4. Melhorando o sistema de busca – agora colocaremos um formulário para entrada dos dados e reduziremos a busca usando uma função chamada shorcuts que reduz todo esse trabalho, fazendo a carga da template, processando a saida e criando a resposta num único comando. Edite seu arquivo views.py no diretório de busca e deixe ele com o formato abaixo.from django.shortcuts import render_to_responsefrom django.contrib.flatpages.models import FlatPage

def busca(request): query = request.GET.get('q', ' ') results = [ ] if query: results = FlatPage.objects.filter(content__icontains=query) return render_to_response('busca/busca.html', { 'query': query, 'results': results })Teste o sistema que ele funciona perfeitamente.

Agora vamos modificar o template busca.html em /templates/busca.

Page 9: Django Módulo Básico Parte II

busca.html<html> <head> <title>Busca</title> </head> <body> <form method="get" action="/search/"> <p><label for="id_q">Busca:</label> <input type="text" name="q" id="id_q" value="{{ query }}" /> <input type="submit" value="Executa" /></p> </form> {% if results %} <p>Você procura por:"{{ query }}"; o resultado está listado abaixo.</p> <ul> {% for page in results %} <li><a href="{{ page.get_absolute_url }}">{{ page.title }}</a></li> {% endfor %} </ul> {% else %} {% if query %} <p>Não encontrei nenhum resultado.</p> {% else %} <p>Digite a busca na caixa abaixo e pressione "Executa" para buscar.</p> {% endif %} {% endif %} </body></html>Agora você irá executar a URL http://localhost:8080/busca/ e veja o que ocorre:

Este é o resultado que aparece em meu micro onde já cadastrei algumas flatpages.

Page 10: Django Módulo Básico Parte II

5. Cuidados com a segurança quando usamos um sistema de busca - as aplicações web possuem uma vulnerabilidade do sistema de segurança que é o Cross-site scripting(XSS), este ataque ocorre quando injetam scripts maliciosos, no lado do cliente, em páginas web vistas por outros usuários. Através de um XSS, o hacker injeta códigos JavaScript em um campo texto que ao ser apresentado executa o script malicioso podendo causar muitos danos. Isto pode ser evitado pelo servidor se ele remover caracteres que formam as tags HTML. Uma outra forma de ataque é a chamada injeção SQL, onde o hacker usa uma entrada de usuário para fazer uma consulta ao banco de dados, por exemplo o hacker pode enviar o texto DROP DATABASE, que se cegamente executado pode apagar o banco. Para estes ataques o Django possui em primeiro lugar templates que automaticamente “escapam”(modificam o conteúdo) o conteúdo de variáveis evitando assim que elas sejam um código HTML executado pelo navegador, em segundo lugar ao usar models o Django constrói consultas ao banco de dados de forma que a injeção não é possível. Toda vez que você está lidando com os dados apresentados pelo usuário, você precisa de cuidado e garantia que você está tomando as medidas adequadas para preservar asegurança do seu site.

6.Desenvolvendo uma URL para contato – em primeiro lugar vamos desenvolver uma aplicação independente de contato. Digite no seu console: python manage.py startapp contato.Não devemos esquecer que o nosso OS é o Windows e estamos com o python e o django instalados e que o nosso diretório de trabalho é /meu_site, onde criamos nossa aplicação. A partir do momento que digitamos o comando um novo subdiretório foi criado com o nome contato, e que agora iremos alterar os arquivos para gerar a aplicação.Ao criar um formulário para contato devemos ter em mente que ele deve ser claro e útil e você deve validar os campos necessários de forma a evitar erros. Se ao enviar o formulário o mesmo contiver erros devemos mostrar os dados e avisar onde o erro ocorre evitando uma nova digitação das partes desnecessárias. O Django fará a maioria do trabalho necessário desde que você forneça a descrição do campo, as regras de validação e um simples template.

6.1 Criando o formulário de contato – o contato é uma forma de você conseguir aumentar a audiência de seu site , vamos então começar digitando no arquivo de URL(urls.py) a linha:(r'^contato/$', 'meu_site.contato.views.contato'),….. (r'^livros/$','meu_site.livros.views.lista_livros'), (r'^contato/$','meu_site.contato.views.contato'), (r'^foto/(.*)$', 'django.views.static.serve', {'document_root':settings.MEDIA_ROOT}), (r'^tiny_mce/(?P<path>.*)$', 'django.views.static.serve',

{ 'document_root': '/../../foto/js/tiny_mce/tiny_mce.js' }),

Page 11: Django Módulo Básico Parte II

(r'^busca/$', 'meu_site.busca.views.busca'), (r'',include('django.contrib.flatpages.urls')),)

O formulário Django é criado da mesma forma que os modelos (models) usando uma classe Python. De forma padrão insira o novo formulário no diretório de aplicação (forms.py).from django import forms

ESCOLHA = (( 'geral', 'Informações gerais'),('erro','Relatar erro'),('sugestao','Sugestão'),)

class ContatoForm(forms.Form): topico = forms.ChoiceField(choices=ESCOLHA) mensagem=forms.Charfield(widget=forms.Textarea()) #mensagem=.....,initial=”digite sua mensagem”) põe uma mensagem no #campo usuario=forms.EmailField(required=False)

No nosso formulário temos 3 campos: Tópico, Mensagem e email do usuário. O nosso objeto formulário faz um número de coisas bastante úteis como validar dados, gerar seu HTML, emitir mensagens de erro e desenhar o formulário inteiro.views.pyfrom django.shortcuts import render_to_responsefrom forms import ContatoForm

def contato(request): form=ContatoForm() return render_to_response('contato.html',{'form':form})

Este é o template que devemos digitar:contato.html<html> <head> <title>Contato</title> </head> <body> <h1>Contato</h> <form action="." method="post"> <table> {{ form.as_table}} </table> <p><input type="submit" Value="Enviar"></p>

Page 12: Django Módulo Básico Parte II

</form> </body></html>Veja a linha que tem {{form.as_table}} no arquivo de contato.html , ela indica que iremos passar o formulário de contato como tabela, o Django vai gerar um HTML parecido com as linhas abaixo para o formulário.<tr> <th><label for="id_topico">Topico:</label></th> <td> <select name="topico" id="id_topico"> <option value="geral">Informações Gerais</option> <option value="erro">Relatar Erro</option> <option value="sugestao">Sugestão</option> </select> </td></tr><tr> <th><label for="id_mensagem">Mensagem:</label></th> <td><input type="text" name="mensagem" id="id_message" /></td></tr><tr> <th><label for="id_usuario">Usuario:</label></th> <td><input type="text" name="usuario" id="id_sender" /></td></tr>Veja resultado digitando http://localhost:8080/contato/

Page 13: Django Módulo Básico Parte II

Até agora só geramos a entrada de dados, vamos agora fazer a verificação dos dados.from django.shortcuts import render_to_responsefrom forms import ContatoForm

def contato(request): if request.method == 'POST': form=ContatoForm(request.POST) else: form=ContatoForm() return render_to_response('contato.html',{'form':form})

Veja agora se você não digitar as informações corretamente você verá as mensagens de campo obrigatório ou o aviso que você deve digitar um e-mail no campo. Uma instância do campo de formulário(forms) pode ter 2 estados, vinculado e não vinculado(bound e unbound), ou seja válido ou mostra os dados novamente.

Note que depois que o formulário foi preenchido ele passa sua regra de validação e então os dados estão disponíveis e podemos fazer alguma coisa útil com eles. Se o campo usuário foi preenchido com o e-mail então podemos enviar um retorno ao usuário.

6.2 Processando o Contato – uma vez que o usuário preencheu o formulário é necessário fazer alguma coisa útil com ele. Vamos então responder ao contato através do e-mail.Vamos agora ver se o formulário está vinculado a dados válidos, então chamamos o método is_valid() e se ele for válido usaremos o método cleaned_data para pegarmos o dado mantendo seu formato Python:form=ContatoForm(request.POST)if form.is_valid(): #processa o formulário de dados topico=form.cleaned_data['topico'] mensagem=form.cleaned_data['message'] usuario=form.cleaned_data.get('usuario','[email protected]']Para o usuário foi estabelecido um e-mail caso ele não exista. Agora então enviaremos um e-mail para o administrador.from django.core.mail import send_mail…..

send_mail('Retorno, tópico: %s' % topico, mensagem, usuario,['[email protected]'])

E finalmente redirecionamos nosso site para a página de agradecimento.

Page 14: Django Módulo Básico Parte II

return render_to_response('enviado.html')#enviado.html no diretório templates

<html> <head> <title>Enviado</title> </head> <body> <h1>Enviado com sucesso!</h1> </body></html>

Para enviar o e-mail temos que usar um servidor SMTP numa porta especificada. O usuário e a senha devem ser especificados e servirão para autenticar o servidor STMP, e se a segurança for usada a variável TLS (transport layer security)deve ser True.

Arquivo: settings.py…............#coloque no final do arquivo

EMAIL_HOST='smtp.gmail.com'EMAIL_HOST_USER='[email protected]'EMAIL_HOST_PASSWORD='senha'EMAIL_PORT=587EMAIL_USE_TLS=True

Agora veja como ficou nosso arquivo views.py, no diretório contato:

from django.core.mail import send_mailfrom django.shortcuts import render_to_responsefrom forms import ContatoForm

def contato(request): if request.method == 'POST': form=ContatoForm(request.POST) if form.is_valid(): #processa o formulário de dados topico=form.cleaned_data['topico'] mensagem=form.cleaned_data['mensagem'] usuario=form.cleaned_data.get('usuario','[email protected]') send_mail('Retorno do seu site, topico: %s'%topico ,usuario+":"+mensagem,

Page 15: Django Módulo Básico Parte II

usuario,['[email protected]']) return render_to_response('enviado.html') else: form=ContatoForm() return render_to_response('contato.html',{'form':form})

O arquivo forms.py, que está no diretório contato junto com o arquivo views.py.

forms.pyfrom django import forms

ESCOLHA = (( 'geral', 'Informações gerais'),('erro','Relatar erro'),('sugestao','Sugestão'),)

class ContatoForm(forms.Form): topico = forms.ChoiceField(choices=ESCOLHA) mensagem=forms.CharField(widget=forms.Textarea(),initial="Digite aqui sua Mensagem") usuario=forms.EmailField(required=False)

A mensagem que chegou ao administrador do site. Mostra que ela foi enviada pelo gmail e no corpo da mensagem quem mandou ela e a mensagem do usuário.

Referência Bibliográfica: 1. Bennett, James. Practical Django Projects. Editora Apress, 2008.2. Brandão, Marinho. Aprendendo Django no Planeta Terra. 2009.3. Holovaty, Adrian and Kaplan-Moss, Jacob. The Definitive Guide to Django

Web Development Done Right. Editora Apress, 2008.4. http://docs.djangoproject.com/en/1.1/