2. Sumário
1.Sofisticando seu CMS...........................................................................................3
2.Adicionando um Editor de Rich-Text..................................................................3
3.Adicionando um sistema de busca.......................................................................5
4.Melhorando o sistema de busca............................................................................8
5.Cuidados com a segurança quando usamos um sistema de busca..................10
6. Desenvolvendo uma URL para contato............................................................10
3. 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 admin
admin.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'),
4. (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.html
2. admin/flatpages/change_form.html
3. 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({
5. 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:
6. /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/ servidor
from 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 templates
from django.template import loader, Context
# FlatPage é um modelo de classe que representa as páginas CMS
from django.contrib.flatpages.models import FlatPage
# define a função Python, com request uma instância de django.http.HttpRequest
def 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>
7. </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 admin
admin.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' }),
8. (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 HttpResponse
from django.template import loader, Context
from 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_response
from 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.
9. 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.
10. 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 a
seguranç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' }),
11. (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.py
from django.shortcuts import render_to_response
from 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>
12. </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/
13. Até agora só geramos a entrada de dados, vamos agora fazer a verificação dos dados.
from django.shortcuts import render_to_response
from 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','semretorno@example.com']
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,
['administrador@example.com'])
E finalmente redirecionamos nosso site para a página de agradecimento.
14. 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='seu_email@gmail.com'
EMAIL_HOST_PASSWORD='senha'
EMAIL_PORT=587
EMAIL_USE_TLS=True
Agora veja como ficou nosso arquivo views.py, no diretório contato:
from django.core.mail import send_mail
from django.shortcuts import render_to_response
from 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','semretorno@example.com')
send_mail('Retorno do seu site, topico: %s'%topico ,usuario+":"+mensagem,
15. usuario,['asergionogueira@ig.com.br'])
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.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(),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/