Django e settings.py: dicas e boas práticas
Em vez de ficar rasgando elogios ao Django, como de costume, eu tentarei aproveitar o melhor o meu (e o seu) tempo e mostrar algo que é de fato útil. O assunto em questão envolve o módulo settings.py, cuja função é fornecer as configurações necessárias para que o projeto funcione. Apesar deste módulo ser uma peça importante em qualquer projeto Django, pouco se fala sobre ele, ou sobre boas práticas associadas a ele. Por isso, achei que seria interessante mostrar a minha visão pessoal sobre o assunto.
O poder do Python
Quem não está acostumado a trabalhar com Django pode estranhar o fato deste utilizar um script Python para fazer a configuração do projeto: o famoso settings.py. E essa estranheza é justificada, afinal muitos desenvolvedores — principalmente os que vêm de outras linguagens — estão acostumados a trabalhar com ferramentas onde tal tarefa é feita com arquivos XML ou coisa assim.
O fato é que utilizar um script Python para tal é uma excelente idéia, pois você deixa de depender de algum tipo de estrutura estática (e muitas vezes inconveniente) para algo mais flexível e poderoso, que, no caso, é a própria linguagem de programação. Isso faz uma grande diferença em situações onde tal flexibilidade é necessária.
Quer exemplos?
Ambientes de desenvolvimento/produção
Eis como fizemos aqui. Primeiramente, defina a variável de ambiente WORKSPACE. No Linux, isso pode ser feito através do arquivo ~/.bashrc:
export WORKSPACE=1
A idéia é possibilitar a criação de perfis de configuração, cada qual correspondente a um ambiente de execução. A existência ou não da variável de ambiente é o que define o ambiente no qual a aplicação roda.
Continuando com o exemplo, no diretório raíz do seu projeto Django, crie o módulo environment.py, com o seguinte conteúdo:
import os def production_mode(): return not development_mode() def development_mode(): return 'WORKSPACE' in os.environ
Finalmente, modifique o módulo settings.py para que este utilize tais métodos onde for necessário definir configurações diferentes para ambientes de execução diferentes:
from environment import production_mode # Configurações padrão PREPEND_WWW = False DEBUG = True # Configurações para ambiente de produção if production_mode(): PREPEND_WWW = True DEBUG = False MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.middleware.doc.XViewMiddleware', 'pages.middleware.PageFallbackMiddleware', 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', ) # Habilitando caching em modo de produção if production_mode(): MIDDLEWARE_CLASSES += ( 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware', )
Não tenha medo de utilizar os recursos do Python onde eles se fizerem necessários, apenas tomando cuidado para não exagerar e acabar criando acidentalmente um Algoritmo Genético para configurar seu projeto!
Informações secretas (IPs, usernames, passwords, etc)
Praticamente não há quem ignore a importância de um bom sistema de controle de revisões (Subversion, Git, etc). O problema é que, muitas vezes, não tomamos o devido cuidado com o que colocamos dentro dos nossos repositórios. Sempre que possível, informações secretas — como endereços de IP, usernames e passwords — devem ser mantidas fora dos repositórios.
Em um projeto Django, as informações de acesso a servidores de e-mail e bancos de dados devem estar disponíveis através do módulo settings.py. Felizmente, existe um jeito simples de manter essas informações separadas das outras configurações.
Primeiramente, abra o arquivo settings.py do seu projeto e remova todas as senhas e outras informações que você considere secretas. Em seguida, cole o seguinte trecho de código no final do arquivo:
try: from private import * except ImportError: pass
Feito isso, crie o módulo private.py no diretório raíz do seu projeto Django. Coloque nele as configurações que você removeu do settings.py no passo anterior. Exemplo:
from environment import production_mode SECRET_KEY = 'secret_key_do_seu_projeto' EMAIL_HOST = 'localhost' EMAIL_HOST_PASSWORD = 'senha_email_local' DATABASE_HOST = 'localhost' DATABASE_USER = 'username_db_local' DATABASE_PASSWORD = 'senha_db_local' if production_mode(): EMAIL_HOST = 'ip_email_producao' EMAIL_HOST_PASSWORD = 'senha_email_producao' DATABASE_HOST = 'ip_db_producao' DATABSE_USER = 'username_db_producao' DATABASE_PASSWORD = 'senha_db_producao'
Certifique-se de adicionar o arquivo private.py no ignore (.cvsignore para CVS, .gitignore para Git, etc) correspondente ao sistema de controle de revisões sendo utilizado. Faça o commit e pronto.
Para finalizar, se o seu repositório já contém uma versão “insegura” do módulo settings.py, mude as senhas dos seus servidores.
E você, o que recomenda?
Tem alguma dica útil para compartilhar conosco? Nós adoraríamos ouvir o que você tem a dizer!


