Srikanth Technologies

Deploying Django Project to PythonAnywhere.com

In this blog, I list out steps required to deploy a Django project to PythonAnywhere.com.

PythonAnywhere.com is a cloud platform that allows you to have a free account, which allows you to host one web application without custom domain. Of course, you can upgrade your account and get more features. For details, please check PythonAnywhere.com

When you register with a username (mine is srikanthtechnologies), you get to host a web application that is available at username.pythonanywhere.com (srikanthtechnologies.pythonanywhere.com).

Note: In the rest of the blog, whenever I use srikanthtechnologies, it means you have to replace that with your own username.

The following are steps to be taken to deploy a Django project that is in your local system using SQLite database to PythonAnywhere.com.

Prepare your project in local system

I assume you have Django project that is fully functioning in your local system. Make sure it is bug free by testing it using Django Development Server.

I assume the name of the project is website in c:\django folder. It has a single project called books that uses SQLite database. The following is the directory structure of website project. I am showing only important files in that project.

c:\django
      website
          manage.py
          db.sqlite3
          website
            settings.py
            ...
          books
            templates
            static
               styles.css 
            ...

In order to deploy a Django project to any production server, you have to take a few steps. Exact steps may differ from one server to another. Here I am taking steps needed for PythonAnywhere.com. However, most of the steps are to be taken even for other servers such as Heroku etc.

Change website\settings.py

Go to settings.py in website folder and make the following changes. Lines in bold are the ones modified.

from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'i8)#tq1_1bq^%ev%4ast3_8%hw@#r#edkpeo_krfkli+##l&qt'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['localhost','srikanthtechnologies.pythonanywhere.com'] 


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'books',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'website.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'website.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases

DATABASES = {
     'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': str(BASE_DIR / 'db.sqlite3'),      # str must be used otherwise throws error 
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

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

Here are important changes:

Collect static files into a folder

All static resources like images, stylesheets must be placed in a single folder in the server. So, we need to use collectstatic command to collect all static resources and place them in a folder, whose name is mentioned using STATIC_ROOT in settings.py.

Give the following command from outer website folder in which we have file manage.py. It will copy all static resources of all applications into the folder mentioned in settings.py - staticfiles.

python manage.py collectstatic 

Create .zip file

Once settings.py is modified and static files are collected into a single folder, we are ready to create a .zip file that will be uploaded to PythonAnywhere.

However, it must be noted that it is possible to use git to clone a repo that is available in github.com. You can push your project (from local system) to github repo and then clone it in PythonAnywhere.

I feel, to start with, it is easier to zip the entire project, upload to PythonAnywhere and unzip there. PythonAnywhere does allow you to upload individual files and even modify them there in the server using a simple editor.

Once website.zip (using any software like winzip) is created for website folder, we are ready to upload to PythonAnywhere.

Upload zip file and unzip

Go to files section of PythonAnywhere and select Upload a file button.

Select website.zip file from local file system to be uploaded.

You can see website.zip in your home directory (/home/srikanthtechnologies).

Go to bash console using Consoles option in Dashboard and select bash option.

Make sure you are in home directory and unzip website.zip.

~ $ pwd
/home/srikanthtechnologies
~ $ unzip website.zip
....
~ $ cd website
~/website $ ls
books  db.sqlite3  manage.py staticfiles  website

Now you see a folder /home/srikanthtechnologies/website with all files related to project.

Installing libraries

In case your project needs some extra libraries that PythonAnywhere is not providing by default, you can install them using pip3. You can create a virtual environment also if you need a separate environment for your project.

Do check what libraries PythonAnywhere is providing (batteries included) before you manually install them. It is possible to get list of installed libraries from bash console as shown below.

Note: You must use pip3 and python3 as pip and python refer to version 2.x.

~$pip3 list 

If you decide to install any required library like Django Rest Framework, use PIP3 as follows. You must use --user flag otherwise it throws error.

~$pip3 install djangorestframework --user  

Create and configure Web Application in PythonAnywhere.com

From Dashboard in PythonAnywhere, click on Web link to go to web section.

Click on Add a new web app and it will ask you to provide details of web application.

In Select a Python Web Framework section, select Manual Configuration and then select Python 3.8 as your Python version.

When it displays configuration of your newly created web application, provide the following details:

I hope you could take above steps successfully to deploy Django project to PythonAnywhere.com. I found it the most intuitive of all. Having tried a few different options, I felt it is the easiest of all options. Give a try.

It is possible to use MySQL database instead of SQLite as PythonAnywhere provides MySQL for every user by default. Get more details about How to use MySQL.

All the best!