Auto-complete com Django e JQuery UI

agosto 19th, 2011

Auto-complete é aquele recurso usado por alguns sites, onde ao digitar alguma coisa em uma caixa de texto, aparecem sugestões que coincidam com os caracteres digitados, bastando clicar para selecionar a opção desejada. É algo que facilita a vida do usuário e também reduz o tráfego de informações entre a aplicação e o banco de dados, o que hoje em dia é algo que vale muito a pena considerar.

Vou apresentar como fazer isso usando o framework Django e a JQuery UI. É necessário um conhecimento básico prévio de Django, pois não vou mostrar todas as etapas da criação da aplicação.

Antes de qualquer coisa, adicione as referências para a JQuery e JQuery UI na página do auto-complete. É recomendável utilizar o CDN do Google, conforme indica na própria página do JQuery UI:

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js" type="text/javascript"></script>

Em primeiro lugar, o exemplo de um model que vamos usar, bem simples para focar na didática:

class Livro(models.Model):
	nome = models.CharField(max_length=100, null=False)
 
	def __unicode__(self):
		return self.nome

Uma simples classe Livro com um campo nome.

Agora, a view que responderá as requisições Ajax. Ela vai receber os caracteres digitados pelo usuário, efetuará uma busca no banco de dados, vai formatar os dados para o auto-complete e devolver a resposta para a requisição Ajax no formato JSON:

from django.http import HttpResponse
from django.utils import simplejson
 
def busca_autocomplete(request):
	busca = request.GET['term']
	livros = Livro.objects.filter(livro__istartswith=busca)
	res = [ dict(id=l.id, label=l.__unicode__(), value=l.__unicode__()) for l in livros ]
 
	return HttpResponse(simplejson.dumps(res), mimetype="application/x-javascript")

Criada a view, é necessário configurar a url para ela, no arquivo urls.py:

(r'^livros/$', 'seu_projeto.sua_aplicacao.views.busca_autocomplete')

A view que criamos logo acima será acionada quando o browser solicitar a url /livros/.

E finalmente, o código Javascript que vai configurar o auto-complete. Ele deve ser colocado na página onde está o campo texto que o usuário vai digitar a informação e, conforme ele for digitando, o auto-complete vai apresentar sugestões baseadas no que ele digitou. Vamos considerar que o id do campo texto será “texto”.

