Arquivo da categoria 'Django'

Python logging em Django

Postado por Rafael Sierra em 3/11/2009

Que o módulo logging e o framework Django são excelentes ferramentas pra qualquer trabalho todos sabem, mas como fazer para integrar os dois?

Eu sempre achei um saco o fato do Django não ter um módulo builtin/contrib que permitisse que ao fazer um simples logging.error('PAN!') a mensagem, a data, o nível, the universe and everything, fossem gravados no banco de dados. Pra resolver esse simples problema, nada como uma simples solução.

Solução
A Solução

Para começar crie um aplicativo em sua aplicação chamado "log", nunca crie a aplicação com nome de "logging", a não ser que você queira problemas com imports não funcionando:

python manage.py startapp log

Em seguida crie o seguinte model:

# -*- encoding: utf-8 -*-
from django.db import models
from django.contrib import admin
import logging
 
class Log(models.Model):
    level = models.IntegerField(db_index=True)
    file = models.CharField(max_length=512, db_index=True)
    lineno = models.IntegerField()
    date = models.DateTimeField(db_index=True)
    message = models.TextField()
 
    def _get_level_name(self):
        return logging.getLevelName(self.level)
    levelName = property(fget=_get_level_name)
 
    def _get_message_summary(self):
        if len(self.message) > 100:
            return '%s...'%(self.message[:100])
        else:
            return self.message
    messageSummary = property(fget=_get_message_summary)
 
    def _get_file_summary(self):
        if len(self.file) > 30:
            return '...%s'%(self.file[-30:])
        return self.file
    fileSummary = property(fget=_get_file_summary)
 
class LogAdmin(admin.ModelAdmin):
   date_hierarchy = 'date'
   list_display = ('level', 'levelName', 'date','messageSummary', 'fileSummary', 'lineno')
   list_filter = ('level',)
   search_fields = ('message', 'file')
 
admin.site.register(Log, LogAdmin)
 

Em seguida crie o arquivo "handler.py" dentro do aplicativo "log" com o seguinte conteúdo:

 
# -*- encoding: utf-8 -*-
import logging
import datetime
from SEUPROJETO.log.models import Log
 
class DjangoHandler(logging.Handler):
    '''Executa a manipulação do log e insere no banco de dados'''
    def emit(self, record):
        log = Log()
        log.level = record.levelno
        log.file = record.pathname
        log.lineno = record.lineno
        log.message = record.msg
        # TODO: Utiizar o record.created
        log.date = datetime.datetime.now()
        log.save()
 

Com isso você já tem tudo que precisa pra logar direto pro banco de dados, só falta uma coisa: Configurar o projeto para o logging usar nosso handler.

Pra fazer isso, edite o arquivo __init__.py (e você achando que esse arquivo era inutil :) e adicione o seguinte conteúdo ao arquivo:

 
import logging
from SEUPROJETO.log.handler import DjangoHandler
django_handler = DjangoHandler()
logging.root.addHandler(django_handler)
 

E pronto, é só correr pro abraço, todo e qualquer log que você executar vai ser armazenado no banco de dados.

Yes! Tudo que faltava pra terminar meu projeto!
Yes! Tudo que faltava pra terminar meu projeto!

... e antes que você venha me reclamar que a p0rr@ do log não ta aparecendo em lugar nenhum, verifique se você está usando o logging.debug com a configuração padrão do módulo logging (que só exibe mensagens de nível mais alto).

Em tempo: Eu sei que é extremamente simples criar um módulo/pacote com tudo isso, mas não seria tão didatico simplesmente falar "baixe aqui, copie ali e import lá".

Se você tiver interesse, sugira a implantação deste módulo ao django.contrib ;)

Django RequestContext

Postado por Ricardo Perez em 19/01/2009

O RequestContext do django serve para popular o template com variavés padrões, ou seja váriaveis comum aos templates. Quando você usar o RequestContext como parâmetro no render_to_response de sua view, ele usará os chamados context_processor setados na váriavel TEMPLATE_CONTEXT_PROCESSOR do settings.py do projeto(por padrão esta váriavel não esta no settings), funções que retornão um dicionário de dados.

 
TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
)
 

