Prepare sua aplicação Django para ser disponibilizada no Heroku

Aug 15, 2017 5 min reading
  • Tags:
  • deploy
  • django
  • heroku
  • paas
  • python
Attention: this post was written some time ago and may not be valid anymore, ok?

É bem animador construir nossos próprios projetos e vê-los funcionar em produção, certo? Alguns desenvolvedores podem pensar que fazer o deploy de uma aplicação Django é um pesadelo. Neste post eu vou mostrar como preparar sua aplicação para ter diferentes configurações e efetuar o deploy no Heroku.

Requisitos: Você precisa instalar o Heroku CLI e o GIT.

Heroku

Heroku é um PaaS (Plataforma como Serviço) que vai disponibilizar nosso projeto na web. É preciso que você acesse o dashboard e crie uma nova aplicação.

Um vez criada sua aplicação, é necessário usar o terminal para configurar as credenciais. Para isso, usamos o Heroku CLI para acessar as configurações do app (dê uma olhada na docs para instalar propriamente).

Após a instalação você pode efetuar o login e já adicionar um banco Postgres à sua aplicação:

heroku login
heroku addons:create heroku-postgresql:<your-plan-name> -a <your-application-name>

Mais tarde usaremos o Postgres. Heroku nos ajuda a provisionar um banco de dados com um comando. É bem fácil e você pode aprender sobre isso na docs.

Dica: O comando $ heroku apps é bem útil e nos permite listar os apps que temos.

Preparando nossa aplicação

Quando se trata de gerenciar os ambientes local e de produção eu gosto de usar o python decouple pois ele permite gerenciar as variáveis de ambiente e, com isso, ter diferentes configurações. Além dele, eu uso o djdatabaseurl para tornar simples o uso de diferentes bancos de dados por meio de strings de configuração.

1. Primeiro, crie dois arquivos: .env e .env-sample. O primeiro será usado no nosso ambiente local e deve ser ignorado pelo GIT. O segundo funciona como um template:

SECRET_KEY=YOUR_KEY_GOES_HERE
DEBUG=True
ALLOWED_HOSTS=127.0.0.1,localhost,.herokuapp.com

2. Abra seu settings.py, e cole o código abaixo:

from decouple import config, Csv
from dj_database_url import parse as dburl

SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)

ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())

DEFAULT_DBURL = 'sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3')
DATABASES = {
    'default': config('DATABASE_URL', default=DEFAULT_DBURL, cast=dburl)
}

As primeiras duas linhas importam os módulos enquanto as outras apenas carregam as variáveis de ambiente. O parâmetro cast é obrigatório pois variáveis de ambiente são strings e é importante converter o valor para o tipo de dado correto.

Preste atenção às variáveis DEFAULT_DBURL e DATABASES. A primeira usa o Sqlite no ambiente local mas no Heroku nós iremos configurá-la para armazenar a URL de configuração do Postgres.

Subindo para o Heroku

Nós criamos nossa aplicação no Heroku, adicionamos um banco de dados Postgres e configuramos o projeto para aceitar diferentes strings de configuração. Agora é hora de disponibilizar nossa aplicação!

Certifique-se de que seu arquivo requirements.txt contém todas as dependências

Ele deve ter, ao menos: dj-database-url, gunicorn, psycopg2, python-decouple e pytz. Esse arquivo é extremamente importante pois o Heroku olha para ele a fim de instalar as dependências.

Crie um arquivo Procfile no diretório raiz
web: gunicorn <app>.wsgi --log-file -

O Procfile (sim, o arquivo não tem extensão) informa ao Heroku como executar a aplicação. Atente que deve ser substituído pelo diretório que está o seu arquivo wsgi. Você pode executar o comando localmente para certificar-se de que está correto.

Crie um arquivo runtime.txt no diretório raiz
python-3.6.1

O arquivo vai dizer ao Heroku qual versão do python nosso projeto usa.

Configure suas variáveis de ambiente de produção

Lembra que nosso settings.py carrega os dados do arquivo .env? Bem, python-decouple respeita a precedência das variáveis de ambiente em relação aos arquivos de configuração. Portanto, se existir alguma variável de ambiente em produção a diretiva config não irá olhar para o arquivo .env.

Para cada chave no arquivo .env nós iremos usar o Heroku CLI para configurar a variável de ambiente em produção. Nós precisamos configurar quatro variáveis: SECRET_KEY, DEBUG, ALLOWED_HOSTS e DATABASE_URL. Abra o terminar e execute:

heroku config:set SECRET_KEY='<YOUR_SECRE_KEY>' -a <YOUR_APP>
heroku config:set DEBUG=False -a <YOUR_APP>
heroku config:set ALLOWED_HOSTS=127.0.0.1,localhost,.herokuapp.com -a <YOUR_APP>
heroku config:set DATABASE_URL='<YOUR_DATABASE_URL>' -a <YOUR_APP>

Notas:

  1. SECRET_KEY é cercado por aspas simples pois precisamos explicitamente definí-la como uma string para o Heroku;
  2. Substitua <YOUR_APP> pelo nome da sua aplicação;
  3. A string .herokuapp.com deve estar dentro de ALLOWEDHOSTS_, caso contrário o Django não será executado no Heroku.

Como encontrar DATABASE_URL? Acesse o dashboard > Resources > Heroku Postgres Database. Uma nova aba irá abrir e permitirá você verificar DATABASE CREDENTIALS.

Disponibilize seu app

O dashboard do Heroku irá conter instruções de como disponibilizar seu app. De qualquer maneira, com o git você pode fazê-lo facilmente:

heroku git:remote -a <YOUR_APP_NAME>
git push heroku master

Solução de Problemas

Se você encontrar quaisquer problemas, apenas cheque o terminal pois o Heroku apresenta mensagens expressivas que podem te ajudar. Por exemplo, durante o deploy eu fui apresentado à seguinte mensagem:

remote:        django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app without having set the STATIC_ROOT setting to a filesystem path.
remote:
remote:  !     Error while running '$ python manage.py collectstatic --noinput'.
remote:        See traceback above for details.
remote:

Ao checá-la percebi que havia esquecido de configurar a variável STATIC ROOT no arquivo \settings.py_ e instalar o middleware WSGI para servir os arquivos estáticos.

Nota: Django não foi pensado para servir arquivos estáticos. Use a Amazon S3 (ou equivalente) em projetos “reais”.

Isso é tudo, pessoal!


Comments