DEV Community

Cover image for Automatically deploying Django app to PythonAnywhere through GitHub.
Soumya Ranjan Naik
Soumya Ranjan Naik

Posted on • Updated on

Automatically deploying Django app to PythonAnywhere through GitHub.

This post will explain how to setup automatic deployments to a Django Web-App hosted on PythonAnywhere.

What people normally do:
1. Everyone does this:

Local -> GitHub

2. People with PAID account do this(using ssh access):

Local -> PythonAnywhere

3. What I do(with a free or paid account):

Local -> GitHub -> PythonAnywhere

Let me first explain why I do this and then I will explain how to do this stuff.

Note: You are free to Jump to the Implementation section

Why?

Putting it simply GitHub is great place to collaborate and they have a better UI than PythonAnywhere to view code. Setting up PythonAnywhere's ssh access for everyone who will be working on the project is just too time taking for me and then again explain them what I did is another difficult task and that too if I have a paid account.

So, I thought it would be amazing if we can just push code onto GitHub and GitHub automatically updates the code on PythonAnywhere and not to mention the default features that are provided by GitHub like Pull Requests, Issues, Actions(haven't used them till now still a feature) and everything else that GitHub offers.

How

We will be using something known as Deploy Keys and Webhooks provided by GitHub to tell our Django Web-App tha it has been updated so it pulls the latest code.

First:

Install the Python package named GitPython by using the following command:

$ pip install GitPython
Enter fullscreen mode Exit fullscreen mode

Second:

Write the view function that will receive the update and update the code on the server.

Go to your views.py and add the following code:

import git
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def update(request):
    if request.method == "POST":
        '''
        pass the path of the diectory where your project will be 
        stored on PythonAnywhere in the git.Repo() as parameter.
        Here the name of my directory is "test.pythonanywhere.com"
        '''
        repo = git.Repo("test.pythonanywhere.com/") 
        origin = repo.remotes.origin

        origin.pull()

        return HttpResponse("Updated code on PythonAnywhere")
    else:
        return HttpResponse("Couldn't update the code on PythonAnywhere")
Enter fullscreen mode Exit fullscreen mode

You can also send response codes with them by passing the parameter "status" within the "HttpResponse" that will be returned.

Third:

Set the URL where the Payload from GitHub will be sent.

To add the payload URL add the following lines into urls.py file of your Django Project:

from django.urls import path

'''
here the name of my app is updater so I add the import my view from there
replace updater with your app-name where you have your views.py
'''
from updater import views

urlpatterns = [
    path("update_server/", views.update, name="update"),
]

Enter fullscreen mode Exit fullscreen mode

Fourth:

Now push this code to GitHub and login to our account on PythonAnywhere.

Now follow the following steps:

Step 1: Open a bash terminal on PythonAnywhere.

Step 2: Issue the following command:

$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Enter fullscreen mode Exit fullscreen mode

after this command you will be shown the following prompt:

> Generating public/private rsa key pair.
Enter fullscreen mode Exit fullscreen mode

Step 3: When you're prompted to "Enter a file in which to save the key," press Enter. This accepts the default file location.

> Enter a file in which to save the key (/home/you/.ssh/id_rsa): [Press enter]
Enter fullscreen mode Exit fullscreen mode

Step 4: At the prompt, type a secure passphrase.

> Enter passphrase (empty for no passphrase): [Type a passphrase]
> Enter same passphrase again: [Type passphrase again]
Enter fullscreen mode Exit fullscreen mode

Step 5: Issue the following command on the bash terminal of PythonAnywhere to get your key.

$ cat ~/.ssh/id_rsa.pub 
Enter fullscreen mode Exit fullscreen mode

then press CTRL+C to copy the key.

Fifth:

Go to your GitHub Account and then Go to the Repository in which you have your Django Project.

Then follow the following steps:

Step 1: From your repository, click Settings as shown below.

Alt Text

Step 2: In the sidebar, click Deploy Keys, then click Add deploy key.

Alt Text

Step 3: Provide a title, paste in your public key.

Alt Text

Step 4: Select Allow write access if you want this key to have write access to the repository. A deploy key with write access lets a deployment push to the repository.

Step 5: Click Add key.

Sixth:

Go to your PythonAnywhere account and go to the bash terminal and setup your Web-App but use the SSH instead of HTTPS for cloning your Repository from GitHub.

Note: I would suggest to use the automated script pa_autoconfigure_django.py available in pythonanywhere package which can be installed via pip to automatically setup my project on PythonAnywhere.

If you already have a project setup on PythonAnywhere using HTTPS then open a bash terminal and edit the remote URL to set SSH by using the following command :

$ git remote set-url origin git@github.com:USERNAME/REPOSITORY.git
Enter fullscreen mode Exit fullscreen mode

Seventh:

Go back to the settings tab of your Repository on GitHub and follow the following steps :

Step 1: In the sidebar, click Webhooks, then click Add webhook.

Alt Text

Step 2: Fill in the Payload URL and set the "Content type" to "application/json" as shown below.

Alt Text

Step 3: click "Add webhook".

Finally:

You will see the following when it is success

Alt Text

If it show some other icon in place of a green tick then click on edit and at the bottom you can see the "Recent Deliveries" here you can click on the button shown below to see the details of that delivery.

Alt Text

After clicking you will see two tabs "Request" and "Response" to see the details of failure you can click on response and you will get the details as shown below

Alt Text

If you get any response code other than 200 then go to the error log on your PythonAnywhere account and check what's the problem.

The most common mistake that I make is when I return something else instead of HttpResponse it will throw some Attribute error.

If you get stuck somewhere then feel free to contact me on telegram using the link https://t.me/soumya_r .

Top comments (15)

Collapse
 
gpjt profile image
Giles Thomas

PythonAnywhere dev here -- thanks for the great how-to! Just a quick note, you should add an "import git" to the top of that views.py.

Collapse
 
soumyaranjannaik profile image
Soumya Ranjan Naik • Edited

Thanks for pointing it out. Corrected it.
By the way as far as I know you work pythonanywhere right ? (I have seen your name on forums)

Collapse
 
gpjt profile image
Giles Thomas

Yes, that's me :-) And thanks for adding the correction!

Collapse
 
friedmanyariv profile image
Yariv Friedman

Thanks for the sharing. I followed the path until stumble across: git remote set-url origin git@github.com:USERNAME/REPOSITORY.git then I recieved constantly "
fatal: Not a git repository (or any parent up to mount point /home/donbonbon)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set). I actually wasn't sure if I need to use my git repo or pythonanywhere, I ended up testing all.. Noting worked... can you kindly advise. PS - I also tried it on an empty project with the script your recommended... it gave a warning to work only with python 2.7. Any input would be highly appreciated.