Muito boas as dicas. Eu particularmente não gosto de o django armazenar as senhas em forma de texo, e possibilitar que elas seja obtidas facilmente. Em meus projetos eu adotei a política de criptografar as senhas (estes dados que você coloca como private). No caso, adoto algo do tipo:
Onde descriptografar é uma função que eu mesmo criei, baseada no base64 pra criptografar.
Excelente idéia Vinicius, com certeza eu a implementarei aqui. Obrigado por compartilhar!
A minha abordagem mantém as senhas fora do repositório, mas não adianta muita coisa pois elas ainda existem (de forma plain-text, o que é pior) nos computadores de desenvolvimento. Se, por exemplo, o meu notebook for furtado por alguém com o mínimo de conhecimento, essas informações podem ser usadas de forma indevida.
Obrigado novamente!
A minha abordagem evita que a senha seja lida em texto plano, mas se o usuário fizer:
$ python
>>> import settings
>>> settings.DATABASE_PASSWORD
‘minha_senha_em_texto_plano’
Ou seja, se a pessoa entender de python e django, consegue a senha fácil, fácil… e não adianta nem mandar o arquivo com as senhas em formato .pyc…
O ideal seria que o django recomendasse que você criptografasse a senha, e então o core faria algum algoritmo pra descompressão na hora de conectar ao servidor… mas ainda assim, não impossibilita que peguem a senha, mas dificulta bastante…
Ah sim! Nesse caso não tem jeito mesmo. Ainda assim, é uma proteção a mais.
o que fazemos nos nossos servidores é permitir acesso ao arquivo de local_settings somente aos usuários que realmente necessitam (não colocamos senhas e hash de segurança no settings padrão), assim a senha fica em um arquivo protegido, já nas máquinas locais, se for ambiente linux dá pra fazer algo semelhante, mas como todas as máquinas tem um bd próprio e não usam o bd principal, a segurança não precisa ser grande.
outro ponto é que o usuário de acesso ao banco do django (e o acesso à rede do bd) também devem ser restritos.
Agora, se a pessoa tiver a senha do usuário do linux, souber django, tiver acesso à rede do banco, ou ele é funcionário ou vcs demoraram pra contratar =P
Obrigado pelas informações, Anderson!
Essa parte é algo que gosto mais do rails do que do django. No rails eu tenho, nativamente, arquivo de configurações gerais (environment.rb) e depois tenho mais três arquivos de configurações:
Ambiente de Desenvolvimento: development.rb
Ambiente de Produção: production.rb
Ambiente de Teste: test.rb
Claro que da para fazer isso com o Django, mas não é nativo.
abraços,
Verdade Willian, concordo plenamente. Além do Rails, são vários os frameworks que possibilitam dividir configurações por tipo de “ambiente”, e isso é muito útil no dia-a-dia.
Criar algo mais padronizado para o Django é uma idéia que deve ser considerada. Assim que sobrar um tempinho eu vou tentar bolar alguma coisa! (será que sai OUTRO projeto open source?)
Grande abraço!