diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py index 18830dd3ae..253a2722b6 100644 --- a/django/contrib/sites/models.py +++ b/django/contrib/sites/models.py @@ -2,15 +2,32 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.http import get_host +SITE_CACHE = {} + class SiteManager(models.Manager): def get_current(self): + """ + Returns the current ``Site`` based on the SITE_ID in the + project's settings. The ``Site`` object is cached the first + time it's retrieved from the database. + """ from django.conf import settings try: sid = settings.SITE_ID except AttributeError: from django.core.exceptions import ImproperlyConfigured raise ImproperlyConfigured("You're using the Django \"sites framework\" without having set the SITE_ID setting. Create a site in your database and set the SITE_ID setting to fix this error.") - return self.get(pk=sid) + try: + current_site = SITE_CACHE[sid] + except KeyError: + current_site = self.get(pk=sid) + SITE_CACHE[sid] = current_site + return current_site + + def clear_cache(self): + """Clears the ``Site`` object cache.""" + global SITE_CACHE + SITE_CACHE = {} class Site(models.Model): domain = models.CharField(_('domain name'), max_length=100) diff --git a/docs/sites.txt b/docs/sites.txt index e7a8ecbfa6..5896afcf41 100644 --- a/docs/sites.txt +++ b/docs/sites.txt @@ -213,6 +213,31 @@ To do this, you can use the sites framework. A simple example:: >>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url()) 'http://example.com/mymodel/objects/3/' +Caching the current ``Site`` object +=================================== + +**New in Django development version** + +As the current site is stored in the database, each call to +``Site.objects.get_current()`` could result in a database query. But Django is a +little cleverer than that: on the first request, the current site is cached, and +any subsequent call returns the cached data instead of hitting the database. + +If for any reason you want to force a database query, you can tell Django to +clear the cache using ``Site.objects.clear_cache()``:: + + # First call; current site fetched from database. + current_site = Site.objects.get_current() + # ... + + # Second call; current site fetched from cache. + current_site = Site.objects.get_current() + # ... + + # Force a database query for the third call. + Site.objects.clear_cache() + current_site = Site.objects.get_current() + The ``CurrentSiteManager`` ==========================