Visão do Vale
Website of the journal Visão do Vale, a regional newspaper located in Vale do Caí, Rio Grande do Sul, Brazil (http://visaodovale.com.br/)
O Django Brasil é um grupo de usuários e pesquisadores brasileiros de Django, uma framework para desenvolvimento ágil para a Web, baseada na linguagem Python e em padrões da programação orientada a objetos.
Usuários do Django no Brasil: Lista de discussão de ajuda ao Django em português.
django-l10n-portuguese: Equipe de localização e tradução do Django para o português.
Diversas empresas adotam o Django a cada dia mais. Veja algumas histórias de grande satisfação que a opção pelo Django gerou.
Você escreve sobre Django em português? Avise-nos, e adicionaremos seu feed nesta página.
Website of the journal Visão do Vale, a regional newspaper located in Vale do Caí, Rio Grande do Sul, Brazil (http://visaodovale.com.br/)
Home site of a very well-known Brazilian fashion consultant, specialized in Fashion, Health, Beauty and Well-Being. (http://cristianaarcangeli.terra.com.br/)
National computer students metting. (http://enecomp.org.br/)
Django-flash, um despretencioso projeto de software livre desenvolvido pela Destaquenet, tem recebido excelentes críticas por quem o vem utilizando regularmente. Sua adoção vem crescendo vagarosamente, mas consistentemente. Nem preciso dizer o quanto isso é gratificante para nós. De um tempo para cá, eu fui contactado por alguns desses usuários perguntando sobre a possibilidade de ter o [...]
Há alguns acertos de design que são praticamente incontestáveis.
O novo recurso de classes de modelo do tipo "proxy = True" é um desses acertos.
Esta é uma das novidades da versão 1.1 (há, de fato, várias outras novidades na QuerySet que resolvem diversos outros problemas) que vão me ajudar bastante, do tipo que dá a tentação de reescrever muita coisa pra ficar mais elegante e compatível com a novidade.
Vamos partir da seguinte classe de modelo, que aliás, é um caso bastante comum em diversas situações:
from django.db import models
class Funcionario(models.Model):
nome = models.CharField(max_length=50)
vendedor = models.BooleanField(blank=True, default=False)
gerente = models.BooleanField(blank=True, default=False)
def __unicode__(self):
return self.nome
Para registrar a classe "Funcionario" no Admin, você pode criar a classe "AdminFuncionario" no módulo admin.py da aplicação:
class AdminFuncionario(ModelAdmin):
list_display = ('nome','vendedor','gerente')
list_filter = ('vendedor','gerente')
Veja, temos aí um caso comum: um funcionário tem um nome, e pode ser, ora vendedor, ora gerente, ora ambos ou ora nenhum dos dois.
A consequência conhecida é que sempre é necessário usar de filtros, managers e outros meios para filtrar quando se deseja um dos 4 variantes de funcionários. Dentre as situações mais comuns que precisamos resolver estão:
Bom, é provável que você já tenha passado por pelo menos uma dessas situações, e as soluções em geral envolvem todo tipo de gato, desde scripts utilizando JavaScript até métodos em managers, widgets, forms, etc.
Agora veja a solução, quando se cria classes de modelo proxy para resolver essa situação:
from django.db import models
class Funcionario(models.Model):
nome = models.CharField(max_length=50)
vendedor = models.BooleanField(blank=True, default=False)
gerente = models.BooleanField(blank=True, default=False)
def __unicode__(self):
return self.nome
class VendedorManager(models.Manager):
def get_query_set(self):
qs = super(VendedorManager, self).get_query_set()
qs = qs.filter(vendedor=True)
return qs
class Vendedor(Funcionario):
class Meta:
proxy = True
objects = VendedorManager()
def save(self, *args, **kwargs):
self.vendedor = True
return super(Vendedor, self).save(*args, **kwargs)
class GerenteManager(models.Manager):
def get_query_set(self):
qs = super(GerenteManager, self).get_query_set()
qs = qs.filter(gerente=True)
return qs
class Gerente(Funcionario):
class Meta:
proxy = True
objects = GerenteManager()
def save(self, *args, **kwargs):
self.gerente = True
return super(Gerente, self).save(*args, **kwargs)
Observe que nada foi modificado na classe de modelo "Funcionario". Nem mesmo foi necessária alguma importação adicional.
Feito isso, você pode usar tranquilamente as novas classes "Gerente" e "Vendedor" naturalmente, em qualquer lugar. A distinção entre elas inclui:
Já tudo o mais que não for determinado manualmente, irá trabalhar de forma específica e transparente, vinculado à classe herdada.
Não serão criadas tabelas no banco de dados para esta classe, ela é totalmente abstrata, porém, tem o papel de trabalhar como interface para uma classe numa situação peculiar.
Veja como fica por exemplo o "admin.py" (agora o arquivo completo):
from django.contrib import admin
from django.contrib.admin.options import ModelAdmin
from django import forms
from models import Funcionario, Vendedor, Gerente
class AdminFuncionario(ModelAdmin):
list_display = ('nome','vendedor','gerente')
list_filter = ('vendedor','gerente')
class FormGerente(forms.ModelForm):
class Meta:
model = Gerente
exclude = ('gerente',)
class AdminGerente(ModelAdmin):
form = FormGerente
class FormVendedor(forms.ModelForm):
class Meta:
model = Vendedor
exclude = ('vendedor',)
class AdminVendedor(ModelAdmin):
form = FormVendedor
admin.site.register(Funcionario, AdminFuncionario)
admin.site.register(Vendedor, AdminVendedor)
admin.site.register(Gerente, AdminGerente)
Veja que agora cada uma delas tem seu próprio Admin ocultando os campos que forem desnecessários e completamente customizável (o que vale também para os templates customizáveis para o Admin).
É ou não é fantástico?
Essa semana tive que implementar em um dos meus projetos um sistema de busca full-text. como estou utilizando o Mysql, ele possui um mecanismo de pesquisa integrado. Há outras bibliotecas de pesquisa como o Lucene, Xapian e Sphinx e todas elas possuem modulos para integra-las ao Django(django-search-lucene, djapian e django-sphinx ) mas no meu caso, como estou utilizando uma hospedagem compartilhada, tenho certas restrições para instalar algumas bibliotecas, portanto tive que partir para esta alternativa.
Bom, vamos ao que é necessário para funcionar a busca:
digamos que você possui um model de noticias:
class Artigo(models.Model):
data_publicacao = models.DateTimeField("Data de Publicação", default=datetime.now)
titulo = models.CharField(max_length=200)
slug = models.SlugField()
texto = models.TextField("Texto da noticia")
class Meta:
ordering = ['-data_publicacao']
get_latest_by = 'data_publicacao'
def __unicode__(self):
return self.titulo
CREATE FULLTEXT INDEX fti_noticias_artigo ON noticias_artigo(titulo,texto)
objects = SearchManager(('titulo', 'texto'))Artigo.objects.search('minha busca')SELECT titulo, data_publicacao, slug, texto, MATCH(titulo, texto) AGAINST ('minha busca')
AS `relevance`
FROM noticias_artigo
WHERE MATCH(titulo, texto) AGAINST ('minha busca')Artigo.objects.search('minha busca').order_by('relevance')A simple blog engine using the django-diario application. (http://blog.arthurfurlan.org/)
Yep, that's the second time I post a "Hello world" entry here. The reason is that I recently moved my domain from an account at Bluehost to a VPS at Linode. So, first of all, I would like to introduce you to merlin, my new VPS. :)
As I'm the sysadmin behind my server now, I decided to not install mod-php here and then I had to change my blog engine. I used to run Wordpress for years and now I'm running django-diario, a wonderful blog engine for django made by Brazilian djanglers.
About this new version of my old blog, you may have noticed that it has only this post... That's right, I removed the old stuff (in fact I just didn't migrate them from Wordpress) and I intend to start translating and re-posting a small part of them as soon as possible. If you want to see here any specific post from my old blog, please, let me know.
As you can see now I'm writing in English and I used to write in Portuguese... I'm not a professional English writer, so you won't be a lucky guy if you find some bugs around here and if you do find something, please, let me know about it and I will gladly fix it.
In my old blog I used to post mainly about ubuntu and php, from now on I will post more about python and debian. This time I'll also try to write more often and probably in small chunks.
I think that's all...
Se você se deparou com um UnicodeEncodeError ao fazer o upload de algum arquivo com caracteres especiais usando WSGI no Django, a solução pode estar aqui: How to use django with mod_wsgi – Additional Tweaking.
Eu passei pelo seguinte erro:
UnicodeEncodeError: 'ascii' codec can't encode characters
in position 86-87: ordinal not in range(128)
Em resumo é preciso alterar as [...]
Câmara Municipal de Pato Branco (http://www.camarapatobranco.com.br/)
O Será que eu compro? é a rede social das compras. Nosso propósito não é vender, mas sim estabelecer um canal para o debate sobre produtos e serviços, seja aqueles que são comercializados na web quanto aqueles que são comercializados fora dela. Comprou algo e gostou? Conte para os outros, deixe sua opinião aqui. Mas se comprou e não valeu a pena ou você acha que o atendimento e a qualidade estiveram abaixo do esperado, denuncie aqui com sua opinião. Por outro lado, se vai comprar algo, deixe aqui a sua pergunta, para que outras pessoas possam responder e te ajudar na escolha. Há também espaço para imagens e links sobre os produtos e serviços, pra faciliatr a escolha. Algumas imagens não vão ser nada boas, mas vão denunciar um produto ruim no mercado, e assim por diante. O mais importante é saber que a opinião mais importante é a de quem compra. Não adianta nada ouvir as belas propagandas de quem vende, é preciso saber o que os compradores acharam. (http://www.seraqueeucompro.com/)
Website desenvolvido em Django. (http://www.imobiliariavilmai.com.br/)
A minha satisfação com o "Será que eu compro?" não é só por ter tido uma boa ideia. A rapidez com que a coisa fluiu foi muito satisfatória.
Há uma semana atrás, numa tarde de sábado, eu coloquei a minha filha para dormir e estava com algum tempo sobrando. Algo em torno de 2 ou 3 horas. Tinha muito trabalho pra fazer, mas na verdade eu não estava afim, era sábado e eu queria só brincar um pouco.
Veio a ideia à cabeça e eu à coloquei em prática.
Algumas horas de trabalho depois e o site foi ao ar, na segunda-feira cedinho. Na terça com domínio registrado, tive condições de lançar os registros básicos de SEO para que os sites de busca pudessem começar a indexar o site.
Afora as horas de sono da Tarsila no fim de semana, e algum tempo no domingo enquanto assistia algo na TV, o tempo gasto foi muito pouco: os minutos de sobra durante a semana.
Como pode ver, foi muito pouco tempo pra ter o site publicado. E agora, vou listar abaixo aquilo que eu acho que foi decisivo pra isso, e que há algum tempo eu venho aprendendo e gostaria de passar a outros como boas práticas a serem lembradas.
Não vou entrar na questão de se a ideia é boa ou não. Claro que se você tem uma ideia e quer fazer dela realidade, é porque você acredita nela e acha que é boa. E eu estou particularmente convencido de que boas ideias não são maiores do que um trabalho dedicado.
A questão é: você tem uma ideia possível de "entrar no ar" em etapas curtas?
Eu pessoalmente estou cansado de projetos longos. Especialmente aqueles ficam ainda mais longos à medida que o tempo passa. Um projeto pode ser imenso mas é importante que possa ser usado na prática o quanto antes, ainda que com poucas funcionalidades, mas sem deixar de ser interessante e útil.
O "Será que eu compro?" é uma ideia grande. O lista de "ideias" e "pendências" é maior que a lista de "funcionalidades ok" e vai tomar alguns meses para ficar "no jeito". Ainda assim, a lista de requisitos obrigatórios era pequena o suficiente para ir a público em menos de 10 ou 15 horas de dedicação.
Tente organizar o seu projeto de forma que a primeira versão seja viável o mais rápido o possível.
Preciso dizer mais? Está óbvio que usar um framework maduro faz quase toda a diferença. O Django e o Python foram fundamentais nesse projeto. Diversas "coisinhas" que são feitas em 10, 15 ou 20 minutos só são possíveis usando um bom framework.
O Django é um framework com mais de 5 anos de vida, milhares de desenvolvedores que usam e sites construídos com ele, e uma comunidade muito ativa, especialmente no Brasil. O sistema de renderização de templates é fundamentalmente produtivo e a forma como o fluxo é distribuído entre Views, Models, Middlewares, etc. forma um conjunto produtivo e poderoso.
O Python é uma linguagem pragmática, simples e acessível, mas não é só isso. A vasta documentação na web e a quantidade de boas bibliotecas disponíveis fazem muita diferença na hora de fazer algo funcionar. Durante esta semana passei uns maus bocados ao usar o Lazarus para construiur uma aplicação desktop, isso porque precisava de um simples hash e boa comunicação com arquivos .MDB (Access) e Sqlite. A comunidade do Lazarus tem feito o melhor que pode por dele, mas a falta de documentação e de bibliotecas estão dificultando muito o trabalho. No Python este problema raramente existe.
Evidentemente há outros excelentes frameworks como Ruby On Rails, Merb e Pylons que são igualmente produtivos e maduros, há linguagens como Ruby, PHP e outras. Enfim, o desenvolvimento "ágil" não se resume só a essas ferramentas, mas há uma separação muito clara do que é ágil e maduro para o que não é.
Eu tenho um conjunto extenso de utilidades que inclui o django-plus, algumas utilidades relacionadas à realidade brasileira e outras coisas soltas por aí, mas para este caso específico eu usei um pequeno conjunto de aplicações plugáveis que eu usei no AprendendoDjango.com e no meu site pessoal, que inclui as seguintes utilidades:
Com essas três aplicações, é possível construir qualquer site básico visualmente, a partir do próprio site já no ar. Adicione a isso um conjutno bem bolado de códigos para cache de páginas e imagens (usando memcached), sitemaps, contato, etc. e você tem uma base reusável e prática para construir o seu site.
Está aí uma grande sacada. Hoje a web possui diversos serviços de APIs para todo tipo de utilidade: imagens, vídeos, buscas, notícias, blogs, autenticação, etc. Tanto para publicar quanto para pesquisar. A lista inclui em destaque:
Usando uma API madura e conceituada disponível na Web, o seu trabalho caminha incrivelmente rápido e ganha outro nível de qualidade, basicamente é o novo conceito de "não re-inventar a roda" da Web 2.0.
O local e modelo de hospedagem utilizados pode fazer muita diferença também.
No caso do "Será que eu compro?" o serviço de hospedagem utilizado é o Google App Engine (GAE). Ele tem a qualidade matadora de resolver alguns problemas sérios numa paulada só: performance, escalabilidade, praticidade e algumas questões mais importantes que envolvem hospedagem de sites, e faz uso da arquitetura de cloud computing do Google.
Com o uso de versões diferentes, você pode manter mais de uma versão do site, uma para testes de novidades e outra para a versão em produção. Com o uso de boas práticas no uso de Ajax e cache, aliados à escalabilidade natural do GAE, o site fica muito escalável.
Quer um exemplo? Neste site evitei algumas práticas comuns que utilizei ao longo dos anos: nas páginas renderizadas não há em nenhum lugar referências diretas ao usuário logado ou a outras funcionalidades mais "dinâmicas". Desta forma, essas páginas são renderizadas para o cache com expiração em 30 dias.
E o que eu fiz pra evitar problemas com isso? Simples. Criei um decorator que substitui o cache_page (do Django) com um algorítimo próprio para armazenar as páginas renderizadas em cache, usando uma chave baseada na URL e na QUERY_STRING. Desta forma, uma outra função faz o trabalho de cache invalidate quando os objetos relacionados são modificados. O código que faz isso está disponível no django snippet 1493. Assim, o cache só expira quando é descartado (isso é gerenciado pelo próprio memcache), quando um objeto relacionado é modificado ou quando se passam 30 dias.
A outra solução adotada foi fazer uso de Ajax para carregar elementos relacionados diretamente ao usuário, como é o caso do painel do usuário na página inicial e a votação.
Também evitei coisas como timesince e em breve quero criá-lo em JavaScript para que as datas sejam "calculadas" no lado cliente, a partir de uma data em formato UTC.
Esse tipo de técnicas adotadas permitiriam até mesmo a geração de arquivos HTML estáticos para as páginas, e como o cache é armazenado em memória, a performance e escalabilidade são as melhores que já consegui construir.
Por fim, outras ferramentas importantes que utilizei foram:
Igualmente práticos e seguros, facilitam muito o nosso trabalho.
Após colocar o site no ar e dar a ele o acesso publico, obviamente o que queremos é ver o maior número de gente usá-lo e apontar sugestões, críticas, bugs, elogios, etc.
Para isso, é importante conseguir o melhor posicionamento possível nos sistemas de busca.
Neste caso, além de adotar algumas das boas práticas de webstandard conhecidas, é importante tomar o cuidado para construir um bom Sitemap e um consistente (e de preferência também simples) robots.txt.
Uma das ferramentas obrigatórias de SEO é o Google Webmaster Tools. É ali que se registra o site, envia e valida os Sitemaps e o robots.txt. É ali também que podemos apontar algumas otimizações no direcionamento do site para determinados países e idiomas, tempo de varredura e palavras-chave preferidas. Ferramenta obrigatória pra quem quer ter uma chance a mais de acertar.
De nada vale um profissional sem seus amigos e parceiros. Como disse uma vez Isaac Newton: "se enxerguei mais longe, é porque me apoiei sobre ombros de gigantes". Não que a minha humildade tenha ido passear em algum lugar nesse fim de semana, não há qualquer comparação com Newton aqui, apenas inspiração.
O melhor que pude fazer assim que o site foi ao ar foi buscar as pessoas que considero mais importantes de ouvir nesse assunto. Claro que não me lembrei de todas, mas quando me lembro, envio uma mensagem perguntando, pedindo advice.
E a essência da pergunta é sempre a mesma: o que acha da ideia e o que fazer para que ela se torne realidade?.
As respostas que chegaram até agora inspiraram este artigo e algumas melhorias no site. Outras vão inspirar mudanças futuras e há ainda aquelas que me fizeram rever (ou pelo menos planejar isso) alguns elementos do site.
Por fim, o maior dos desafios.
Não há solução perfeita nem mesmo eterna e a web é campo vasto para experimentações. Mas o objetivo é sempre melhorar.
Eu acredito que o maior desafio não é ter uma grande ideia. O maior desafio também não é técnico. Por incrível que pareça, também não acredito que seja financeiro. Não acredito que rios de dinheiro mudariam muito a chance de sucesso da ideia.
Criar não é exatamente uma grande façanha. Grandes façanhas são resultados de anos de trabalho duro. Os grandes inventores e teóricos científicos sabem muito bem disso. Grandes visionários que são referências para nós também. Se Bill Gates, Sergey Brin e Steve Jobs ficaram ricos, é porque foram muitos anos de trabalho duro, 15 ou 18 horas por dia.
Eu acredito que o grande desafio é sempre a persistência. Eu já venci e já fracassei nesse ponto, e espero vencer de novo desta vez.
É a persistência que faz um produto desconhecido perambular por anos no desconhecido até crescer rapidamente na popularidade, e em se tratando de um site de social, isso é ainda mais importante, pois sem conteúdo, não há motivo para alguém se interessar pelo site.
Portanto, esse é o gigante a ser vencido agora.
No mais, espero que as dicas lançadas aqui sejam úteis a você, e quem sabe você também coloque uma boa ideia em prática e sejamos parceiros? Porquê não?
V2 WindCenter is a windsurf and kitesurf club in João Pessoa-PB, Northeast of Brazil. A perfect spot to sail all the year, with beautiful beaches and pleasant temperature. The V2 club offers windsurf and kitesurf lessons, equipments rental, sale and storage. (http://www.v2windcenter.com.br/)
This is my personal weblog, where i write mostly about Python and Django. Unfortunately just in Portuguese, for now. (http://igorsobreira.com/)
Hospedado por PyTown.com. Django Brasil é a comunidade brasileira de usuários do framework web Django. Django é uma marca registrada de Lawrence Journal-World.