# Configuring and setting up subdomains on Django using django-hosts

A subdomain is basically a domain that’s part of another main domain and it is used a lot in many websites. I spent a decent amount of time figuring out how to do that and found [this very helpful post](http://www.learningaboutelectronics.com/Articles/How-to-set-up-subdomains-Django-website.php) and decided to extend it a little in a tutorial form. So if you ever want to add a subdomain for your Django site, something like [`subdomain.your-site.com`](http://subdomain.your-site.com), this might help. 

We are going to go through all the steps from creating a project in django, to getting our subdomain up and running.

## Create a Python virtual environment

As a best practice, we will create a virtual environment. I will use [conda here](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html) to create it with a specific version of python.

```bash
$ conda create -n django-env python=3.6
$ conda activate django-env
```

## Packages installation

Now let’s use pip to install [Django](https://www.djangoproject.com/) \[3\] and [django-hosts](https://pypi.org/project/django-hosts/) \[4\]:

```bash
$ pip install django django-hosts
```

## Create a Django project and app

Once installed, let’s go to our workspace directory and create our django project:

```bash
$ django-admin startproject simpletest
```

You will see a new directory created named `simpletest` and inside it, a `manage.py` file and another `simpletest` folder. To avoid confusion between the project and our apps, I like to rename the parent folder so l’ll just call it `simpletest-prj`. Now you will have something like this:

```plaintext
simpletest-prj
├── manage.py
└── simpletest
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
```

Let’s move inside our `simpletest` directory to run `python3 manage.py runserver` and open [http://localhost:8000/](http://localhost:8000/) to make sure our project works. You should get a page like this.

![](https://res.cloudinary.com/hu0vek80i/image/upload/v1/media/uploads/2020/12/21/django-create-project_nmc1rp align="center")

Now stop your application and create a new app that we will call `home`:

```bash
$ python3 manage.py startapp home
```

We now want to put our own homepage instead of the django default landing page by following a few steps: 

First we need to add a new line to the `urls.py` file in `simpletest` under the admin url so that Django knows where to look and redirect when opening our site:

```python
from django.contrib import admin
from django.urls import path
from . import views  # <-- new import

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home),  # <-- new line
]
```

Then we need to create a `views.py` file under the `simpletest` folder with the following code. This is the one with the logic, but now we will only render and return a `home.html` file:

```python
from django.shortcuts import render

def home(request):
    return render(request, 'home.html')
```

The next thing is to create a template folder under the main project directory `simpletest-prj` and our `home.html` file with the following content:

```xml
<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        Hello there, and welcome to my new site.
    </body>
</html>
```

Finally, we need to create our `TEMPLATE_DIR` variable and add it to the `TEMPLATES` structure on the `settings.py` file:

```python
import os

# Right below the BASE_DIR declaration
TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates')
```

```python
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [TEMPLATE_DIR,],  # <-- This is the modified line
        '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',
            ],
        },
    },
]
```

Refresh your page or run it one more time to get the expected result:

![](https://res.cloudinary.com/hu0vek80i/image/upload/v1/media/uploads/2020/12/21/main-modified-page_icsjyw align="center")

Our directory structure will now look like this:

```python
simpletest-prj
├── db.sqlite3
├── home
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
├── simpletest
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   ├── views.py
│   └── wsgi.py
└── templates
    └── home.html
```

## Configure the app with subdomain

So now our main page is located at `localhost:8000` and what we like to do is to host our `home` app on `home.localhost:8000` instead of something like `localhost:8000/home`. For that we will do the following:

We need to add `home` to our app list along with the already installed `django-hosts` in the `settings.py` file:

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'home',  # <-- Add this
    'django_hosts',  # <-- and this
]
```

Then let’s add our hosts to the `ALLOWED_HOSTS` variable in the same file:

```python
ALLOWED_HOSTS = ['localhost', 'home.localhost']
```

The `MIDDLEWARE` variable needs to be updated with the following two values, the first one at the beginning and the second one at the end

```python
'django_hosts.middleware.HostsRequestMiddleware'
'django_hosts.middleware.HostsResponseMiddleware'
```

```python
MIDDLEWARE = [
    'django_hosts.middleware.HostsRequestMiddleware',  # <-- new line
    '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',
    'django_hosts.middleware.HostsResponseMiddleware',  # <-- another new line
]
```

Under the `ROOT_URLCONF` line, add the following:

```python
ROOT_HOSTCONF = 'simpletest.hosts'
DEFAULT_HOST = 'www'
```

And now we create a `hosts.py` file under `simpletest`. This file will contain all the list of subdomains that will be on our site:

```python
from django_hosts import patterns, host
from django.conf import settings

host_patterns = patterns(
    '',
    host(r'www', settings.ROOT_URLCONF, name='www'),
    host(r'home', 'home.urls', name='home')
)
```

So now we go on to create and edit a `urls.py` file under the `home` directory:

```python
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.home, name='home'),
]
```

And create our view in its corresponding `views.py` file:

```python
from django.shortcuts import render

def home(request):
    return render(request, 'home/hello.html')
```

Create a `templates` folder under `home` with another `home` subdirectory and a `hello.html` file inside:

```xml
<html>
    <head>
        <title>Home</title>
    </head>
    <body>
        Welcome to the subdomain homepage!
    </body>
</html>
```

Save all, refresh your application or run it one more time, and now go to [http://home.localhost:8000/](http://home.localhost:8000/)

![](https://res.cloudinary.com/hu0vek80i/image/upload/v1/media/uploads/2020/12/21/home-app-subdomain_lwwpep align="center")

For reference, the directory structure should look something like the following at this point:

```plaintext
simpletest-prj
├── db.sqlite3
├── home
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── templates
│   │   └── home
│   │       └── hello.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── manage.py
├── simpletest
│   ├── __init__.py
│   ├── asgi.py
│   ├── hosts.py
│   ├── settings.py
│   ├── urls.py
│   ├── views.py
│   └── wsgi.py
└── templates
    └── home.html
```

And that would be it! When you’re ready to deploy your application on your configured domain, just make sure you edit the `ALLOWED_HOSTS` variable to match the name of the actual domain.
