Ugo's Blog


How to implement subdomains in Django

A step-by-step guide on how to implement subdomains in Django...

Author: Ugochukwu E. Nwachukwu
 Jan. 13, 2023    395 views  


The content of this blog post is for informational purposes only and should not be considered as professional advice or endorsement.




I discovered that this is not really a popular topic in the Django community. It's something I have always found interesting and decided to see if it was possible. As you obviously guessed, it is. So, here is a step-by-step guide on one way of implementing subdomains in Django.

NoteBefore proceeding, this article assumes you already have a good understanding of the Python programming language and Django web framework.

 

Installation

First, we need to install the needed modules. Run these commands in the terminal.

pip install django 
pip install django-hosts

 

Create Project

Next, we need to create our project. Run these commands in the terminal.

python -m django startproject DjangoSubDomainsProject

 

For this example, we will create two apps. These two apps will be App1 and App2, and they will have corresponding subdomains; app1.localhost:8000 will be for App1 and app2.localhost:8000 will be for App2. So let's create these apps. Run these commands in the terminal.

python -m django startapp App1
python -m django startapp App2

 

 

Modify Settings File

For this, we need to open the settings.py file in the DjangoSubDomainsProject folder,

Firstly, we need to let Django know we'll be using the apps we have created and the django-hosts app. Add App1, App2 and django_hosts to INSTALLED_APPS setting. Now, you should have something like this;

INSTALLED_APPS = [

    ...  # represents other apps

    "App1",

    "App2",

    "django_hosts",

]

 

Next, we need to make sure that django_hosts.middleware.HostsRequestMiddleware is at the beginning of your MIDDLEWARE or MIDDLEWARE_CLASSES setting. You also need to add django_hosts.middleware.HostsResponseMiddleware to the end of your MIDDLEWARE or MIDDLEWARE_CLASSES setting. You should have something like this now;

MIDDLEWARE = [

    "django_hosts.middleware.HostsRequestMiddleware", # must remain at the top of this list

    ...  # represents other Middleware

    "django_hosts.middleware.HostsResponseMiddleware", # must remain at the bottom of this list

]

 

Modifying your template setting is the next step. You need to ensure that you have a TEMPLATES_DIR setting and it is set to "templates". This way, Django can easily reference the templates folder in each app.

TEMPLATES_DIR = "templates"

TEMPLATES = [

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        'DIRS': [TEMPLATES_DIR,],

        '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',

            ],

        },

    },

]

 

Now we configure the settings for our static files.

STATIC_URL = "/static/"
STATIC_ROOT = "static"

 

The next step is to create the hosts.py file in the folder as your urls.py.

Set the ROOT_HOSTCONF setting in your settings.py file to dotted Python import path of the module containing your host patterns, e.g.

ROOT_HOSTCONF = "DjangoSubDomainsProject.hosts"

 

Set the DEFAULT_HOST setting to the name of the host pattern you want to refer to as the default pattern. It will be used if no other pattern matches or you do not give a name to the host_url template tag. We will cover that tag later on. This is what I used in this case.

DEFAULT_HOST = "www"

 

In case you want to append a default domain name to the domain part of the rendered URL you can simply set the PARENT_HOST. In our case, this is recommended. For instance:

PARENT_HOST = "localhost:8000"

 

Setting the hosts

Next, we need to add hosts to our hosts.py fileFor the sake of this project, I will use these hosts.

from django.conf import settings

from django_hosts import patterns, host



host_patterns = patterns("",

    host(r'www', settings.ROOT_URLCONF, name='www'),

    host(r'app1', 'App1.urls', name='app1'),

    host(r'app2', 'App2.urls', name='app2'),

)

 

 

Now, you might use dynamic or wildcard host schemes. An example of a scenario where this can be used is if you want usernames to be the subdomains, for example, if your main domain is example.com, you can have <username>.example.com where the username can be the various usernames of your users. For that, you will need to use regular expressions. Here's a sample;

host(r"(\w+)", "<path.to.custom_urls>", name="wildcard"),

You can add this to host_patterns above.

 

Adding views to our apps

Now, we need to add views to our apps so we can see the work we have done so far in the browser. We will start with App1.

Go to the views.py file of App1 and create a simple view. Here's mine;

from django.shortcuts import render

# Create your views here.


def home(request):
    return render(request, "App1/index.html")

 

Create a urls.py file in the App1 folder and add this view to the urlpatterns.

from django.urls import re_path

from . import views

urlpatterns = [
    re_path("^$",views.home,name="home"),
]

Do the same for App2.

 

The next step is to create a static folder and a templates folder in your App1 folder, then in both of those folders, create a folder called App1. You should have something like this;

Side Note: The reason we put the contents of the static and templates folder in folders named App1 is because, in our settings.py file, the TEMPLATES_DIR setting is "templates", which means Django should get its templates from the templates folders of all the apps, and the STATIC_ROOT setting is "static", which means Django should get the static files from the static folders of all the apps.
Using these settings will mean Django will combine all the contents of all the static folders into one and do the same for the template folders. This might yield errors if some files have the same name, for example, if there is an index.html file in the templates folder of App1 and if there is also an index.html file in the templates folder of App2. To solve this, we put the contents of the static folder in a sub-folder called App1 and the contents of the templates folder in a sub-folder called App1. We will do the same for App2. This way, instead of having two index.html files, we can have App1\index.html and App2\index.html.

 

Next, in the App1 folder of our templates folder in App1, create an index.html file and add some basic HTML code, and style it. Do the same in App2. Make sure the contents of both files are different.

 

Now, we need to put links so both apps can be linked. Here's where it gets interesting. In both index.html files, load the hosts template tag like so;

{% load hosts %}

 

Now, create and add the links for our views.

<a href="{% host_url 'home' host 'app1' %}">App1</a>
<a href="{% host_url 'home' host 'app2' %}">App2</a>

 

These will be rendered as

<a href="//app1.localhost:8000/">App1</a>

<a href="//app2.localhost:8000/">App2</a>

 

Et voila! You've successfully made a simple Django website that supports multiple domains! Try it out! Go app1.localhost:8000  for App1 and app2.localhost:8000  for App2. Congrats on making it this far.

 

Here's the GitHub repo for this project:

https://github.com/ugo-en/DjangoSubDomainsProject

 

 

Credits

In learning about this concept and creating this post, I found this link to be crucial.

 

 






Liked this post? Share it to others!










Check Profile