Collapse
 
akshayg profile image
Akshay-G-Dev

I know its too late but adding it here for future readers
for some reason git@github.com:USERNAME/REPOSITORY.git doesn't work so instead do this

git remote set-url origin https://{token}@github.com/{username}/{project}.git

and here is steps to create access token for above url, as password access is not supported now

Collapse
 
oaltun profile image
oaltun

Hi there, thanks for the tutorial.

Question: does one still have to push the "Reload ..." button in the web tab in pythonanywhere manually after doing this? Or is this only for getting the code to pythonanywhere?

If it also solves the problem of manual reloading in the web tab, I will give it a go :).

Collapse
 
soumyaranjannaik profile image
Soumya Ranjan Naik

Yeah, you have to. You can also use pythonanywhere API to do it.

Collapse
 
tanuja01 profile image
Tanuja01

Hi,

I'm receiving this error:
cmdline: git pull -v origin
stderr: 'fatal: Could not read from remote repository.
NO MATCH
Please make sure you have the correct access rights
and the repository exists

Please guide me

Collapse
 
tahseen09 profile image
Tahseen Rahman

Awesome!
It's so much fun to learn something new.

Collapse
 
iamgaddiel profile image
Gaddiel Ighota • Edited

Hi everyone,
I know this post has been made since, but I'm having same issues @tanuja01 raised and I can't seem to find anything that address this issue. Due to this the webhook setup on GitHub does not check as okay.
I really need help with this ASAP because my current project I'm working on depends on it.

Collapse
 
asher_not_found profile image
asher

To auto-reload the web app:
pythonanywhere.com/forums/topic/27...

Collapse
 
maneprajakta profile image
Prajakta Mane

Can a private GitHub repo be connected to pythonanywhere.

Collapse
 
soumyaranjannaik profile image
Soumya Ranjan Naik

Yes you can

Collapse
 
maneprajakta profile image
Prajakta Mane

Thank you !

Collapse
 
smyja profile image
Smyja

Spent the whole day setting it up. Thanks, I learnt new things while doing it.