<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Red Robot Studios &#187; Django</title>
	<atom:link href="http://www.redrobotstudios.com/blog/category/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.redrobotstudios.com/blog</link>
	<description>Web development company specialising in Django and mobile development for clients around the world</description>
	<lastBuildDate>Wed, 14 Jul 2010 09:12:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Don&#8217;t delete an image file when deleting a Django model instance</title>
		<link>http://www.redrobotstudios.com/blog/2010/03/02/dont-delete-image-file-when-deleting-django-model-instance/</link>
		<comments>http://www.redrobotstudios.com/blog/2010/03/02/dont-delete-image-file-when-deleting-django-model-instance/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 09:54:22 +0000</pubDate>
		<dc:creator>Scott Barnham</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://www.redrobotstudios.com/blog/?p=55</guid>
		<description><![CDATA[If you have a Django model with a FileField or ImageField, when you delete the model instance, the associated file or image is also deleted.  In most cases this is desirable and keeps things tidy, but I had a situation recently where the image file should not be deleted when the model was deleted. [...]]]></description>
			<content:encoded><![CDATA[<p>If you have a Django model with a <code>FileField</code> or <code>ImageField</code>, when you delete the model instance, the associated file or image is also deleted.  In most cases this is desirable and keeps things tidy, but I had a situation recently where the image file should not be deleted when the model was deleted.  Here&#8217;s a simple way to override the default behaviour.</p>
<h3>Custom file storage</h3>
<p>Django uses storage classes to determine how files are read and written.  Normally, the data is just written as files to disk, but there are other possibilities such as storing on remote servers.</p>
<p>It&#8217;s easy to write a <a href="http://docs.djangoproject.com/en/dev/howto/custom-file-storage/">custom file storage</a> class to override the behaviour of the default <code>FileStorageSystem</code>.  In this case, we only need to change the <code>delete</code> method so it does not delete the file.</p>
<p>In custom.py</p>
<pre>from django.core.files import storage

class NoDeleteFileStorage(storage.FileSystemStorage):
    def delete(self, name):
        pass</pre>
<p>We can then <a href="http://docs.djangoproject.com/en/1.1/topics/files/#file-storage">use the custom file storage</a> by making an instance and passing it to the <code>ImageField</code>.</p>
<p>In models.py</p>
<pre>from custom import NoDeleteFileStorage

ndfs = NoDeleteFileStorage()

class ImageInstance(models.Model):
    image = models.ImageField(storage=ndfs, ...)</pre>
<p>It&#8217;s as simple as that!  Custom file storage has some interesting possibilities.  With it you can handle how files are named or integrate with some caching or <a href="http://en.wikipedia.org/wiki/Content_Delivery_Network">CDN</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.redrobotstudios.com/blog/2010/03/02/dont-delete-image-file-when-deleting-django-model-instance/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Requiring https for certain paths in Django</title>
		<link>http://www.redrobotstudios.com/blog/2010/02/06/requiring-https-for-certain-paths-in-django/</link>
		<comments>http://www.redrobotstudios.com/blog/2010/02/06/requiring-https-for-certain-paths-in-django/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 12:03:25 +0000</pubDate>
		<dc:creator>Scott Barnham</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://www.redrobotstudios.com/blog/?p=45</guid>
		<description><![CDATA[A while ago I wrote about Securing Django with SSL.  Here&#8217;s a small addition.
Some paths need https
If you&#8217;re using SSL it makes sense for certain parts of the site to require a secure connection.  For example, the admin section.
Previously I shared the secure_required decorator which forces requests to use https for specific views. [...]]]></description>
			<content:encoded><![CDATA[<p>A while ago I wrote about <a href="http://www.redrobotstudios.com/blog/2009/02/18/securing-django-with-ssl/">Securing Django with SSL</a>.  Here&#8217;s a small addition.</p>
<h3>Some paths need https</h3>
<p>If you&#8217;re using SSL it makes sense for certain parts of the site to require a secure connection.  For example, the admin section.</p>
<p>Previously I shared the <a href="http://www.redrobotstudios.com/blog/2009/02/18/securing-django-with-ssl/">secure_required</a> decorator which forces requests to use https for specific views.  This works ok, but if you know an entire section of the site under a given path (e.g. <code>/admin/</code>) should be secure, it&#8217;s hassle to have to add the decorator to each view.</p>
<p>You can require secure connections over https using webserver config or using Django itself.</p>
<h3>Requiring https using Nginx</h3>
<p>In your Nginx config file under the section for the unsecure http/port 80 server you can specify a location path and redirect all requests to it to https instead.</p>
<pre>server {
    listen 10.10.10.10:80;
    server_name example.com;
...
    location /admin {
        # force admin to use https
        rewrite (.*) https://example.com/$1 permanent;
    }
...
}
</pre>
<p>Apache and other web servers can have a similar configuration.</p>
<p>If you can configure it in the web server, that&#8217;s more efficient because the request can be redirected by the server, without having to contact your Django project.  However, it should be fairly rare for requests to be redirected like this so it&#8217;s not a big performance issue and sometimes it&#8217;s easier to handle things in Django.</p>
<h3>Requiring https using Django middleware</h3>
<p>In Django it&#8217;s easy to write <a href="http://docs.djangoproject.com/en/dev/topics/http/middleware/">custom middleware</a> which gets called before each request reaches a view.</p>
<p>Here&#8217;s a small piece of middleware which checks if the request is over http to a path we want to be secure and if so redirects to the same path but over https.</p>
<pre>from django.http import HttpResponsePermanentRedirect
from django.conf import settings

class SecureRequiredMiddleware(object):
    def __init__(self):
        self.paths = getattr(settings, 'SECURE_REQUIRED_PATHS')
        self.enabled = self.paths and getattr(settings, 'HTTPS_SUPPORT')

    def process_request(self, request):
        if self.enabled and not request.is_secure():
            for path in self.paths:
                if request.get_full_path().startswith(path):
                    request_url = request.build_absolute_uri(request.get_full_path())
                    secure_url = request_url.replace('http://', 'https://')
                    return HttpResponsePermanentRedirect(secure_url)
        return None</pre>
<p>In <code>settings.py</code></p>
<pre>MIDDLEWARE_CLASSES = (
...
    'myproject.middleware.SecureRequiredMiddleware',
)

HTTPS_SUPPORT = True
SECURE_REQUIRED_PATHS = (
    '/admin/',
    '/accounts/',
    '/management/',
)
</pre>
<p><code>SECURE_REQUIRED_PATHS</code> is a list or tuple of paths that should be secure.  Any request to a path which starts with one of these will be required to use https.</p>
<p><code>HTTPS_SUPPORT</code> is a custom setting to make it easier to use this on your dev server without SSL support.  Set it to <code>True</code> in the settings for the live server and <code>False</code> in the settings for the dev server.</p>
<p>So there we go, an easy way to require secure https requests for certain parts of your Django site.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.redrobotstudios.com/blog/2010/02/06/requiring-https-for-certain-paths-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Securing Django with SSL</title>
		<link>http://www.redrobotstudios.com/blog/2009/02/18/securing-django-with-ssl/</link>
		<comments>http://www.redrobotstudios.com/blog/2009/02/18/securing-django-with-ssl/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 11:56:08 +0000</pubDate>
		<dc:creator>Scott Barnham</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://www.redrobotstudios.com/blog2/?p=42</guid>
		<description><![CDATA[When we built the centralized authentication system for Red Robot Studios we wanted all authentication and account resources to be available solely over&#160;https.

This article covers some tips and tricks we discovered while building the app, and how you can use Django to get fine-grained control as to which resources are available&#160;securely.

Why bother with&#160;security?
We all know [...]]]></description>
			<content:encoded><![CDATA[<p>When we built the centralized authentication system for <a href="http://www.redrobotstudios.com/">Red Robot Studios</a> we wanted all authentication and account resources to be available solely over&nbsp;https.
</p>
<p>This article covers some tips and tricks we discovered while building the app, and how you can use Django to get fine-grained control as to which resources are available&nbsp;securely.
</p>
<h3>Why bother with&nbsp;security?</h3>
<p>We all know that data sent over http is cleartext and can potentially be read on any network between the client and server.  But the risk feels pretty minimal and many sites don&#8217;t bother using <span class="caps">SSL</span> to encrypt sensitive traffic.  For online banking and ecommerce, you&#8217;d be crazy not to use it, but for other sites, why&nbsp;bother?</p>
<p>The chances of your http requests being snooped upon by an <span class="caps">ISP</span>, intermediate networks or your hosting company seem minimal.  But one potentially big risk is users accessing your website on an open wireless&nbsp;network.
</p>
<p>For example, perhaps your user has an unsecured wireless home or office network or maybe they use wireless networks in coffee shops and airports: It&#8217;s really easy in this situation for sensitive requests to be snooped&nbsp;upon.
</p>
<p>The data on your website may not be sensitive, but if you use Django&#8217;s admin or authentication frameworks, two important bits of information are passed as&nbsp;cleartext.
</p>
<p>When a user logs in, their username and password is posted in cleartext.  Assuming login is successful, each subsequent request includes a cookie containing the <code>sessionid</code>. The <code>sessionid</code> is just a random string, but if you know the <code>sessionid</code> of a user, it is trivial to hijack the session and have the same access to the website as that user does until they log&nbsp;out.</p>
<h3>Encrypting login&nbsp;sessions</h3>
<p>If you want to be sure user credentials and sessions cannot be compromised by eavesdroppers, you need to use <span class="caps">SSL</span> encryption.  Install an <span class="caps">SSL</span> certificate on the server so that traffic is encrypted end-to-end between client and&nbsp;server.
</p>
<p>You probably don&#8217;t want the whole site to be secure because it will be a lot slower and significantly increase the load on your servers.  Instead, you can be selective about which parts of the site should use https instead of http.  If you want user sessions to be secure, you should make sure that logging in and all parts of the site that require a logged-in user use&nbsp;https.</p>
<h3><span class="caps">SSL</span></h3>
<p>Standard <span class="caps">SSL</span> certificates are pretty cheap these days – under $20 per year.  We go some from <a href="http://www.rapidsslonline.com/">RapidSSLOnline</a>.  Each secure site needs its own <span class="caps">IP</span> address, so if you&#8217;re hosting multiple sites using virtual hosting, you&#8217;ll need to look in to getting some dedicated&nbsp;IPs.
</p>
<p>There are lots of guides to installing <span class="caps">SSL</span> certificates and configuring web servers such as Apache, Lighttpd and Nginx, so I won&#8217;t cover that&nbsp;here.
</p>
<h3>Making Django sessions&nbsp;secure</h3>
<p>Django uses cookies for its sessions.  When a cookie is set, you can specify that it be a secure cookie, meaning it is only ever passed over https and not in http requests.  We can tell Django to use secure cookies for sessions by adding a setting to <code>settings.py</code>
</p>
<pre><code>SESSION_COOKIE_SECURE = True
</code></pre>
<p>If you set Django to use secure cookies then try to log in over http you will get the&nbsp;error</p>
<blockquote><p><span class="dquo">&#8220;</span>Looks like your browser isn&#8217;t configured to accept cookies. Please enable cookies, reload this page, and try&nbsp;again.&#8221;
</p>
</blockquote>
<p>This happens because Django sets the cookie, but it&#8217;s a secure cookie, so when the page loads over http, Django can&#8217;t see the cookie and so assumes cookies are disabled in your&nbsp;browser.
</p>
<h3>Requiring https for&nbsp;admin</h3>
<p>To avoid this cookie warning and make sure you only ever pass your admin credentials over https, you can configure your web server so that any http requests are redirected to&nbsp;https.</p>
<p>For example, in Nginx it would look&nbsp;like:
</p>
<pre><code>server {
    server_name example.com;
    location /admin {
        # force admin to use https
        rewrite (.*) https://example.com/$1 permanent;
    }
...
}
</code></pre>
<p>In Apache, something&nbsp;like:
</p>
<pre><code>&lt;Location /admin&gt;
    RewriteRule (.*) https://example.com/$1 [L,R=301]
    ...
&lt;/Location&gt;
</code></pre>
<p>Of course, these bits of config should go in the http config, not the https config or you will cause infinite&nbsp;redirects!
</p>
<h3>Requiring https for certain&nbsp;views</h3>
<p>If all the logged-in parts of your site are in a certain path (e.g. /accounts/ and /members/) you can configure your web server in the same way to require https for these&nbsp;locations.
</p>
<p>If certain views require https (e.g. <code>/members/bert/</code> is public but <code>/members/bert/edit/</code> requires login), you may want to check <code>request.is_secure()</code> in those views.  A neat way to do it is with a decorator which can also redirect any http requests to&nbsp;https.</p>
<pre><code>from django.conf import settings
from django.http import HttpResponseRedirect

def secure_required(view_func):
    """Decorator makes sure URL is accessed over https."""
    def _wrapped_view_func(request, *args, **kwargs):
        if not request.is_secure():
            if getattr(settings, 'HTTPS_SUPPORT', True):
                request_url = request.build_absolute_uri(request.get_full_path())
                secure_url = request_url.replace('http://', 'https://')
                return HttpResponseRedirect(secure_url)
        return view_func(request, *args, **kwargs)
    return _wrapped_view_func
</code></pre>
<p>Then on your&nbsp;view:
</p>
<pre><code>@secure_required
@login_required
def edit_member(request, slug):
    ...
</code></pre>
<h3>Moving between http and https&nbsp;pages</h3>
<p>It&#8217;s normal to use full path URLs like <code>/accounts/login/</code> and <code>/blog/</code>.  Bear in mind that if you are accessing the site over https and follow one of these links, you will also access them over https.  If you want to be explicit, you need to specify the protocol and domain in the links, e.g. <strong>https</strong>://example.com/accounts/login/ and <strong>http</strong>://example.co/blog/&nbsp;.</p>
<p>For $20 and a bit of config, you can secure logged-in sessions on your site and protect yourself and your users from being compromised by eavesdroppers.  There are still plenty of sites where this is overkill, but you can see now how easy it is to secure your Django site with&nbsp;<span class="caps">SSL</span>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.redrobotstudios.com/blog/2009/02/18/securing-django-with-ssl/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Versioned Media and Expires Headers in Django</title>
		<link>http://www.redrobotstudios.com/blog/2008/12/18/versioned-media-and-expires-headers-in-django/</link>
		<comments>http://www.redrobotstudios.com/blog/2008/12/18/versioned-media-and-expires-headers-in-django/#comments</comments>
		<pubDate>Thu, 18 Dec 2008 11:04:29 +0000</pubDate>
		<dc:creator>Andrew Gleave</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://www.redrobotstudios.com/blog2/?p=39</guid>
		<description><![CDATA[We try to make our sites as responsive as possible, and as part of our testing, we realised that we should do the right thing and add Expires Headers to our static media.  Our web servers are configured so when a client requests an image, stylesheet or JavaScript file, it is returned along with [...]]]></description>
			<content:encoded><![CDATA[<p>We try to make our sites as responsive as possible, and as part of our testing, we realised that we should <em>do the right thing</em> and add <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21">Expires Headers</a> to our static media.  Our web servers are configured so when a client requests an image, stylesheet or JavaScript file, it is returned along with a far-future expires header.  This tells the client not to ask for that file again, but to cache it for a month or&nbsp;more.
</p>
<h4>Encouraging Caching with Expires&nbsp;Headers</h4>
<p>Without an expires header, the client will request media files each time it loads a page.  Using <code>if-modified-since</code> and <code>etag</code> headers, the server usually doesn&#8217;t return the media files, but instead returns a <code>304 Not Modified</code> response.  Not resending the data is good.  Not having to deal with the request at all is even better – that&#8217;s what expires headers&nbsp;offer.</p>
<p>Of course, if you tell clients not to request your stylesheet again for a month, what happens when you change your stylesheet?  The client won&#8217;t know and won&#8217;t get the changes.  That&#8217;s pretty disastrous.  What we need is a way of changing the <span class="caps">URL</span> when our media changes so that clients will pick up the new&nbsp;version.
</p>
<h4>Changing URLs when Content&nbsp;Changes</h4>
<p>There are a number of ways to serve your media so you can specify far-future dates in the expires header, but still have the client pick up new versions.  We refer to this as versioned&nbsp;media.
</p>
<p>One common scheme is to put the modification date of the file in its <span class="caps">URL</span>.  When the file date changes, the <span class="caps">URL</span> changes and clients request the new version.  The <span class="caps">URL</span> might look something like <code>/media/main.css?200812180930</code> or <code>/media/main-2008-12-18-0930.css</code>.  The former is easier because the querystring is ignored by the web server and the file returned as&nbsp;normal.
</p>
<p>Using the date is good if you want more granular per-file versioning, but it seems a little messy.  We decided to use a version number in the <span class="caps">URL</span> instead, e.g. <code>/media/v123/main.css</code>.  To make this work we need to put a version number in the templates and have our web server ignore the version number and just serve the&nbsp;file.</p>
<h4>Versioned Media Context&nbsp;Processor</h4>
<p>Typically, Django-based sites use the <code>MEDIA_URL</code> context processor to include external resources such as Javascript and images in to their templates. We expanded on this idea by having <code>VERSIONED_MEDIA_URL</code> which puts the version number in as&nbsp;well.
</p>
<p>Remembering to update a version number would be error prone, so we wanted to transparently support any updates to media.  We use <a href="http://subversion.tigris.org/">Subversion</a> for version control, and figured out that we could use the versioning metadata of our media directory to help us generate a unique path, which would change as the media was updated.  That&#8217;s exactly what we needed, and would allow us to specify expires headers on all paths which include a version number but still ensure that users would receive new copies of files if any&nbsp;changed.</p>
<pre><code>from django.utils.version import get_svn_revision
from django.conf import settings

VERSIONED_MEDIA_URL = None

def get_versioned_media_url():
    if hasattr(settings, 'MEDIA_VERSION') and settings.MEDIA_VERSION is not None:
       version = 'v%s' % settings.MEDIA_VERSION
    else:
        revision = get_svn_revision(settings.MEDIA_ROOT)
        version = revision.replace('SVN-', 'v')
    return u'%s%s/' % (settings.MEDIA_URL, version)

def versioned_media(request):
    """Adds versioned media url to the context."""
    global VERSIONED_MEDIA_URL
    if not VERSIONED_MEDIA_URL:
        VERSIONED_MEDIA_URL = get_versioned_media_url()
    return {'VERSIONED_MEDIA_URL': VERSIONED_MEDIA_URL}
</code></pre>
<p>You can see from the code that we&#8217;ve added a <code>MEDIA_VERSION</code> setting which is either manually set, or can be set by a deployment script. We make use of django&#8217;s get_svn_revision method to pick up the version number from our <code>MEDIA_ROOT</code> and we then append our version number to our <code>MEDIA_URL</code>, adding it to context as <code>VERSIONED_MEDIA_URL</code>.
</p>
<p>It&#8217;s convenient to update code on your server with a simple <code>svn up</code>, but serving from a working copy may have <a href="http://scottbarnham.com/blog/2008/04/22/serving-websites-from-svn-checkout-considered-harmful/">security issues</a>.  Instead, we have a deployment script which updates a working copy then copies the files (excluding <code>.svn</code> directories) to the directories used by the web server.  It finds the revision number and writes that to the settings file so our version number is still updated&nbsp;automatically.</p>
<h3>Configuring Expires Headers in&nbsp;Nginx</h3>
<p>Now that we have a version-specifc <span class="caps">URL</span> for all our media, we need to configure the webserver to add an Expires Header to any requests which are destined for a versioned <span class="caps">URL</span>.  We use <a href="http://nginx.net/">Nginx</a>, but the theory applies to any&nbsp;webserver.
</p>
<pre><code>location /versioned-media {
    internal;
    expires 90d;
    alias   /srv/www/live/thebarbershop/site/media;
}

location /media {
    rewrite /v(?:\d+)/(.*) /versioned-media/$1;
    rewrite /vunknown/(.*) /media/$1;
    root   /srv/www/live/thebarbershop/site;
}
</code></pre>
<p>We configure our <code>/media</code> <span class="caps">URL</span> so that any request which matches the version string created by our context processor is forwarded to the <code>/versioned-media</code> path, which then applies the expires header and sets the expiry date to 90 days in the future. Any request path without a version number simply gets served without the expires&nbsp;header.</p>
<p>One drawback: committing a change means that all versioned media URLs change, not just the one for the file that changed. However, we feel this is only a small drawback given the advantages this gives for the common case of a high-traffic site with relatively infrequent changes to the base&nbsp;media.
</p>
<p>When you couple adding Expires Headers with other techniques&nbsp;like:
</p>
<ul>
<li>
     <a href="http://developer.yahoo.com/yui/compressor/"><span class="caps">YUI</span> compressing your javascript and&nbsp;css</a>
 </li>
<li>
     <a href="http://wiki.codemongers.com/NginxHttpGzipModule">GZip compression for your&nbsp;media</a>
 </li>
<li>
     <a href="http://docs.djangoproject.com/en/dev/ref/middleware/#module-django.middleware.gzip">Django&#8217;s GZipMiddleware for your&nbsp;templates</a>
 </li>
<li>
     <a href="http://www.alistapart.com/articles/sprites/"><span class="caps">CSS</span> spriting</a>,
 </li>
</ul>
<p>you can dramatically reduce both the number and size of requests to your application, and give users a more responsive&nbsp;experience.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.redrobotstudios.com/blog/2008/12/18/versioned-media-and-expires-headers-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Handling Subdomains in Django</title>
		<link>http://www.redrobotstudios.com/blog/2008/12/12/handling-subdomains-in-django/</link>
		<comments>http://www.redrobotstudios.com/blog/2008/12/12/handling-subdomains-in-django/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 17:46:57 +0000</pubDate>
		<dc:creator>Scott Barnham</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://www.redrobotstudios.com/blog2/?p=35</guid>
		<description><![CDATA[This is the first part of our series on some of the more interesting tech we&#8217;ve developed for Red Robot Studios. We&#8217;re working from webserver up, so we thought that subdomains would be a good place to&#160;start.

Subdomains are useful when you want to host multiple sites with the same code and different data.  For [...]]]></description>
			<content:encoded><![CDATA[<p>This is the first part of our series on some of the more interesting tech we&#8217;ve developed for <a href="http://www.redrobotstudios.com/">Red Robot Studios</a>. We&#8217;re working from webserver up, so we thought that subdomains would be a good place to&nbsp;start.
</p>
<p>Subdomains are useful when you want to host multiple sites with the same code and different data.  For example, providing websites for clubs where each club has its own subdomain.  In Django, you could have a <code>Club</code> model and some associated models holding data.  When a user visits <code>alpha.example.com</code>, you want to show the data from the <code>Club</code> model instance for <code>alpha</code>.</p>
<h4><span class="caps">DNS</span> Subdomains and&nbsp;Wildcards</h4>
<p>You could add individual subdomains using <span class="caps">DNS</span> <code>CNAME</code>s or <code>A</code> records, but if you want to generate objects in your Django app on the fly, have a look at wildcards.  To match any subdomain you add “*” as a subdomain.  It looks something&nbsp;like:
</p>
<p><code>*.example.com 14400 IN A 208.77.188.166</code>
</p>
<p>This will match <code>www.example.com</code> as well as <code>alpha.example.com</code>, <code>beta.example.com</code>,&nbsp;etc.
</p>
<h4>Webserver&nbsp;Wildcards</h4>
<p>The webserver config needs a similar setting so it knows to respond to any&nbsp;subdomain.
</p>
<p>In Nginx, it looks something&nbsp;like:
</p>
<pre><code>server {
    listen       208.77.188.166:80;
    server_name  example.com *.example.com;
...
</code></pre>
<p>In&nbsp;Apache:
</p>
<pre><code>&lt;VirtualHost 208.77.188.166&gt;
    ServerName example.com
    ServerAlias *.example.com
...
</code></pre>
<p>If you want to use <span class="caps">SSL</span> certificates on your subdomains, you need to get a “wildcard subdomain certificate”.  They cost more than a regular certificate, but are necessary to provide a valid certificate for any subdomain on your site.  We go ours from <a href="http://www.rapidsslonline.com/">RapidSSLOnline</a>.</p>
<p>This should be enough config for your Django app to receive requests for any subdomain. Now your Django app needs to respond appropriately for each&nbsp;subdomain.
</p>
<h4>Getting the Subdomain in&nbsp;Django</h4>
<p>There are a few different ways to do it, but we went with a piece of middleware that gets the subdomain from the request and retrieves a matching&nbsp;model.
</p>
<p>We have added two additional settings: <code>DOMAIN_MIDDLEWARE_MODEL</code> and <code>DOMAIN_MIDDLEWARE_INSTANCE_NAME</code> to our settings.py so we can specify the model which the middleware queries, and the name which the instance is given when added to our <code>request</code> instance.</p>
<pre><code>DOMAIN_MIDDLEWARE_MODEL = 'core.Club'
DOMAIN_MIDDLEWARE_INSTANCE_NAME = 'club'
</code></pre>
<p>The model is assumed to have a field named &#8220;slug&#8221;, which the middleware uses to match the subdomain against an instance of the&nbsp;model.
</p>
<p>Right, so let&#8217;s create our&nbsp;middleware:
</p>
<pre><code>class DomainMiddleware(object):
    """Gets the correct instance of an application-specific model by matching the
    sub-domain of the request."""

    def __init__(self):
        self.site_domain = Site.objects.get_current().domain
        if self.site_domain.startswith('www.'):
            self.site_domain = self.site_domain[4:]
        self.SUBDOMAIN_RE = re.compile(r'^(?:www\.)?(?P&lt;slug&gt;[\w-]+)\.%s' % re.escape(self.site_domain))
        try:
            app_name, model_name = settings.DOMAIN_MIDDLEWARE_MODEL.split('.', 2)
            self.model = get_model(app_name, model_name)
            self.instance_name = settings.DOMAIN_MIDDLEWARE_INSTANCE_NAME
            assert self.instance_name
        except (AttributeError, AssertionError):
            raise ImproperlyConfigured('DomainMiddleware requires DOMAIN_MIDDLEWARE_MODEL and DOMAIN_MIDDLEWARE_INSTANCE_NAME settings')
</code></pre>
<p>In our <code>init</code> method we do some basic setup like creating a regex which will match the subdomain slug, and loading in our model using <code>django.db.models.get_model</code> with the <code>app.model</code> args from <code>DOMAIN_MIDDLEWARE_MODEL</code>.</p>
<pre><code>    def process_view(self, request, view_func, view_args, view_kwargs):
        """If domain is not main site, check for subdomain.

        Get the model from the subdomain slug.
        """
        port = request.META.get('SERVER_PORT')
        domain = request.META.get('HTTP_HOST', '').replace(':%s' % port, '')
        if domain.startswith('www.'):
            domain = domain[4:]
        if domain != self.site_domain:
            match = self.SUBDOMAIN_RE.match(domain)
            if match:
                slug = match.group('slug')
                instance = get_object_or_404(self.model, slug=slug)
            setattr(request, self.instance_name, instance)
        return None
</code></pre>
<p>In <code>process_view</code> we grab the subdomain from the <code>HTTP_HOST</code> header of the request, and using <code>get_object_or_404</code> we load the correct instance of the model and set it as an attribute on our <code>request</code> object with the name given in <code>DOMAIN_MIDDLEWARE_INSTANCE_NAME</code>.</p>
<p>When someone goes to <code>alpha.example.com</code> the middleware picks out <code>alpha</code> and gets the <code>Club</code> instance with <code>slug=alpha</code> and adds it to <code>request</code> to be used in&nbsp;views.</p>
<p>The middleware uses <code>Site.objects.get_current()</code> to get the base <span class="caps">URL</span>, so make sure you have <code>Site</code> set up properly or none of your subdomains will&nbsp;match.
</p>
<p>The advantage of having the middleware load in the correct instance for you is that your views can simply use the <code>club</code> attribute to access all related data for this club.</p>
<pre><code>def index(request):
    members = request.club.members.approved().order_by('-creation_date')
    return list_detail.object_list(
        request                 = request,
        queryset                = members,
        template_name           = 'club/index.html',
        template_object_name    = 'member'
    )
</code></pre>
<p>This is extremely useful when you want to ensure that your data is correctly filtered: you don&#8217;t need to have each view filter based on the subdomain, which is pretty error-prone, and if you get it wrong a user&#8217;s data would end up on someone else&#8217;s page.  This way is a lot&nbsp;simpler.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.redrobotstudios.com/blog/2008/12/12/handling-subdomains-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
