arrow_back Volver
Inicio keyboard_arrow_right Artículos keyboard_arrow_right Artículo

Deploy Django Heroku

Eduardo Ismael Garcia

Full Stack Developer at Código Facilito.

av_timer 6 Min. de lectura

remove_red_eye 5673 visitas

calendar_today 25 Octubre 2019

Lo primero que debemos de hacer es instalar, quizás, la librería más importante de todas, me refiero a gunicorn. gunicorn es un servidor HTTP para Unix, sin él, será prácticamente imposible realizar el despliegue 😬.

pip install gunicorn

Para este tutorial trabajaremos con el gestor de base de datos PostgreSQL, es por ello que la siguiente librería a instalar será psycopg2.

pip install psycopg2==2.7.4

Para realizar la conexión entre el proyecto y el gestor de base de datos usaremos la librería dj-database-url, esto principalmente, ya que Heroku nos proveerá de una base de datos que no se encuentra en el mismo servidor (lo cual no es nada malo); Es por ello que será necesario realizar la conexión mediante una url.

pip install dj-database-url

Para que podamos iniciar el servidor haremos uso de ciertas variables de entorno. Recordemos que las variables de entorno son una excelente forma en la cual podemos almacenar datos sensibles, por ejemplo, llaves secretas, tokens, passwords etc.... Para la lectura de dichas variables podemos apoyarnos de la ya clásica librería os, sin embargo, yo de forma personal recomiendo usar la librería decouple, una librería muy fácil de utilizar y que sin duda nos ahorrará un par de líneas de código.

pip install python-decouple

Listo, estas serían todas las librerías necesarias para poder realizar el deploy. Una vez instaladas cada una de ellas, el siguiente paso es generar nuestro archivo requirements.txt, archivo donde colocaremos todas las dependencias del proyecto.

Para generar dicho archivo ejecutaremos la siguiente sentencia.

pip freeze > requirements.txt

A partir de requirements.txt, el servidor instalará todas las dependencias necesarias para que el proyecto funcione correctamente; La instalación se hará de forma automatica al momento de realizar el deploy, es por ello que es de suma importancia que siempre que agreguemos una nueva librería al proyecto modifiquemos dicho archivo.

Configuraciones

Bien, ya tenemos las librerías instaladas, ahora, lo que debemos de hacer es modificar nuestro proyecto. Nos concentramos en el archivo settings.py.

Lo primero que haremos será modificar nuestra constante DEBUG, colocamos su valor como False.

DEBUG = False

Posteriormente asignamos los hosts válidos. En este caso coloco asterisco , indicando que acepte todos los hosts.

ALLOWED_HOSTS = ['*']

Configuramos nuestra base de datos. En este caso me apoyo de la librería decouple con su función config, de tal forma que podamos leer la variable de entorno DATABASE_URL, variable que crearemos en un par de minutos.


import dj_database_url
from decouple import config

DATABASES = {
    'default': dj_database_url.config(
        default=config('DATABASE_URL')
    )
}

Ahora trabajamos con los archivos estáticos. Esto puede ser un dolor de cabeza para los nuevo desarrolladores, y con mucha razón, en versiones anteriores de Django las configuraciones eran muchas y los pasos a seguir en ocasiones difíciles, afortunadamente esto ha ido mejorando en cada nueva versión 😅.

Agregamos las siguientes líneas de código al final de nuestro archivo settings.py.

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

Cómo sabemos (o si no, ahora ya lo sabes) Django no soporta servir archivos estáticos en producción, así que nos apoyaremos de WhiteNoise, una librería fantástica que sin duda nos ayudará en este problema.

Instalamos WhiteNoise (Lo siento, una librería más 🙈. Es la última, lo prometo).

pip install whitenoise

Recordemos la regla, si agregamos una nueva librería debemos modificar el archivo requirements.txt.

pip freeze > requirements.txt

Una vez instalado WhiteNoise, procedemos a agregar el middleware WhiteNoiseMiddleware.

MIDDLEWARE = [
         ...
     'whitenoise.middleware.WhiteNoiseMiddleware',
]

Finalizamos agregando la siguiente línea de código al final del archivo settings.py.

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Uff, muchas configuraciones, y aun faltan un par más 😰. Ya casi acabamos.

En el archivo urls.py (el principal) agregamos las siguientes líneas de código, esto con la finalidad de poder utilizar los archivos estáticos.

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Generamos una nueva carpeta llamada static. Esta carpeta es cien por ciento obligatoria. Al nosotros realizar el deploy, Heroku ejecutara, de forma automatica, la instrucción python manage.py collectstatic --noinput, si esta carpeta no existe obtendremos un error.

La carpeta static debe de encontrarse en la raiz del proyecto, al mismo nivel que el archivo manage.py.

