<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Guguweb - heroku</title><link href="https://www.guguweb.com/" rel="alternate"></link><link href="https://www.guguweb.com/feeds/heroku.atom.xml" rel="self"></link><id>https://www.guguweb.com/</id><updated>2022-01-07T15:56:58+01:00</updated><subtitle>Freelance developer and sysadmin</subtitle><entry><title>How to migrate your existing Django project to Heroku</title><link href="https://www.guguweb.com/2016/05/18/how-to-migrate-your-existing-django-project-to-heroku/" rel="alternate"></link><published>2016-05-18T14:15:45+00:00</published><updated>2022-01-07T15:56:58+01:00</updated><author><name>Augusto Destrero</name></author><id>tag:www.guguweb.com,2016-05-18:/2016/05/18/how-to-migrate-your-existing-django-project-to-heroku/</id><summary type="html">&lt;hr&gt;
&lt;p&gt;Recently I had some fun with &lt;a href="https://www.heroku.com/" target="_blank" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;, the well known PaaS provider. I had a small personal Django project I use for invoicing that I ran locally with ./manage.py runserver when needed. That was a perfect candidate for the &lt;a href="https://www.heroku.com/pricing" target="_blank" rel="noopener noreferrer"&gt;Heroku free plan&lt;/a&gt; because I need to access the app …&lt;/p&gt;</summary><content type="html">&lt;hr&gt;
&lt;p&gt;Recently I had some fun with &lt;a href="https://www.heroku.com/" target="_blank" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;, the well known PaaS provider. I had a small personal Django project I use for invoicing that I ran locally with ./manage.py runserver when needed. That was a perfect candidate for the &lt;a href="https://www.heroku.com/pricing" target="_blank" rel="noopener noreferrer"&gt;Heroku free plan&lt;/a&gt; because I need to access the app only occasionally.&lt;/p&gt;
&lt;p&gt;In this tutorial I assume you have a basic knowledge of what Heroku is, and that you already know how to create and deploy a Python project on Heroku. In case you miss some basic information you can refer to the good &lt;a href="https://devcenter.heroku.com/articles/getting-started-with-python" target="_blank" rel="noopener noreferrer"&gt;Getting started tutorial on Heroku with Python&lt;/a&gt;.&lt;/p&gt;
&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#how-to-structure-your-django-project-for-heroku"&gt;How to structure your Django project for Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#how-to-configure-your-django-project-for-heroku"&gt;How to configure your Django project for Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-an-heroku-application-for-your-django-project"&gt;Create an Heroku application for your Django project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#migrating-data"&gt;Migrating data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#media-files-on-aws-s3"&gt;Media files on AWS S3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="how-to-structure-your-django-project-for-heroku"&gt;How to structure your Django project for Heroku&lt;/h2&gt;
&lt;p&gt;Here I focus on my use case, which was to migrate an existing Django project on Heroku platform. My existing Django project was structured in accordance to the best practices I read in the wonderful &lt;a href="http://twoscoopspress.com/products/two-scoops-of-django-1-8" target="_blank" rel="noopener noreferrer"&gt;Two Scoops of Django&lt;/a&gt; book, so my project structure was similar to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;django/
├── project
│   ├── __init__.py
│   ├── settings
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── local.py
│   │   └── production.py
│   ├── urls.py
│   ├── wsgi.py
├── app
│   ├── __init__.py
│   ├── admin.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   ├── views.py
└── manage.py
requirements
├── base.txt
├── local.txt
└── production.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;See how I have different settings for each deploy environment: one for local development, one for production. All common settings go in base.py.&lt;/p&gt;
&lt;p&gt;See also how I have a different requirements file for each environment, for example I have django-debug-toolbar in local.txt, while I have psycopg2 in production.txt. All common requirements are in base.txt.&lt;/p&gt;
&lt;p&gt;For Heroku I created a file &lt;em&gt;heroku.txt&lt;/em&gt; under &lt;em&gt;requirements/&lt;/em&gt; directory with the following content:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-r base.txt

