└── README.md /README.md: -------------------------------------------------------------------------------- 1 | How to Deploy Django Applications on Heroku 2 | =========================================== 3 | 4 | ![heroku-django](https://simpleisbetterthancomplex.com/media/2016-08-09-how-to-deploy-django-applications-on-heroku/featured.jpg) 5 | # Install heroku CLI 6 | [Sign up](https://signup.heroku.com/) to Heroku. 7 | 8 | Then install the [Heroku Toolbelt](https://toolbelt.heroku.com/). It is a command line tool to manage your Heroku apps 9 | 10 | After installing the Heroku Toolbelt, open a terminal and login to your account: 11 | ```bash 12 | $ heroku login 13 | Enter your Heroku credentials. 14 | Email: newtonkiragu@herokudeploying.com 15 | Password (typing will be hidden): 16 | Authentication successful. 17 | ``` 18 | 19 | # Preparing the Application 20 | In this tutorial I will be using a repo which is in development which is [ArtExtractKe](https://github.com/Benard18/ArtExtractKe) 21 | It's an very simple Django project, that shows various categories and their companies. 22 | Its available on [github](https://github.com/Benard18/ArtExtractKe) so you can actually clone the repository and follow along or try it on your own existing django project. 23 | 24 | ## Assumptions 25 | * Your familiar with the basics of django e.g concept of apps, settings, urls, basics of databases 26 | * You have django application that you want to deploy to heroku 27 | * You are familiar with virtual environments - not a must but the knowledge would be a plus 28 | * Your deployment db is postgres 29 | 30 | We need to add the following to our project, we will cover each of them in detail in the below section 31 | 32 | * Add a `Procfile` in the project root; 33 | * Add `requirements.txt` file with all the requirements in the project root; 34 | * Add `Gunicorn` to `requirements.txt`; 35 | * A `runtime.txt` to specify the correct Python version in the project root; 36 | * Configure `whitenoise` to serve static files. 37 | 38 | ## Procfile 39 | Heroku apps include a `Procfile` that specifies the commands that are executed by the app’s dynos. 40 | 41 | For more information read on the [heroku documentation](https://devcenter.heroku.com/articles/procfile). 42 | 43 | Create a file named `Procfile` in the project root with the following content: 44 | ``` 45 | web: gunicorn your_project_name.wsgi 46 | ``` 47 | 48 | ## Runtime.txt 49 | This file contains the python version you are using for heroku to use, create `runtime.txt` in your project root and add your python version in the following format 50 | ``` 51 | python-3.6.6 52 | ``` 53 | ## Django-Heroku 54 | We then install Django-Heroku which will come with the necessary requirements that will help us in deployment such as whitenoise,decouple and such but this will not satisfy all instalations. 55 | 56 | ```bash 57 | pip install django-heroku && pip freeze > requirements.txt 58 | ``` 59 | PLEASE after doing this remove the pkg-resources bug so that you may deploy fluidly. 60 | 61 | List of [Heroku Python Runtimes](https://devcenter.heroku.com/articles/python-runtimes). 62 | 63 | ## Whitenoise: Django Static Files settings 64 | Lets first configure static related parameter in `settings.py` 65 | ```python 66 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 67 | 68 | # Static files (CSS, JavaScript, Images) 69 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 70 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 71 | STATIC_URL = '/static/' 72 | 73 | # Extra places for collectstatic to find static files. 74 | STATICFILES_DIRS = ( 75 | os.path.join(BASE_DIR, 'static'), 76 | ) 77 | ``` 78 | Turns out django does not support serving static files in production. However, WhiteNoise project can integrate into your Django application, and was designed with exactly this purpose in mind. 79 | 80 | Lets first install Whitenoise `pip install whitenoise` 81 | 82 | It is not a must to edit the wsgi.py file because there is an update available so let's just ignore it. 83 | 84 | Next, install `WhiteNoise` into your Django application. This is done in `settings.py’s middleware section` (at the top): 85 | ```python 86 | MIDDLEWARE_CLASSES = ( 87 | # Simplified static file serving. 88 | # https://warehouse.python.org/project/whitenoise/ 89 | 'whitenoise.middleware.WhiteNoiseMiddleware', 90 | ... 91 | ``` 92 | Add the following setting to `settings.py` in the static files section to enable gzip functionality. 93 | ```python 94 | # Simplified static file serving. 95 | # https://warehouse.python.org/project/whitenoise/ 96 | 97 | STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' 98 | 99 | # configuring the location for media 100 | MEDIA_URL = '/media/' 101 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 102 | 103 | # Configure Django App for Heroku. 104 | django_heroku.settings(locals()) 105 | ``` 106 | ## Requirements.txt 107 | If your under a virtual environment run the command below to generate the requirements.txt file which heroku will use to install python package dependencies 108 | 109 | `pip freeze > requirements.txt` 110 | Make sure you have the following packages if not install the using pip then run the command above again 111 | ``` 112 | config==0.3.9 113 | dj-database-url==0.5.0 114 | Django==1.11 115 | django-bootstrap3==10.0.1 116 | django-heroku==0.3.1 117 | gunicorn==19.9.0 118 | Pillow==5.2.0 119 | psycopg2==2.7.5 120 | python-decouple==3.1 121 | pytz==2018.5 122 | whitenoise==3.3.1 123 | ``` 124 | If you are following along with the mtribune app you should use the provided `requirements.txt` as you need to install more python packages, for any app just make sure you have the above packages as a plus.(Do not forget the pkg bug..remove it) 125 | 126 | ## Optional but very helpfull settings 127 | ### python-decouple and dj-database-url 128 | Python Decouple is a must have app if you are developing with Django. It’s important to keep your application credentials like API Keys, Amazon S3, email parameters, database parameters safe, specially if it’s an open source repository. Also no more development_settings.py and production_settings.py, use just one settings.py for your whole project. 129 | 130 | Install it via `pip install python-decouple` 131 | 132 | dj-database-url is a simple Django utility allows you to utilize the 12factor inspired `DATABASE_URL` environment variable to configure your Django application. 133 | 134 | Install it via `pip install dj-database-url` 135 | 136 | Firts create a `.env` file and add it to `.gitignore` so you don’t commit any sensitive data to your remote repository. 137 | below is an example of configurations you can add to the `.env` file. 138 | 139 | ```python 140 | #just an example, dont share your .env settings 141 | SECRET_KEY='342s(s(!hsjd998sde8$=o4$3m!(o+kce2^97kp6#ujhi' 142 | DEBUG=True 143 | DB_NAME='tribune' 144 | DB_USER='user' 145 | DB_PASSWORD='password' 146 | DB_HOST='127.0.0.1' 147 | MODE='dev' 148 | ALLOWED_HOSTS='.herokuapp.com' 149 | DISABLE_COLLECTSTATIC=1 150 | ``` 151 | 152 | We then edit `settings.py` to enable decouple to use the `.env` configurations. 153 | 154 | ```python 155 | import os 156 | import django_heroku 157 | import dj_database_url 158 | from decouple import config,Csv 159 | 160 | MODE=config("MODE", default="dev") 161 | SECRET_KEY = config('SECRET_KEY') 162 | DEBUG = config('DEBUG', default=False, cast=bool) 163 | # development 164 | if config('MODE')=="dev": 165 | DATABASES = { 166 | 'default': { 167 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 168 | 'NAME': config('DB_NAME'), 169 | 'USER': config('DB_USER'), 170 | 'PASSWORD': config('DB_PASSWORD'), 171 | 'HOST': config('DB_HOST'), 172 | 'PORT': '', 173 | } 174 | 175 | } 176 | # production 177 | else: 178 | DATABASES = { 179 | 'default': dj_database_url.config( 180 | default=config('DATABASE_URL') 181 | ) 182 | } 183 | 184 | db_from_env = dj_database_url.config(conn_max_age=500) 185 | DATABASES['default'].update(db_from_env) 186 | 187 | ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv()) 188 | ``` 189 | 190 | # Lets deploy now 191 | First make sure you are in the root directory of the repository you want to deploy 192 | 193 | Next create the heroku app 194 | ```bash 195 | heroku create 196 | ``` 197 | 198 | Create a postgres addon to your heroku app 199 | ```bash 200 | heroku addons:create heroku-postgresql:hobby-dev 201 | ``` 202 | Next we log in to [Heroku dashboard](https://dashboard.heroku.com) to access our app and configure it 203 | 204 | ![Imgur](https://i.imgur.com/dbDQxlJ.png) 205 | 206 | Click on the Settings menu and then on the button Reveal Config Vars: 207 | Next add all the environment vaiables, by default you should have `DATABASE_URI` configuration created after installing postgres to heroku. 208 | 209 | Alternatively you can add all your configurations in `.env` file directly to heroku by running the this command. 210 | 211 | ```bash 212 | heroku config:set $(cat .env | sed '/^$/d; /#[[:print:]]*$/d') 213 | ``` 214 | Remember to first set `DEBUG` to false and confirm that you have added all the confuguration variables needed. 215 | 216 | ![Imgur](https://i.imgur.com/D0s6BkV.png?1) 217 | 218 | ### pushing to heroku 219 | 220 | confirm that your application is running as expected before pushing, runtime errors will cause deployment to fail so make sure you have no bugs, you have all the following `Procfile`, `requirements.txt` with all required packages and `runtime.txt` . 221 | 222 | ```bash 223 | $ git push heroku master 224 | ``` 225 | 226 | if you find an error where the heroku git initialization has turned out unsuccessful; run the following command 227 | ``` 228 | bash 229 | $ heroku git:remote -a 230 | ``` 231 | If you did everything correctly then the deployment should be done after a while with an output like this 232 | 233 | ```bash 234 | Enumerating objects: 94, done. 235 | Counting objects: 100% (94/94), done. 236 | Delta compression using up to 8 threads. 237 | Compressing objects: 100% (84/84), done. 238 | Writing objects: 100% (94/94), 3.35 MiB | 630.00 KiB/s, done. 239 | Total 94 (delta 24), reused 0 (delta 0) 240 | remote: Compressing source files... done. 241 | remote: Building source: 242 | remote: 243 | remote: -----> Python app detected 244 | remote: -----> Installing python-3.6.6 245 | remote: -----> Installing pip 246 | remote: -----> Installing requirements with pip 247 | remote: Collecting config==0.3.9 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 1)) 248 | remote: Downloading https://files.pythonhosted.org/packages/0a/46/186ac016f3175211ec9bb4208579bc6dc9dd7dc882790d9f281533b83b0f/config-0.3.9.tar.gz 249 | remote: Collecting dj-database-url==0.5.0 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 2)) 250 | remote: Downloading https://files.pythonhosted.org/packages/d4/a6/4b8578c1848690d0c307c7c0596af2077536c9ef2a04d42b00fabaa7e49d/dj_database_url-0.5.0-py2.py3-none-any.whl 251 | remote: Collecting Django==1.11 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 3)) 252 | remote: Downloading https://files.pythonhosted.org/packages/47/a6/078ebcbd49b19e22fd560a2348cfc5cec9e5dcfe3c4fad8e64c9865135bb/Django-1.11-py2.py3-none-any.whl (6.9MB) 253 | remote: Collecting django-bootstrap3==10.0.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 4)) 254 | remote: Downloading https://files.pythonhosted.org/packages/18/a8/f12d8491155c7f237084b883b8600faf722e3a46e54f17a25103b0fb9641/django-bootstrap3-10.0.1.tar.gz (40kB) 255 | remote: Collecting django-heroku==0.3.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 5)) 256 | remote: Downloading https://files.pythonhosted.org/packages/59/af/5475a876c5addd5a3494db47d9f7be93cc14d3a7603542b194572791b6c6/django_heroku-0.3.1-py2.py3-none-any.whl 257 | remote: Collecting gunicorn==19.9.0 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 6)) 258 | remote: Downloading https://files.pythonhosted.org/packages/8c/da/b8dd8deb741bff556db53902d4706774c8e1e67265f69528c14c003644e6/gunicorn-19.9.0-py2.py3-none-any.whl (112kB) 259 | remote: Collecting Pillow==5.2.0 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 7)) 260 | remote: Downloading https://files.pythonhosted.org/packages/d1/24/f53ff6b61b3d728b90934bddb4f03f8ab584a7f49299bf3bde56e2952612/Pillow-5.2.0-cp36-cp36m-manylinux1_x86_64.whl (2.0MB) 261 | remote: Collecting psycopg2==2.7.5 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 8)) 262 | remote: Downloading https://files.pythonhosted.org/packages/5e/d0/9e2b3ed43001ebed45caf56d5bb9d44ed3ebd68e12b87845bfa7bcd46250/psycopg2-2.7.5-cp36-cp36m-manylinux1_x86_64.whl (2.7MB) 263 | remote: Collecting python-decouple==3.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 9)) 264 | remote: Downloading https://files.pythonhosted.org/packages/9b/99/ddfbb6362af4ee239a012716b1371aa6d316ff1b9db705bfb182fbc4780f/python-decouple-3.1.tar.gz 265 | remote: Collecting pytz==2018.5 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 10)) 266 | remote: Downloading https://files.pythonhosted.org/packages/30/4e/27c34b62430286c6d59177a0842ed90dc789ce5d1ed740887653b898779a/pytz-2018.5-py2.py3-none-any.whl (510kB) 267 | remote: Collecting whitenoise==3.3.1 (from -r /tmp/build_19aebf8f25d534a39e73b13219af9927/requirements.txt (line 11)) 268 | remote: Downloading https://files.pythonhosted.org/packages/0c/58/0f309a821b9161d0e3a73336a187d1541c2127aff7fdf3bf7293f9979d1d/whitenoise-3.3.1-py2.py3-none-any.whl 269 | remote: Installing collected packages: config, dj-database-url, pytz, Django, django-bootstrap3, whitenoise, psycopg2, django-heroku, gunicorn, Pillow, python-decouple 270 | remote: Running setup.py install for config: started 271 | remote: Running setup.py install for config: finished with status 'done' 272 | remote: Running setup.py install for django-bootstrap3: started 273 | remote: Running setup.py install for django-bootstrap3: finished with status 'done' 274 | remote: Running setup.py install for python-decouple: started 275 | remote: Running setup.py install for python-decouple: finished with status 'done' 276 | remote: Successfully installed Django-1.11 Pillow-5.2.0 config-0.3.9 dj-database-url-0.5.0 django-bootstrap3-10.0.1 django-heroku-0.3.1 gunicorn-19.9.0 psycopg2-2.7.5 python-decouple-3.1 pytz-2018.5 whitenoise-3.3.1 277 | remote: 278 | remote: -----> Discovering process types 279 | remote: 280 | remote: -----> Compressing... 281 | remote: Done: 56.3M 282 | remote: -----> Launching... 283 | remote: Released v6 284 | remote: https://mtr1bune.herokuapp.com/ deployed to Heroku 285 | remote: 286 | remote: Verifying deploy... done. 287 | To https://git.heroku.com/mtr1bune.git 288 | * [new branch] master -> master 289 | 290 | ``` 291 | 292 | ### Run migrations 293 | ```bash 294 | $ heroku run python manage.py migrate 295 | ``` 296 | 297 | If you instead wish to push your postgres database data to heroku then run 298 | ```bash 299 | $ heroku pg:reset 300 | $ heroku pg:push DATABASE_URL --app 301 | ``` 302 | You can the open the app in your browse. 303 | 304 | # Comment 305 | This process was a lot and you can easily mess up as I did, I suggest analyzing the part where you went wrong and going back to read on what you are supposed to do. I also highly recommend going through official documentations about deploying python projects to heroku as you will get a lot information that can help you debug effectively. I will provide some links in the resources section. 306 | 307 | Remember heroku does not offer support for media files in the free tier subscription so find some where else to store those e.g Amazon s3. 308 | 309 | # Resources 310 | ## heroku Docs 311 | * https://devcenter.heroku.com/articles/heroku-postgresql 312 | * https://devcenter.heroku.com/articles/django-assets 313 | * https://devcenter.heroku.com/articles/python-runtimes 314 | * https://devcenter.heroku.com/articles/procfile 315 | * https://devcenter.heroku.com/articles/getting-started-with-python#introduction 316 | * https://devcenter.heroku.com/articles/deploying-python 317 | * https://devcenter.heroku.com/articles/django-app-configuration 318 | * https://devcenter.heroku.com/articles/python-gunicorn 319 | 320 | ## very helpfull articles 321 | * https://simpleisbetterthancomplex.com/tutorial/2016/08/09/how-to-deploy-django-applications-on-heroku.html 322 | * https://simpleisbetterthancomplex.com/2015/11/26/package-of-the-week-python-decouple.html 323 | 324 | 325 | 326 | --------------------------------------------------------------------------------