Django 'Sites' Model - what is and why is 'SITE_ID = 1'?

Django was created from a set of scripts developed at a newspaper to publish content on multiple domains; using one single content base.

This is where the "sites" module comes in. Its purpose is to mark content to be displayed for different domains.

In previous versions of django, the startproject script automatically added the django.contrib.sites application to INSTALLED_APPS, and when you did syncdb, a default site with the URL example.com was added to your database, and since this was the first site, its ID was 1 and that's where the setting comes from.

Keep in mind that starting from 1.6, this framework is not enabled by default. So if you need it, you must enable it

The SITE_ID setting sets the default site for your project. So, if you don't specify a site, this is the one it will use.

So to configure your application for different domains:

  1. Enable the sites framework
  2. Change the default site from example.com to whatever your default domain is. You can do this from the django shell, or from the admin.
  3. Add your other sites for which you want to publish content to the sites application. Again, you can do this from the django shell just like any other application or from the admin.
  4. Add a foreign key to the Site model in your object site = models.ForeignKey(Site)
  5. Add the site manager on_site = CurrentSiteManager()

Now, when you want to filter content for the default site, or a particular site:

foo = MyObj.on_site.all() # Filters site to whatever is `SITE_ID`
foo = MyObj.objects.all() # Get all objects, irrespective of what site
                          # they belong to

The documentation has a full set of examples.


Things would be much easier to understand if Django's default SiteAdmin included the id field in the list_display fields.

To do this, you can redefine SiteAdmin (anywhere in your app, but I'd recommend your admin.py or maybe your urls.py) like this:

from django.contrib import admin
from django.contrib.sites.models import Site

admin.site.unregister(Site)
class SiteAdmin(admin.ModelAdmin):
    fields = ('id', 'name', 'domain')
    readonly_fields = ('id',)
    list_display = ('id', 'name', 'domain')
    list_display_links = ('name',)
    search_fields = ('name', 'domain')
admin.site.register(Site, SiteAdmin)

After including this code snippet, the ID for each "Site" will be shown in the first column of the admin list and inside the form as a read only field. These 'id' fields are what you need to use as SITE_ID:

modified admin page showing Site records' id

The concept is that each different site runs in a different application server instance, launched using a different yourdomain_settings.py that then includes a base_settings.py with the rest of the common configuration.

Each of these yourdomain_settings.py will define its own SITE_ID and all other different settings.py parameters that they need to look and be different from each other (static resources, templates, etc.) then you'll define a DJANGO_SETTINGS_MODULE environment variable pointing to that specific yourdomain_settings.py file when launching the application server instance for that domain.

A further note: get_current_site(request) does need request to be available for it to work. If your code doesn't have one, you can use Site.objects.get_current() that however will need a SITE_ID properly defined in the running application server's settings.