dj-database-url==0.3.0
psycopg2==2.6.1
whitenoise==2.0.2
django-storages==1.4.1
boto==2.38.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="how-to-configure-your-django-project-for-heroku"&gt;How to configure your Django project for Heroku&lt;/h2&gt;
&lt;p&gt;On Heroku I will use Postgres as database backend (which is free , and &lt;a href="https://github.com/kennethreitz/dj-database-url" target="_blank" rel="noopener noreferrer"&gt;dj-database-url&lt;/a&gt; to configure the database parameters using an environment variable, which is already set by Heroku.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll also use &lt;a href="http://whitenoise.evans.io/en/stable/django.html" target="_blank" rel="noopener noreferrer"&gt;whitenoise&lt;/a&gt; to handle static files directly from django and &lt;a href="https://github.com/jschneier/django-storages" target="_blank" rel="noopener noreferrer"&gt;django-storages&lt;/a&gt; to handle media files on Amazon S3.&lt;/p&gt;
&lt;p&gt;The first thing you have to do to tell Heroku you are deploying a python project is to put a &lt;code&gt;requirements.txt&lt;/code&gt; file in the root of your git project. You can create a file with this content to include the requirements specific to Heroku:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-r requirements/heroku.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you have to do some modification to your settings, for deploy on Heroku platform:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Parse database configuration from $DATABASE_URL&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dj_database_url&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="n"&gt;ALLOWED_HOSTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yourappname.herokuapp.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dj_database_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;WSGI_APPLICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;yourproject.wsgi_heroku.application&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;STATICFILES_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;whitenoise.django.GzipManifestStaticFilesStorage&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;static_root&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;storages&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_FILE_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;storages.backends.s3boto.S3BotoStorage&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AWS_ACCESS_KEY_ID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AWS_SECRET_ACCESS_KEY&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;yourbucketname&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you have to edit your wsgi.py file to make use of whitenoise for static files, the file whould look something like this. Save it in a different wsgi_heroku.py file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.wsgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_wsgi_application&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;whitenoise.django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DjangoWhiteNoise&lt;/span&gt;

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DJANGO_SETTINGS_MODULE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;yourproject.settings.heroku&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_wsgi_application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DjangoWhiteNoise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="create-an-heroku-application-for-your-django-project"&gt;Create an Heroku application for your Django project&lt;/h2&gt;
&lt;p&gt;Now you can create you Heroku application:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="n"&gt;eu&lt;/span&gt; &lt;span class="n"&gt;yourappname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the root directory of your project you should have a Procfile, used by Heroku to know how to launch the web worker, in our case the Procfile should contain just one line like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;pythonpath&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt; &lt;span class="n"&gt;yourproject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wsgi_heroku&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now push the code on Heroku:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can create the database schema with the usual migrate command, run on the Heroku instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;heroku run python django/manage.py migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="migrating-data"&gt;Migrating data&lt;/h2&gt;
&lt;p&gt;If you have some data to migrate you can use a couple of command from core Django&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./manage.py dumpdata yourapp &amp;gt; yourapp/fixtures/app_data.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can import the data on Heroku instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;loaddata&lt;/span&gt; &lt;span class="n"&gt;app_data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="media-files-on-aws-s3"&gt;Media files on AWS S3&lt;/h2&gt;
&lt;p&gt;If your application needs some user uploaded data, you can use Amazon S3 to store the files, by using django-storages app to configure the correct Storage for you media files.&lt;/p&gt;
&lt;p&gt;The configuration of django-storages is out of scope for this tutorial, but you can find some &lt;a href="https://www.caktusgroup.com/blog/2014/11/10/Using-Amazon-S3-to-store-your-Django-sites-static-and-media-files/" target="_blank" rel="noopener noreferrer"&gt;good tutorials&lt;/a&gt; on the web.&lt;/p&gt;</content><category term="web"></category><category term="django"></category><category term="git"></category><category term="heroku"></category><category term="python"></category></entry></feed>