Para criar um contex_processor é só criar uma função da seguinte maneira, você pode criar um arquivo context_processor.py na pasta de sua app.

 
def teste_contex_processor(request):
    user = request.user
 
    return {
      'user':user,
      'ip_address': request.META['REMOTE_ADDR']
    }
 

e colocar o context_processor criado no settings

 
TEMPLATE_CONTEXT_PROCESSORS = (
    ...,
    "meuprojeto.app.context_processor.teste_context_processor",
)
 

Para usar o RequestContext no render_to_response, basta fazer o seguinte:

 
    ...
    return render_to_response(
        'templates/index.html',
        dicionario_de_dados,
        context_instance=RequestContext(request)
    )
 

*lembrando que você tem que passar request como parâmetro.

Reaproveitando a inteface do Admin do Django

Postado por Rafael Sierra em 16/12/2008

Finalmente o Django pra mim atingiu a perfeição, depois da minha surpresa com o {{ block.super }}, agora foi a vez de eu realizar um sonho meu: Aproveitar as interfaces maravilhosas de administração do Django.

Sempre é um verdadeiro pé no saco ter que ficar escrevendo código que você sabe que ta pronto, e mais sacal ainda quando o código ta a apenas "../../" de você, mas agora é um trabalho a menos que eu tenho :D (especialmente considerando a minha "super habilidade" com CSS).

Agora vamos ao que interessa, o conhecimento necessário pra fazer isso funcionar levou cerca de 4 horas pra ser adiquirido, foram 4 horas engolindo e reengolindo código do Django, mas no final resultou em uma view como a seguinte (ignorem os imports desnecessários):

 
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.text import ugettext_lazy as _
from django.contrib.auth.decorators import login_required
from mysearch.profiles.models import Profile
from mysearch.profiles.admin import ProfileAdmin
from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
 
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
 
@login_required
def index(request):
    admin_model = admin.site._registry[Profile]
    admin_model.admin_site.root_path = request.path
    cl = ChangeList(
        request,
        Profile,
        ProfileAdmin.list_display,
        ProfileAdmin.list_display_links,
        ProfileAdmin.list_filter,
        ProfileAdmin.date_hierarchy,
        ProfileAdmin.search_fields,
        ProfileAdmin.list_select_related,
        ProfileAdmin.list_per_page,
        admin_model)
    cl.query_set = cl.query_set.filter(user=request.user)
    cl.get_results(request)
 
    context = {
        'title': cl.title,
        'is_popup': cl.is_popup,
        'cl': cl,
        'has_add_permission': admin_model.has_add_permission(request),
        'root_path': admin_model.admin_site.root_path,
        'app_label': _('Profile'),
    }
 
    return render_to_response('admin/change_list.html',
        context, context_instance=RequestContext(request))
 

Vamos as explicações agora. Primeiramente, pra que isso funcione é preciso que seu model tenha sido registrado no Admin do Django, no meu caso o model utilizado foi esse chamado Profile.

Depois disso é criado um objeto do tipo `django.contrib.admin.views.main.ChangeList`, infelizmente todos os parametros devem ser passados, e essa foi a parte que mais me decepcionou, uma vez que todos os atributos poderiam ser resgatados com base no último argumento, ou simplesmente pedindo a classe que define o model, mas tudo bem, é um pequeno preço a se pagar pelo beneficio.

Após criar a variável `cl`, vem o ponto que meu deu maior dor de cabeça: Filtrar o que eu quero que apareca para o usuário. Nesse caso eu precisava que o usuário tivesse acesso apenas ao próprio conteudo, e pra isso adicionei o `.filter(user=request.user)`, porém, isso não basta, é preciso chamar a função `cl.get_results(request)` pra que ele possa atualizar a lista de resultados que vai ser usada

A váriavel `context`, neste caso, é usada pelo template `admin/change_list.html`, sinta-se a vontade para copiar o template da pasta do Django e colocar na sua pra editar.

