Django Sites framework and a multi-site CMS
The Django Sites framework has been widely adopted by many Django apps, as a way to use a single Django installation and a shared database, to serve multiple sites, while keeping the various model objects separated. This greatly simplifies the job of managing multiple Django applications, and makes it possible, for instance, to serve an article up on multiple websites, each running its own separate set of applications, some or all of which may be shared.
The framework is fairly flexible. As the documentation demonstrates, one may use it to associate content with sites in a OneToMany or ManyToMany relationship. For example, you may decide that articles always belong to a single site, or perhaps that they can be shared between multiple sites.
The sites framework is used by a number of components, including the comments and the syndication systems. In this way, comments or feeds are associated with a specific site, and objects can easily be filtered by sites, using the CurrentSiteManger provided by the Sites framework.
The Sites framework makes an assumption: Every site has its own settings.py, and the SITE_ID for a site is specified in settings.py. This fact is used by the sites framework to determine the current site. Thus, when one runs the code,
current_site = Site.objects.get_current()
the site framework checks the current SITE_ID in django.conf.
This is all very reasonable. However, there is one huge assumption being made here, namely, that one never wants to run multiple sites on the same application, with the samesettings.py file. Because the sites framework forces you to set a SITE_ID in settings.py, it is in not possible to serve content for multiple domains from a single application.
Django
is not designed to be domain-neutral. It does not treat the domain name
of your site as an arbitrary parameter, and allow you to do with it as
you wish. Consider how urls.py is setup. The domain name
is stripped from the URL before your URL configurations can touch it.
You cannot grab the URL as a parameter to be passed to a view. Why?
Because the URL belongs to the site. All of the apps assume that domain
= new site = new settings.py. This has some consequences that are
difficult to work around.
Consider the following scenario: You are designing a CMS to manage multiple websites from a single application on a single server. If we do this the way the Sites framework wants us to do it, we need to create a separate Django instance for each website. Thus, we multiply our initial memory usage by as many sites as we wish to serve. Setting up a site now requires us to not only setup a new wsgi or mod_python instance (assuming Apache), but also to setup a separate settings.py file (and possibly a separate urls.py file) for every site.
What is the alternative? How about having a single Django instance, whether using fast_cgi, wsgi, or mod_python, serves all the sites. One instance to rule them all. This
app stores templates, page content, and stylesheets in the database.
All that is necessary to create a new site, is point a domain at your
Django CMS server, and a new domain object, setup templates and
stylesheets from within admin, and start adding content.
However, to do this, we must scrap the Django sites framework, and implement our own. That's fine, and to be expected, since the sites framework serves another purpose. No use using the wrong tool for the job, right? Well, there is this niggling little problem, namely that all the Django apps that might be used for multiple sites also assume you will be using separate Django configurations for each site.
Take my example of the single-instance to rule them all. I want to add
the Comments framework. I want to use it on multiple blog or news
sites, each with its own look and feel. Therefore, I need to be able to
customize the preview and post templates for every website. If I am
doing my sites the Django way — no problem, because every app is
running in a separate instance, each with its own template path. But
how do I do it with a single instance? I can't. Whatever templates I
choose to use with the comments framework, end up being used for every
website. My only alternative is either to roll my own comment system,
or to spin off django.contrib.comments into its own app, and develop it
on my own.
I cannot really complain. When you don't run with the
current, you cannot expect everything to just work. But I have to
wonder if there might not be some benefit to re-thinking the way in
which sites, settings.py and urls.py interact. But, as they say, I Want
A Pony. In particular — will it ever be possible to treat the domain as
just another urls.py component, without losing the ability to run
separate domains in separate instances? This would have huge benefits. Imagine using a catch-all DNS record, and being able to specify a URL config this way:
(r'(?P<prefix>[-\w]+)\.(?P<domain>.[-\w]+)/page/(?P<slug>[-\w]+)/*', 'myapp.views.getpage')
What do you think?


blog comments powered by Disqus