$(function() {
	$( "#texto" ).autocomplete({
		source: "/livros/",
		minLength: 3,
		select: function( event, ui ) {
			alert("ID: " + ui.item.id);
		}
 
	});

Explicando resumidamente… o parâmetro source informa a URL que vai responder à requisição, o parâmetro minLength indica o número mínimo de caracteres que o usuário deverá digitar para acionar o auto-complete e o parâmetro select é a rotina que vai tratar o evento de seleção de uma opção do auto-complete (no nosso caso, exibir um alert com o ID do livro).

[PostgreSQL] Obter locais próximos (fórmula de Haversine)

agosto 16th, 2011

Sabe aquele recurso que algumas redes sociais têm, de exibir os pontos próximos à sua localização? Sim, é possível e bem simples de fazer. A fórmula matemática que faz tudo funcionar chama-se Fórmula de Haversine. Sem mais delongas, vamos ao código:

-- Cálculo da distância entre dois pontos usando a fórmula de Haversine em PostgreSQL
CREATE OR REPLACE FUNCTION distancia_km(lat1 NUMERIC, lng1 NUMERIC, lat2 NUMERIC, lng2 NUMERIC)
RETURNS DOUBLE PRECISION AS
$BODY$
	SELECT 6371 * acos(
		sin( radians($1) ) * sin( radians( $3 ))
	      + cos( radians($1) ) * cos( radians( $3 )) * cos(radians($4) - radians($2))  )
	AS distance;
$BODY$
  LANGUAGE SQL IMMUTABLE
  COST 100;

Suponhamos que exista uma tabela de usuários onde exista os campos latitude e longitude. É fácil criar uma query usando a função acima para trazer os usuários mais próximos do seu local, em um raio de 10 Km:

SELECT * FROM usuarios WHERE distancia_km(minha_latitude, minha_longitude, latitude, longitude) < 10
AND distancia_km(minha_latitude, minha_longitude, latitude, longitude) <> 0

Serão listados os usuários que estão a menos de 10 Km de distância de você.

OBS: Se quiser usar milhas ao invés de quilômetros, use a constante 3959 ao invés de 6371 na função:

-- Cálculo da distância entre dois pontos usando a fórmula de Haversine em PostgreSQL
CREATE OR REPLACE FUNCTION distancia_milhas(lat1 NUMERIC, lng1 NUMERIC, lat2 NUMERIC, lng2 NUMERIC)
RETURNS DOUBLE PRECISION AS
$BODY$
	SELECT 3959 * acos(
		sin( radians($1) ) * sin( radians( $3 ))
	      + cos( radians($1) ) * cos( radians( $3 )) * cos(radians($4) - radians($2))  )
	AS distance;
$BODY$
  LANGUAGE SQL IMMUTABLE
  COST 100;

É hora de aprender uma nova linguagem! Escolhida: Python

janeiro 31st, 2011

PythonSabe aquela velha máxima que diz que um programador deve aprender uma nova linguagem por ano? Pois então, resolvi botar a mão na massa e seguir esta regra. Mas aí vem a pergunta: qual linguagem aprender?? Para decidir, enumerei alguns requisitos: ser orientada a objetos e também funcional, sintaxe simples mas com bastante recursos, comunidade vasta e ativa e ser adequada para desenvolvimento web. De imediato selecionei Ruby, Python e Scala, mas logo excluí Scala da lista, pelo fato de ser uma linguagem bem mais recente e por isso sua comunidade ainda é menor que Ruby e Python. Entretanto, é uma linguagem que promete muito, talvez ano que vem.

Aí começou o dilema… Ruby ou Python? Ambas as linguagens atendem perfeitamente os requisitos que eu coloquei, mas a escolha por Python foi mais pela maturidade da linguagem e também por um framework web que me interessou bastante: Django. É incrível a simplicidade e a objetividade do framework Django, com muito pouco tempo é possível desenvolver uma aplicação simples, como um blog, por exemplo. Além disso, há uma infinidade de aplicações e bibliotecas prontas, o que torna a produtividade ainda maior.

Para quem procura uma linguagem simples, Python é perfeita. Ela consegue aliar simplicidade com uma gama de recursos comparável a linguagens como C/C++ e Java. Para quem possui experiência em C, é possível criar extensões para Python. Há também uma variante de Python que executa na máquina virtual Java, chamada Jython. Ideal quando a aplicação Python necessita usar rotinas em Java. Precisa desenvolver aplicações para desktop? Sim, é possível… WxWindows, GTK, Qt, Tk, etc, é só escolher. Para a web, além do Django, existem vários outros frameworks, como TurboGears, Pylons, Web2Py, etc. O próprio Google escolheu Python como a primeira linguagem para o desenvolvimento de aplicações para a sua plataforma de cloud computing, Google App Engine.

Resumindo, estou aprendendo, mas estou gostando muito de Python. É o tipo de linguagem que a gente fica se perguntando porque não aprendeu antes.

Nginx + Apache + PHP5 + APC + Linux + Memcached = PERFORMANCE!! (parte 2)

janeiro 24th, 2011

Depois de apresentar a configuração do Apache, PHP, APC e Memcached na primeira parte, agora é hora do Nginx. Basicamente, vamos utilizar o Nginx para servir apenas conteúdo estático (imagens, css, javascript, etc), pois ele possui recursos que garantem uma boa performance para este fim, como por exemplo usar o Memcached como cache. Quando ele recebe uma requisição para processar um arquivo PHP, ele “passa a bola” para o Apache, servindo também como um proxy. Fica mais fácil de entender olhando o fluxo abaixo:

                                PHP
requisição --> [Nginx] ------------> [Apache] ---> (PHP + APC)
                  |
                  |
                  |
                  | conteúdo estático
                  | (imagens, js, css, etc)
                  |
            (Memcached)

Após o famoso comando apt-get install nginx, devemos editar os arquivos de configuração e acertar os detalhes para que tudo isso aí em cima funcione corretamente. Vamos começar pelo arquivo /etc/nginx/nginx.conf, onde estão as configurações globais:

user www-data;
worker_processes  2;
 
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;
 
events {
    worker_connections  1024;
}
 
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
 
    access_log  /var/log/nginx/access.log;
    client_body_temp_path /var/lib/nginx/body 1 2;
    sendfile        on;
 
    keepalive_timeout  65;
    tcp_nodelay        on;
 
    # Habilitar a compressão gzip
    gzip  on;
    gzip_buffers 32 8k;
    gzip_comp_level   6;
    gzip_http_version 1.0;
    gzip_min_length   0;
    gzip_types        text/html text/css image/x-icon
        application/x-javascript application/javascript text/javascript application/atom+xml application/xml ;
 
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Não há muito segredo, principalmente se você já mexeu com os arquivos de configuração de outros web servers, como o Apache. O próximo passo agora é a configuração do virtual server, onde ficam os detalhes mais importantes. O arquivo para configuração do virtual server default é o /etc/nginx/sites-enabled/default:

# O alias "wordpressapache" aponta para o servidor Apache,
# onde serão redirecionados os scripts PHP para processamento.
upstream wordpressapache {
        server dominio.com:8080 weight=1 fail_timeout=120s;
}
 
server {
        listen   80;
        server_name www.dominio.com;
        access_log  /var/log/nginx/wordpressapache.access.log;
 
        location / {
                # Diretório raiz do site
                root /home/site;
                # As linhas abaixo servem para configurar o redirecionamento
                # para o servidor Apache, quando necessário.
                proxy_pass      http://wordpressapache;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                client_max_body_size 10m;
                client_body_buffer_size 128k;
                proxy_connect_timeout 90;
                proxy_send_timeout 90;
                proxy_read_timeout 90;
                proxy_buffer_size 4k;
                proxy_buffers 4 32k;
                proxy_busy_buffers_size 64k;
                proxy_temp_file_write_size 64k;
 
                # Aqui vão as configurações para que o Nginx use o Memcached
                # como cache, para aumentar a performance.
                set $memcached_key $uri;
                memcached_pass 127.0.0.1:11211;
                error_page 404 = @fallback;
        }
 
        # Caso a página não seja encontrada no memcached, passa para o Apache.
        location @fallback {
                proxy_pass      http://wordpressapache;
        }
 
        # Quando forem requisitados scripts PHP, redireciona para o Apache.
        location ~* wp\-.*\.php|wp\-admin {
                proxy_pass      http://wordpressapache;
        }
 
        # Todo o conteúdo estático será processado pelo Nginx.
        location ~* \.(htm|html|jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
                root /home/site;
                expires max;
                break;
        }
 
        if (-f $request_filename) {
                break;
        }
 
        # Nega o acesso aos arquivos .htaccess
        location ~ /\.ht {
                deny all;
        }
 
}

Após acertar as configurações, reinicie o daemon do Nginx com o comando /etc/init.d/nginx restart. Podemos conferir o benchmark usando o Apache Benchmark:

 ab -n 1000 -c 5 http://www.dominio.com:80/
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
 
Benchmarking www.dominio.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
 
Server Software:        nginx/0.6.32
Server Hostname:        www.dominio.com
Server Port:            80
 
Document Path:          /
Document Length:        91427 bytes
 
Concurrency Level:      5
Time taken for tests:   1.230 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      91715000 bytes
HTML transferred:       91427000 bytes
Requests per second:    812.80 [#/sec] (mean)
Time per request:       6.152 [ms] (mean)
Time per request:       1.230 [ms] (mean, across all concurrent requests)
Transfer rate:          72798.78 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     2    6   1.8      6      12
Waiting:        1    5   1.4      5      10
Total:          2    6   1.8      6      12
 
Percentage of the requests served within a certain time (ms)
  50%      6
  66%      7
  75%      7
  80%      7
  90%      8
  95%      9
  98%     10
  99%     10
 100%     12 (longest request)

Nginx + Apache + PHP5 + APC + Linux + Memcached = PERFORMANCE!! (parte 1)

janeiro 5th, 2011

PerformanceO blog www.bragil.net passou por várias reformulações, dentre elas, a migração para WordPress 3 e a mudança de hosting para um Linux virtualizado. Graças a toda liberdade proporcionada por um ambiente com acesso root, foi possível fazer uma configuração de hosting bastante performática, que pode servir de base para outras aplicações.

A seguir vou detalhar o passo-a-passo resumido da configuração usada, que eu apelidei carinhosamente de NAPALM (sigla para Nginx + Apache + PHP + APC + Linux + Memcached).

Nginx é um servidor web que tem ganhado fama por ser extremamente rápido e também por ser uma excelente escolha para servir conteúdo estático, sendo usado como proxy para servidores de aplicação.

O Apache dispensa apresentações, assim como o PHP.

O APC é uma extensão para o PHP que otimiza o código intermediário e mantém um cache dos dados e do código compilado na memória compartilhada. Isto faz aumentar sensivelmente a performance de aplicações PHP.

O Memcached é um sistema de cache em memória de alta performance, bastante usado por grandes nomes da Internet, como Twitter, Flickr, Wikipedia, Youtube, dentre outros.

Quer performance para sua aplicação PHP? Basta misturar isso tudo!! E o melhor, a configuração é tranquila.

Para começar, instale o Apache 2 e o PHP 5. Não vou abordar a instalação e configuração do servidor Apache 2 + PHP 5, pois basta ir no Google, você encontrará bastante coisa.

Configuração do Apache

Depois do Apache + PHP instalados e configurados, altere a porta onde o Apache receberá as conexões para 8080. No Debian, edite as seguintes linhas do arquivo /etc/apache2/ports.conf para o seguinte:

NameVirtualHost dominio.com:8080
Listen 8080

E altere também a porta na configuração do virtual host:

VirtualHost dominio.com:8088

Isto significa que o Apache deixará de atender as requisições na porta 80 (padrão). Ou seja, usaremos o Apache apenas para processar os arquivos PHP, deixando todo o conteúdo estático (imagens, javascript, css, etc) para o Nginx.

Reinicie o servidor Apache. No Debian, o comando é /etc/init.d/apache2 restart.

Instalação e Configuração do APC

Agora é a instalação do APC. No Debian 5, isso é extremamente simples:

apt-get install php-apc

Após instalar, edite o arquivo /etc/php5/conf.d/apc.ini, adicionando as seguintes linhas:

extension=apc.so
apc.enabled=1

É possível configurar vários parâmetros, consulte a documentação do APC.

Para a nova configuração surtir efeito, reinicie o Apache:

/etc/init.d/apache2 restart

Instalação e Configuração do Memcached

apt-get install memcached

Após a instalação, edite o arquivo /etc/memcached.conf. Geralmente não é necessário mudar muita coisa, a não ser o tamanho máximo da memória para o Memcached (o default é 64 MB). O Memcached usa a porta 11211 por padrão, mas também é possível mudar. O arquivo de configuração vem todo comentado, não há segredo.

Para alterar o tamanho do espaço de memória, altere a linha -m 64 para o quanto for necessário (128, 256, 512, 1024,…). Lembrando que o Memcached só ocupa o espaço de memória que estiver em uso pelo cache, ele não reserva todo o espaço inicialmente. Feita a configuração, reinicie o daemon do Memcached com o comando:

/etc/init.d/memcached restart

Agora só falta o Nginx.

Instalação do Nginx

Adivinhem?

apt-get install nginx

Vamos abordar a configuração em um outro artigo. Até lá, que tal dar uma olhada nos arquivos de configuração do Nginx, em /etc/nginx ? Bons estudos!


Page optimized by WP Minify WordPress Plugin