Published on

Building a Blog using Django and AWS Part 1: First Steps

Greetings!

Welcome to my blog!

This site will serve as a record of my work, occasional thoughts and simply as a place to share what I find interesting. I hope you enjoy!

My first pair of posts will show I built this site in Django, put a design together with Tailwind and hosted in AWS. Crucially, I've included my solutions to the errors I encountered: hopefully this will help someone in the future.

Setting up: first steps!

I built this site using the Python library Django and host it on AWS. Django has the capability to handle much more complicated sites than a simple blog (it’s the backbone of the up-and-coming Instagram) and there are simpler ways to host a static site. Nevertheless, I wanted to use Django so I could learn more Python and become more familiar with AWS.

Basic Functionality

The best introduction to Django is Corey Schafer’s tutorial series. The Python backend behind this site effectively copies the project as laid out in the tutorial, with some of the unnecessary additions like user accounts stripped out. This, plus the basic Bootstrap template included in the tutorial, formed the first iteration.

The Dazzling Results

Deployment

Deploying the site to a production server is where the real fun begins. AWS offers free use of a EC2 instance, a load balancer and a nominal (5GB) amount of S3 storage. For now, before torrents of people come hungry for my musings, this is perfectly ample for a small static blog.

I followed these two tutorials on doing this: Amazon’s own and this by testdriven.io

The EB Command Line tooling required a particular version of Python, which differed from my own. The best way I’ve found to juggle different instances of Python is PyEnv, supplemented by the PyEnv VirtualEnv extension. (Conda is an alright alternative for simple data science work, but as soon as you start creating things for use, as opposed to just analysing data, it becomes impossible to manage).

Unfortunately, the official instructions for deploying the Django App to Elastic Beanstalk are limited, so here are some of the errors I came across and how I got around them.

General Naming Conventions

One danger with boilerplate code is checking what is an arbitrary name and what is required by Django. One thing that threw me is that the name of the example app in the Amazon tutorial - ebdjango - is not used elsewhere.

So, in the Django.config file, the tutorial's:

option_settings:
     aws:elasticbeanstalk:container:python:
          WSGIPath: ebdjango.wsgi:application

becomes:

 option_settings:
         aws:elasticbeanstalk:container:python:
               WSGIPath: <your_application_name>.wsgi:application

SQlite

This 'NotSupportedError' comes from Django not being able to find the latest version of SQlite on the EC2 instance. SQL Databases are how Django stores different bits of data – for instance, these blog posts – and, instead of connecting a costly dedicated Postgres RDS, is it simpler to just use a SQlite database hosted on S3. The version of SQlite accessible to the Django app on an Elastic Beanstalk instance is outdated and I found it impossible to build an updated version on the box

The workaround I found is to use the python interface pysqlite on the Production box instead. This annoyingly created problems when running the site locally, so to satisfy both, this only activated when the website was running in AWS, as shown here:

 if IN_PRODUCTION:
     __import__("pysqlite3")
     sys.modules["sqlite3"] = sys.modules.pop("pysqlite3")

    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = os.environ["SECRET_KEY"]

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

     ALLOWED_HOSTS = [
         "charliehetherington.com",
   ]

 else:
     # SECURITY WARNING: keep the secret key used in production secret!
     SECRET_KEY = "ahem"

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

     ALLOWED_HOSTS = ["localhost", "127.0.0.1"]

The line checks whether the code is running in production by seeing whether the variable IN_PRODUCTION exists in the environment. This can be added to AWS in the Environment Configuration page.

If true, it imports pysqlite and replaces the sqlite3 module in the python sys.modules dictionary, which Python uses to keep track of all loaded modules. This means that Django wants to use something from the sqlite3 library, it is directed to pysqlite3 - there were no other code changes needed!

It also provides a nice way to switch between the allowed hosts and DEBUG setting.

Static Files

I found that I needed this in my Django.config file to serve static files correctly when following the AWS tutorial:

aws:elasticbeanstalk:environment:proxy:staticfiles:
   /static: static