Por fim, basta retornar o template que vai pegar o resultado e imprimir na tela pro seu usuário que será muito feliz :D

Observações
O template `admin/change_list.html` não imprime a tabela propriamente dia, ela utiliza uma tag (não documentada no site) chamada `result_list`, essa tag recebe um objeto do tipo `ChangeList` que é o nosso `cl`.

Você ainda vai precisa escrever uma view (ou aproveitar a do Admin) para fazer o handle quando o usuário clicar no objeto, mas essa é a parte fácil :P

Acessando `block` tags parentes em templates Django

Postado por Rafael Sierra em 16/12/2008

Se tem algo que eu admiro muito no sistema de templates do Django, é a tag block, eu acho ela realmente f#!$ pra ca#@!&.

Só que recemente eu descobri algo nela que se eu estivesse em um ato sexual teria resultado em um fork(), que é a possibilidade de acessar o conteúdo antigo da tag antes dela ser sobrescrevida por você.

É extremamente simples, vamos pegar como exemplo o seguinte template `base.html`:

 
<html>
    <head><title>{% block title%}Meu site dahora{% endblock %}</html>
    <body>{% block content %}{% endblock %}
</html>
 

A parte legal fica por conta do bloco title. Até então, sempre que eu quizesse colocar "Meu site dahora | Home" no titulo, eu teria que fazer assim em um template filho:

 
{% extends "base.html" %}
{% block title %}Meu site dahora | Home{% endblock %}
 

O problema óbvio nesse caso, é que se um dia eu resolver trocar o titulo pra "O Jardineiro é Jesus", então eu vo ter que editar todo template que extende o template `base.html` pra arrumar isso.

Eis então que surge a solução

 
{% extends "base.html" %}
{% block title %}{{block.super}} | Home{% endblock %}
 

:D Simples e funcional. VIDA LONGA AO DJANGO!

Gerenciamento de usuários Trac com Django

Postado por Rafael Sierra em 25/11/2008

Uma das minhas maiores broncas com o Trac é na hora de gerenciar usuários.

Até poucos meses atrás eu costumava gerenciar os usuários com o famoso aplicativo htpasswd que utiliza um arquivo de texto simples pra gerenciar os usuários. O primeiro problema que eu tive com ele veio quando eu pensei:

Holly shit...se eu precisar definir permissões de acesso a diferentes Tracs eu to fucked

Foi então que eu resolvi procurar uma alternativa, e o primeiro (e mais obvio) lugar que eu procurei foi no Django, felizmente encontrei a documentação que ensina passo-a-passo como configurar o Apache para autenticar com o Django, é tão ridiculamente simples configurar que recomendo acessar o link por você mesmo e configurar.

Agora eu estava feliz, tinha 3 tracs pra administrar, felizmente, todos com as mesmas permissões de acesso e tudo sobre controle, gerenciamento de usuários centralizado e tudo mais. E eis que finalmente surge a oportunidade de por a prova o gerenciamento de permissões de acesso com o Trac do projeto Djapian (ainda não publicado), dessa forma fiz o seguinte:

  • Os 3 Tracs já existentes estão configurados para permitir apenas acesso de pessoas com o atributo is_staff habilidado
  • O novo Trac foi configurado para permitir acesso de qualquer pessoa que tenha a permissão djapian

Após configurar o Apache apropriadamente eu criei um usuário de teste pelo Admin do Django, feito isso, testei o usuário no Trac do Djapian e no Trac interno, resultado: Perfeito, conseguindo logar-se e negando autenticação respectivamente.

Agora estava tudo perfeito, até eu perceber um detalhe: O projeto Djapian é OpenSource, e eu gostaria que o wiki também fosse, porém, não gostaria de deixar habilitado a edição do mesmo por usuários anonimos, até por questões de rastreamento no caso de alguem apagar ou estragar uma página.

O problema: Como eu permito que usuários se cadastrem?
A solução: Construir um plugin para o Trac que faça a interface com o Django :D