Como Git (el control de versiones que estoy utilizando) no permite trabajar con carpetas vacías, será necesario agregar un nuevo archivo a cada una de las carpetas. Yo recomiendo un archivo .keep. Claro, tu puedes colocar el archivo que desees.

Y el último paso, el más importante, junto con la instalación de gunicorn, será crear el archivo Procfile. Este archivo debe encontrarse en la raiz del proyecto. Dentro del archivo colocamos la siguiente sentencia.

web: gunicorn <el nombre de tu proyecto>.wsgi --log-file -

Listo, ya hemos configurado de manera exitosa nuestro proyecto. Fueron muchos pasos, sin embargo, todos son necesarios y deben seguirse en ese mismo orden para evitar errores.

Aplicación Heroku.

Lo primero que haremos será autenticarnos con Heroku.

heroku login

Una vez autenticados, el siguiente paso será crear nuestra aplicación.

heroku create <nombre de tu aplicación heroku>

Si la aplicación se creó de forma satisfacoria, podemos ingresar a nuestro dashboard y encontrar nuestra aplicación.

Ligamos el repositorio a nuestra app en heroku.

heroku git:remote -a <nombre de tu aplicación heroku>

Si todo ha salido bien, procedemos a crear nuestra base de datos.

heroku addons:create heroku-postgresql:hobby-dev

Una vez la base de datos se haya creado de forma exitosa, de manera automática, se procederá a crear una nueva variable de entorno en el servidor (DATABASE_URL). Esta variable almacenará la url de la base de datos a utilizar.

Con la base de datos creada realizamos el Deploy. Este paso puede tomar un par de minutos dependiendo del tamaño de tu proyecto y tu conexión a internet, así que no desesperes 😬.

git push heroku master

¿Todo bien?, Perfecto, procedemos a ejecutar todas las migraciones.

heroku run python manage.py migrate

Si así lo deseamos podemos hacer un par de pruebas con nuestros modelos.

heroku run python manage.py shell

Sin duda fueron muchas pasos, pero todo tiene su recompensa. Ejecutamos :

heroku open

Y de esta forma podremos visualizar nuestro proyecto en línea 😎. (Claro, tambíen podemos ir a nuestro dashboard > settings> Domains and certificates, y allí encontraremos la url para acceder a nuestro sitio web 😃).

Si queremos echa un vistazo a los logs ejecutamos la siguiente sentencia.

heroku logs

Variables de entorno

Nuestro proyecto esta en línea, sin embargo, aun hay un par de cosas que nos hacen falta pulir para poder terminar el deploy de forma exitosa.

En este caso si ejecutamos nuestro proyecto de forma local tendremos un error 😓 (Quizás más). El error hace referencia a nuestra base de datos y a la variables de entorno DATABASE_URL, variable que únicamente existe en el servidor y no de forma local.

Lo que yo recomiendo es generar un nuevo archivo llamado settings_production.py. Y será en este archivo donde colocaremos todas las configuraciones para que el proyecto pueda ejecutarse en producción (en el servidor).

En mi caso el archivo quedaría de la siguiente manera (El archivo lo coloque al mismo nivel que settings.py).

import dj_database_url
from decouple import config

DATABASES = {
    'default': dj_database_url.config(
        default=config('DATABASE_URL')
    )
}

Y en el archivo settings.py colocó, nuevamente, las configuraciones para mi base de datos de forma local.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

Para que mi proyecto sepa en qué entorno se encuentra ejecutándose, ya sea el desarrollo o producción, me apoyaré de un par mas de variables de entorno. Estas variables las vamos a crear en el servidor.

En mi caso generó tres variables más. Django_DEBUG cuyo valor será False, DJANGO_PRODUCTION, cuyo valor será True y _SECRET_KEY cuyo valor será un un string alpha númerico ( Tu coloca el valor que creas conveniente).

Una vez con las variables, nuevamente, modificamos el archivo settings.py. Sustituimos dos líneas de código.

DEBUG = config('DJANGO_DEBUG', default=True, cast=bool)

SECRET_KEY = config('SECRET_KEY', default='Coloca la llave default que proporciona Django')

Y en la última línea del archivo agregamos el siguiente código.

if config('DJANGO_PRODUCTION_ENV', default=False, cast=bool):
    from .settings_production import *

Y listo, de esta forma nuestro proyecto sabrá en qué entorno se ejecuta. En mi caso o producción o desarrollo, sin embargo, tú puedes tener la n cantidad de entornos que necesites.

Para confirmar que todo esto funciones, hacemos un commit a nuestra rama principal, actualizamos el servidor y probamos de forma local y remota.

Si la página web funciona en ambos entornos, felicidades, has desplegado una aplicación Django en Heroku 🥑.

Bootcamp Ciencia de Datos

12 semanas de formación intensiva en los conocimientos, fundamentos, y herramientas que necesitas para ser científico de datos

Más información