Deploy your Django application with git

Published on: 07 May 2017

I’m going to make a bold statement: Django replaced Ruby on Rails in the hearts
of many developers. With this increase in popularity, we’ve seen tons or
articles, videos and websites dedicated to setting un Django and creating apps
using the framework.

Unfortunately, when it comes to deployment, many of these resources only mention
heroku or pythonanywhere. While these are excellent solutions for quickly
shipping your MVP or prototype, it lacks a bit in terms of flexibility if you
want to create your own custom deployment pipeline.

tl-dr: If you manage your own server infrastructure, we’re going to setup a git
deployment workflow with django

What you’ll need

Working knowledge of ssh

Working knowledge of git

Working knowledge of the bash shell

Basic linux command line skills (sorry hipsters)

(Very) Basic knowledge of vi/vim

Patience

The typical workflow usually looks like this:

You have your development environment, either on your local machine or a remote server

A git server (on GitHub, BitBucket, GitLab …) that you and your team push your work to

A production server (aka your live app).

Usually when you commit and push work you do something like:

git push origin <branch_name>

origin being the name of the remote server your code is being pushed to.
What took me a while to realise is that you can have many remotes for your repo
that point to different servers.

The idea here is to add a new remote to our repo. It will point to our
production server such that when we run git push live master, our code will be
copied over to there.

On the production server

To achieve this, we have some setup work to do on our live server. So go ahead
and connect to it via ssh.

ssh user@host_or_ip_address
# If your server's ssh service listens on a port other than 22, you'll need# to add the -p switch
ssh -p PORT user@host_or_ip_address

Once we’re in, we need to create a new directory for our application. This is
where our deployed code will be copied to.

mkdir -p /home/user/sites/myawesomedjangoproject
# Some people prefer to use /var/www/<project_name>, it's really up to you. Just# make sure remember the path to your project

Please note that the first shebang line is important, it instructs git to use
bash instead of the default shell. Otherwise it won’t activate our (soon to be
created) virtual environment

exit vim by hitting :wq (which in vim lingo means write and quit)

What we’ve done here is set two variables. DEPLOYDIR is an alias for our
project path on the server, and GIT_WORK_TREE which is a special variable that
tells git to copy the code it receives inside of our DEPLOYDIR. This ensures
that we’re always running the latest version of our code.

As you’ve probably noticed, this post-receive file looks very much like a shell
script. That’s because it is (as explained above). It’s executed every time you
push code to the repo.

The last thing we need to is make the script executable, so as soon as you’re
back in the shell run:

sudo chmod +x hooks/post-receive

You can now exit the server and go back to your local machine.

On our local dev environment

Now that we’ve created our remote repository, we need to add it to our
project (I like to call mine live).

It takes one simple command:

git remote add live root@ip_address:/var/repos/myawesomedjangoproject.git
# And if your server's ssh service listens on a different port :
git remote add live ssh://root@ip_address:PORT/var/repos/myawesomedjangoproject.git

To make sure it was added, you can print the list of available remotes by running:

git remote -v# v for verbose

and that’s it ! You can now make changes locally, commit and deploy
them live (or staging if it’s a staging server) and see your changes instantly.

You can obviously still push to github/lab or bitbucket with
git push origin <branch>
like you normally would.

Bonus

As I mentioned in the first part, the post-receive hook is a shell script. Which
means you can use it to perform all kinds of tasks against your code, like
running front-end builds, installing dependencies, etc …

I run my Django Apps as systemd services, if you don’t you can just call python
manage.py runserver. If you want to know how to setup Django the way I do just
follow this very comprehensive tutorial over on Digital Ocean

Conclusion

I am fully aware that there are more sophisticated methods of deployment through
Docker, Travis (For continious integration) etc. But if you have a small app that
you want to ship and you already have an infrastructure, I’ve found this method
to be more than suitable.