Levei aproximadamente 1 dia útil de trabalho para desenvolver esse plugin que pode ser baixado aqui, o plugin é bem simples de se configurar e instalar, para isso siga os seguintes passos:

 
$ wget http://pub.stiod.com/TracDjangoAuth-0.1.tar.gz
$ tar -zxvf TracDjangoAuth-0.1.tar.gz
$ cd TracDjangoAuth-0.1
$ python setup.py bdist_egg
$ cp dist/TracDjangoAuth-0.1-*.egg /path/para/o/seu/trac/plugins/
 

Agora é preciso apenas editar o arquivo trac.ini e acrescentar no final dele as seguintes linhas:

 
[djangoauth]
# Adicione aqui sua permissao
django_permission_name = can_do_something
# Permissoes padroes para cada usuario que se cadastras
default_trac_permissions = WIKI_CREATE,WIKI_MODIFY,WIKI_VIEW
# Settings que deve ser usado
django_settings_module = some_project.settings
 

Apenas note que a opção django_permission_name requer apenas o atributo codename da permissão, diferentemente de seu equivalente no Apache, que precisa do nome da aplicação também como myapp.some_perm.

Feito isso apenas reinicie o Apache e divirta-se, o novo plugin irá criar um novo link chamado "Signup" para que seus usuários possam se cadastrar e se logar :)

Qualquer dúvida, bug, sugestão, correção ou patch, é só comentar ai em baixo ;)

Em tempo: Fiz esse plugin para o Trac 0.10.x, se você estiver disposto a migrar para o 0.11, saiba que a unica mudança é no sistema de templates, de ClearSilver para Genshi.

Djapian – Search API for Django with Xapian

Postado por caio em 19/11/2008

Criamos uma página para o projeto Djapian.

\o/

Djapian - Search API for Django with Xapian

Para quem não conhece, o Djapian, é um aplicativo que você pode incorporar à sua própria solução afim de permitir buscas nos textos, essencial em aplicativos como: Wiki, Blog, CMS e todo tipo de projeto que envolva colaboração de usuários em informação.

Acesse esse post para ver um artigo completo sobre o Djapian.

Mudar o nome da aplicação no admin do Django

Postado por Rafael Sierra em 22/10/2008

Atenção! Pode conter links inúteis

É incrivel, passei meus ultimos um ano e meio trabalhando em empresas de terceiros, porém, eu não sentia aquele prazer que só um verdadeiro programador sente ao programar.

Mãs! Tudo mudou quando decidimos (eu e mais 4 socios) que era hora de tocar a empresa seriamente, então eu sai da empresa onde trabalhava e segui viagem para minha própria empresa.

Bom, enrolei muito já, vamos ao que interessa.

Você já deve ter se revoltado com o Django, mais precisamente com o aplicativo Admin, quando você era obrigado a aceitar uma versão capitalizada (no sentido da primeira-letra-maiúscula, e não financeiro) do nome do seu aplicativo na tela inicial da administração.

Porém, agora sei que é possivel modificar esse nome que fica com fundo azul, tudo graças a uma introspecção no código do Django, algo que eu dificilmente faria trabalhando para terceiros (esse foi o motivo de eu ter escrito aquelas abobrinhas ali em cima :P ), e ao que tudo indica, essa "funcionalidade", não está documentada (pelo menos não foi fácil encontrar informações sobre isso, tanto que devo um link aqui).

Pra resolver esse problema é simples, basta editar o model desejado e adicionar dentro da classe Meta um atributo chamado "app_label" (repare que ele não se encontra na documentação), e com isso o model será agrupado no nome que você der para ele, o interessante, é que você pode agrupar varios aplicativos dentro de uma só tabela, desde que todos os models tenham o mesmo nome no app_label.

Mas o mais bizarro mesmo, é que você pode modificar o app_label de outros aplicativos que não fazem parte do seu projeto, por exemplo, ao adicionar as seguintes linhas em algum model.py seu:

  1.  
  2. from django.contrib.auth.models import User
  3. User._meta.app_label = "AWAAAY"
  4.  

Você vai jogar o modelo User pra dentro da tabela AWAAAAY.

Só gostaria de deixar claro que usar essa "funcionalidade" (não sei se isso seria realmente uma funcionalidade, já que não está documentada) pode resultar em comportamentos adversos (do projeto, não seus), uma vez que eu não estudei completamente o código-fonte do Django pra saber até onde vão os efeitos desse atributo.

So, have fun with moderation.

Em tempo: Estou com o Django-1.0
Nota de copyright: A imagem que utilizei aqui pertence ao site http://djangoproject.com

Django com WSGI

Postado por Ricardo Perez em 15/10/2008

Para quem usa o mod_python para servir suas aplicações em Django e esta insatisfeito ou teve algum problemas com o mesmo. Pois é, eu mesmo tive um baita problemão com o mod_python e precisava de solução urgente, que fosse rápida e fácil de configurar, uma ótima alternativa que eu encontrei foi o mod_wsgi (http://code.google.com/p/modwsgi/), logo de inicio verifiquei que num servidor de alto acesso de usuários a diferença de performance foi visivelmente absurda, hoje em dia só uso o mod_wsgi.Não vou abranger instalação do mod_wsgi mas somente a configuração do Apache e do arquivo wsgi

No seu arquivo de configurção do apache

  1.  
  2. WSGIDaemonProcess user processes=2 maximum-requests=500 threads=1
  3. WSGIProcessGroup usergroup
  4. WSGIScriptAlias / /path/para/aplicacao # sabendo que é a pasta onde fica a aplicação e não ela
  5. Alias /public /path/para/aplicacao/app/public/
  6.  

crie um arquivo na pasta da sua aplicação com o nome app.wsgi

  1.  
  2. import os, sys
  3. sys.path.append('/path/para/aplicacao/')
  4. os.environ['DJANGO_SETTINGS_MODULE'] = 'app.settings'
  5. import django.core.handlers.wsgi
  6. application = django.core.handlers.wsgi.WSGIHandler()
  7.  

Maiores Informações: http://code.google.com/p/modwsgi/ e
http://code.google.com/p/modwsgi/wiki/InstallationInstructions

Referência:
http://ericholscher.com/blog/2008/jul/8/setting-django-and-mod_wsgi/

Django EmailMessage(Erro Com Cópia Oculta)

Postado por Ricardo Perez em 8/09/2008

Hoje deparei com um pequeno problema no módulo EmailMessage do Django, eu precisava mandar um email oculto em uma certa funcionalidade, apesar do EmailMessage dar suporte a cópia oculta(BCC), ele definitvamente mostra para os outros destinatários do email quem foi enviado o email oculto(¬¬), dando uma buscadinha no Google encontrei essa snippet, FixedEmailMessage(http://www.djangosnippets.org/snippets/630/), que além de resolver este problema, também tem suporte a CC.

Vai la um exemplo:


FixedEmailMessage('titulo', 'corpo', from_email='ex@exemplo.com', to=['para@exemplo.com'], bcc=['oculto@email.com'], cc=['copiado@exemplo.com']).send()

Referência: http://www.djangosnippets.org/snippets/630/

Google Chart API e Bovespa

Postado por Rafael Sierra em 9/12/2007

Esses dias eu resolvi fazer um programa pra acompanhar a movimentação financeiras das ações de todas as empresas na bovespa, isso porque nos sites você só encontra informações sobre as empresas top-alguma-coisa ("Maiores altas" e "Maiores baixas" por exemplo), mas com essas informações você não sabe o estado de outras empresas, por exemplo: Qual a empresa que tem o menor valor por ação?, só com a informação dos sites você nunca vai saber. Por esses motivos resolvi fazer esse programa.
Continue Reading »

Av. Conselheiro Nébias, 368A, Cj. 413
Vila Mathias - Santos - SP
Telefone: (13) 3345-4580

© 2008 - 2009 Stiod. Todos os direitos reservados.